mustang 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/Isolate +9 -0
- data/README.md +6 -12
- data/Rakefile +30 -4
- data/TODO.md +9 -0
- data/ext/v8/extconf.rb +56 -0
- data/ext/v8/v8.cpp +37 -0
- data/ext/v8/v8_array.cpp +161 -0
- data/ext/v8/v8_array.h +17 -0
- data/ext/v8/v8_base.cpp +147 -0
- data/ext/v8/v8_base.h +23 -0
- data/ext/v8/v8_cast.cpp +151 -0
- data/ext/v8/v8_cast.h +64 -0
- data/ext/v8/v8_context.cpp +174 -0
- data/ext/v8/v8_context.h +12 -0
- data/ext/v8/v8_date.cpp +61 -0
- data/ext/v8/v8_date.h +16 -0
- data/ext/v8/v8_errors.cpp +147 -0
- data/ext/v8/v8_errors.h +19 -0
- data/ext/v8/v8_external.cpp +66 -0
- data/ext/v8/v8_external.h +16 -0
- data/ext/v8/v8_function.cpp +182 -0
- data/ext/v8/v8_function.h +14 -0
- data/ext/v8/v8_integer.cpp +70 -0
- data/ext/v8/v8_integer.h +16 -0
- data/ext/v8/v8_macros.h +30 -0
- data/ext/v8/v8_main.cpp +53 -0
- data/ext/v8/v8_main.h +13 -0
- data/ext/v8/v8_number.cpp +62 -0
- data/ext/v8/v8_number.h +16 -0
- data/ext/v8/v8_object.cpp +172 -0
- data/ext/v8/v8_object.h +17 -0
- data/ext/v8/v8_ref.cpp +72 -0
- data/ext/v8/v8_ref.h +43 -0
- data/ext/v8/v8_regexp.cpp +148 -0
- data/ext/v8/v8_regexp.h +16 -0
- data/ext/v8/v8_string.cpp +78 -0
- data/ext/v8/v8_string.h +16 -0
- data/ext/v8/v8_value.cpp +370 -0
- data/ext/v8/v8_value.h +19 -0
- data/gemspec.yml +2 -1
- data/lib/core_ext/class.rb +14 -0
- data/lib/core_ext/object.rb +12 -0
- data/lib/core_ext/symbol.rb +23 -0
- data/lib/mustang.rb +44 -0
- data/lib/mustang/context.rb +69 -0
- data/lib/mustang/errors.rb +36 -0
- data/lib/support/delegated.rb +25 -0
- data/lib/v8/array.rb +21 -0
- data/lib/v8/context.rb +13 -0
- data/lib/v8/date.rb +20 -0
- data/lib/v8/error.rb +15 -0
- data/lib/v8/external.rb +16 -0
- data/lib/v8/function.rb +11 -0
- data/lib/v8/integer.rb +16 -0
- data/lib/v8/number.rb +16 -0
- data/lib/v8/object.rb +66 -0
- data/lib/v8/regexp.rb +23 -0
- data/lib/v8/string.rb +27 -0
- data/mustang.gemspec +3 -0
- data/spec/core_ext/class_spec.rb +19 -0
- data/spec/core_ext/object_spec.rb +19 -0
- data/spec/core_ext/symbol_spec.rb +27 -0
- data/spec/fixtures/test1.js +2 -0
- data/spec/fixtures/test2.js +2 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/v8/array_spec.rb +88 -0
- data/spec/v8/cast_spec.rb +151 -0
- data/spec/v8/context_spec.rb +78 -0
- data/spec/v8/data_spec.rb +39 -0
- data/spec/v8/date_spec.rb +45 -0
- data/spec/v8/empty_spec.rb +27 -0
- data/spec/v8/errors_spec.rb +142 -0
- data/spec/v8/external_spec.rb +44 -0
- data/spec/v8/function_spec.rb +170 -0
- data/spec/v8/integer_spec.rb +41 -0
- data/spec/v8/main_spec.rb +18 -0
- data/spec/v8/null_spec.rb +27 -0
- data/spec/v8/number_spec.rb +40 -0
- data/spec/v8/object_spec.rb +79 -0
- data/spec/v8/primitive_spec.rb +9 -0
- data/spec/v8/regexp_spec.rb +65 -0
- data/spec/v8/string_spec.rb +48 -0
- data/spec/v8/undefined_spec.rb +27 -0
- data/spec/v8/value_spec.rb +215 -0
- data/vendor/v8/.gitignore +2 -0
- data/vendor/v8/AUTHORS +3 -1
- data/vendor/v8/ChangeLog +117 -0
- data/vendor/v8/SConstruct +334 -53
- data/vendor/v8/include/v8-debug.h +21 -11
- data/vendor/v8/include/v8-preparser.h +1 -1
- data/vendor/v8/include/v8-profiler.h +122 -43
- data/vendor/v8/include/v8-testing.h +5 -0
- data/vendor/v8/include/v8.h +171 -17
- data/vendor/v8/preparser/SConscript +38 -0
- data/vendor/v8/preparser/preparser-process.cc +77 -114
- data/vendor/v8/samples/shell.cc +232 -46
- data/vendor/v8/src/SConscript +29 -5
- data/vendor/v8/src/accessors.cc +70 -211
- data/vendor/v8/{test/cctest/test-mips.cc → src/allocation-inl.h} +15 -18
- data/vendor/v8/src/allocation.cc +0 -82
- data/vendor/v8/src/allocation.h +9 -42
- data/vendor/v8/src/api.cc +1645 -1156
- data/vendor/v8/src/api.h +76 -12
- data/vendor/v8/src/apiutils.h +0 -7
- data/vendor/v8/src/arguments.h +15 -4
- data/vendor/v8/src/arm/assembler-arm-inl.h +10 -9
- data/vendor/v8/src/arm/assembler-arm.cc +62 -23
- data/vendor/v8/src/arm/assembler-arm.h +76 -11
- data/vendor/v8/src/arm/builtins-arm.cc +39 -33
- data/vendor/v8/src/arm/code-stubs-arm.cc +1182 -402
- data/vendor/v8/src/arm/code-stubs-arm.h +20 -54
- data/vendor/v8/src/arm/codegen-arm.cc +159 -106
- data/vendor/v8/src/arm/codegen-arm.h +6 -6
- data/vendor/v8/src/arm/constants-arm.h +16 -1
- data/vendor/v8/src/arm/cpu-arm.cc +7 -5
- data/vendor/v8/src/arm/debug-arm.cc +6 -4
- data/vendor/v8/src/arm/deoptimizer-arm.cc +51 -14
- data/vendor/v8/src/arm/disasm-arm.cc +47 -15
- data/vendor/v8/src/arm/frames-arm.h +1 -1
- data/vendor/v8/src/arm/full-codegen-arm.cc +724 -408
- data/vendor/v8/src/arm/ic-arm.cc +90 -85
- data/vendor/v8/src/arm/lithium-arm.cc +140 -69
- data/vendor/v8/src/arm/lithium-arm.h +161 -46
- data/vendor/v8/src/arm/lithium-codegen-arm.cc +567 -297
- data/vendor/v8/src/arm/lithium-codegen-arm.h +21 -9
- data/vendor/v8/src/arm/lithium-gap-resolver-arm.cc +2 -0
- data/vendor/v8/src/arm/macro-assembler-arm.cc +457 -96
- data/vendor/v8/src/arm/macro-assembler-arm.h +115 -18
- data/vendor/v8/src/arm/regexp-macro-assembler-arm.cc +20 -13
- data/vendor/v8/src/arm/regexp-macro-assembler-arm.h +1 -0
- data/vendor/v8/src/arm/simulator-arm.cc +184 -101
- data/vendor/v8/src/arm/simulator-arm.h +26 -21
- data/vendor/v8/src/arm/stub-cache-arm.cc +450 -467
- data/vendor/v8/src/arm/virtual-frame-arm.cc +14 -12
- data/vendor/v8/src/arm/virtual-frame-arm.h +11 -8
- data/vendor/v8/src/array.js +35 -18
- data/vendor/v8/src/assembler.cc +186 -92
- data/vendor/v8/src/assembler.h +106 -69
- data/vendor/v8/src/ast-inl.h +5 -0
- data/vendor/v8/src/ast.cc +46 -35
- data/vendor/v8/src/ast.h +107 -50
- data/vendor/v8/src/atomicops.h +2 -0
- data/vendor/v8/src/atomicops_internals_mips_gcc.h +169 -0
- data/vendor/v8/src/bootstrapper.cc +649 -399
- data/vendor/v8/src/bootstrapper.h +94 -27
- data/vendor/v8/src/builtins.cc +359 -227
- data/vendor/v8/src/builtins.h +157 -123
- data/vendor/v8/src/checks.cc +2 -2
- data/vendor/v8/src/checks.h +4 -0
- data/vendor/v8/src/code-stubs.cc +27 -17
- data/vendor/v8/src/code-stubs.h +38 -17
- data/vendor/v8/src/codegen-inl.h +5 -1
- data/vendor/v8/src/codegen.cc +27 -17
- data/vendor/v8/src/codegen.h +9 -9
- data/vendor/v8/src/compilation-cache.cc +92 -206
- data/vendor/v8/src/compilation-cache.h +205 -30
- data/vendor/v8/src/compiler.cc +107 -120
- data/vendor/v8/src/compiler.h +17 -2
- data/vendor/v8/src/contexts.cc +22 -15
- data/vendor/v8/src/contexts.h +14 -8
- data/vendor/v8/src/conversions.cc +86 -30
- data/vendor/v8/src/counters.cc +19 -4
- data/vendor/v8/src/counters.h +28 -16
- data/vendor/v8/src/cpu-profiler-inl.h +4 -3
- data/vendor/v8/src/cpu-profiler.cc +123 -72
- data/vendor/v8/src/cpu-profiler.h +33 -19
- data/vendor/v8/src/cpu.h +2 -0
- data/vendor/v8/src/d8-debug.cc +3 -3
- data/vendor/v8/src/d8-debug.h +7 -6
- data/vendor/v8/src/d8-posix.cc +2 -0
- data/vendor/v8/src/d8.cc +22 -12
- data/vendor/v8/src/d8.gyp +3 -0
- data/vendor/v8/src/d8.js +618 -0
- data/vendor/v8/src/data-flow.h +3 -3
- data/vendor/v8/src/dateparser.h +4 -2
- data/vendor/v8/src/debug-agent.cc +10 -9
- data/vendor/v8/src/debug-agent.h +9 -11
- data/vendor/v8/src/debug-debugger.js +121 -0
- data/vendor/v8/src/debug.cc +331 -227
- data/vendor/v8/src/debug.h +248 -219
- data/vendor/v8/src/deoptimizer.cc +173 -62
- data/vendor/v8/src/deoptimizer.h +119 -19
- data/vendor/v8/src/disasm.h +3 -0
- data/vendor/v8/src/disassembler.cc +10 -9
- data/vendor/v8/src/execution.cc +185 -129
- data/vendor/v8/src/execution.h +47 -78
- data/vendor/v8/src/extensions/experimental/break-iterator.cc +250 -0
- data/vendor/v8/src/extensions/experimental/break-iterator.h +89 -0
- data/vendor/v8/src/extensions/experimental/experimental.gyp +2 -0
- data/vendor/v8/src/extensions/experimental/i18n-extension.cc +22 -2
- data/vendor/v8/src/extensions/externalize-string-extension.cc +2 -2
- data/vendor/v8/src/extensions/gc-extension.cc +1 -1
- data/vendor/v8/src/factory.cc +261 -154
- data/vendor/v8/src/factory.h +162 -158
- data/vendor/v8/src/flag-definitions.h +17 -11
- data/vendor/v8/src/frame-element.cc +0 -5
- data/vendor/v8/src/frame-element.h +9 -13
- data/vendor/v8/src/frames-inl.h +7 -0
- data/vendor/v8/src/frames.cc +56 -46
- data/vendor/v8/src/frames.h +36 -25
- data/vendor/v8/src/full-codegen.cc +15 -24
- data/vendor/v8/src/full-codegen.h +13 -41
- data/vendor/v8/src/func-name-inferrer.cc +7 -6
- data/vendor/v8/src/func-name-inferrer.h +1 -1
- data/vendor/v8/src/gdb-jit.cc +1 -0
- data/vendor/v8/src/global-handles.cc +118 -56
- data/vendor/v8/src/global-handles.h +98 -40
- data/vendor/v8/src/globals.h +2 -2
- data/vendor/v8/src/handles-inl.h +106 -9
- data/vendor/v8/src/handles.cc +220 -157
- data/vendor/v8/src/handles.h +38 -59
- data/vendor/v8/src/hashmap.h +3 -3
- data/vendor/v8/src/heap-inl.h +141 -25
- data/vendor/v8/src/heap-profiler.cc +117 -63
- data/vendor/v8/src/heap-profiler.h +38 -21
- data/vendor/v8/src/heap.cc +805 -564
- data/vendor/v8/src/heap.h +640 -594
- data/vendor/v8/src/hydrogen-instructions.cc +216 -73
- data/vendor/v8/src/hydrogen-instructions.h +259 -124
- data/vendor/v8/src/hydrogen.cc +996 -1171
- data/vendor/v8/src/hydrogen.h +163 -144
- data/vendor/v8/src/ia32/assembler-ia32-inl.h +12 -11
- data/vendor/v8/src/ia32/assembler-ia32.cc +85 -39
- data/vendor/v8/src/ia32/assembler-ia32.h +82 -16
- data/vendor/v8/src/ia32/builtins-ia32.cc +64 -58
- data/vendor/v8/src/ia32/code-stubs-ia32.cc +248 -324
- data/vendor/v8/src/ia32/code-stubs-ia32.h +3 -44
- data/vendor/v8/src/ia32/codegen-ia32.cc +217 -165
- data/vendor/v8/src/ia32/codegen-ia32.h +3 -0
- data/vendor/v8/src/ia32/cpu-ia32.cc +6 -5
- data/vendor/v8/src/ia32/debug-ia32.cc +8 -5
- data/vendor/v8/src/ia32/deoptimizer-ia32.cc +124 -14
- data/vendor/v8/src/ia32/disasm-ia32.cc +85 -62
- data/vendor/v8/src/ia32/frames-ia32.h +1 -1
- data/vendor/v8/src/ia32/full-codegen-ia32.cc +348 -435
- data/vendor/v8/src/ia32/ic-ia32.cc +91 -91
- data/vendor/v8/src/ia32/lithium-codegen-ia32.cc +500 -255
- data/vendor/v8/src/ia32/lithium-codegen-ia32.h +13 -4
- data/vendor/v8/src/ia32/lithium-gap-resolver-ia32.cc +6 -0
- data/vendor/v8/src/ia32/lithium-ia32.cc +122 -45
- data/vendor/v8/src/ia32/lithium-ia32.h +128 -41
- data/vendor/v8/src/ia32/macro-assembler-ia32.cc +109 -84
- data/vendor/v8/src/ia32/macro-assembler-ia32.h +18 -9
- data/vendor/v8/src/ia32/regexp-macro-assembler-ia32.cc +26 -15
- data/vendor/v8/src/ia32/regexp-macro-assembler-ia32.h +1 -0
- data/vendor/v8/src/ia32/register-allocator-ia32.cc +30 -30
- data/vendor/v8/src/ia32/simulator-ia32.h +4 -4
- data/vendor/v8/src/ia32/stub-cache-ia32.cc +383 -400
- data/vendor/v8/src/ia32/virtual-frame-ia32.cc +36 -13
- data/vendor/v8/src/ia32/virtual-frame-ia32.h +11 -5
- data/vendor/v8/src/ic-inl.h +12 -2
- data/vendor/v8/src/ic.cc +304 -221
- data/vendor/v8/src/ic.h +115 -58
- data/vendor/v8/src/interpreter-irregexp.cc +25 -21
- data/vendor/v8/src/interpreter-irregexp.h +2 -1
- data/vendor/v8/src/isolate.cc +883 -0
- data/vendor/v8/src/isolate.h +1304 -0
- data/vendor/v8/src/json.js +10 -10
- data/vendor/v8/src/jsregexp.cc +111 -80
- data/vendor/v8/src/jsregexp.h +6 -7
- data/vendor/v8/src/jump-target-heavy.cc +5 -8
- data/vendor/v8/src/jump-target-heavy.h +0 -6
- data/vendor/v8/src/jump-target-inl.h +1 -1
- data/vendor/v8/src/jump-target-light.cc +3 -3
- data/vendor/v8/src/lithium-allocator-inl.h +2 -0
- data/vendor/v8/src/lithium-allocator.cc +42 -30
- data/vendor/v8/src/lithium-allocator.h +8 -22
- data/vendor/v8/src/lithium.cc +1 -0
- data/vendor/v8/src/liveedit.cc +141 -99
- data/vendor/v8/src/liveedit.h +7 -2
- data/vendor/v8/src/liveobjectlist-inl.h +90 -0
- data/vendor/v8/src/liveobjectlist.cc +2537 -1
- data/vendor/v8/src/liveobjectlist.h +245 -35
- data/vendor/v8/src/log-utils.cc +122 -35
- data/vendor/v8/src/log-utils.h +33 -36
- data/vendor/v8/src/log.cc +299 -241
- data/vendor/v8/src/log.h +177 -110
- data/vendor/v8/src/mark-compact.cc +612 -470
- data/vendor/v8/src/mark-compact.h +153 -80
- data/vendor/v8/src/messages.cc +16 -14
- data/vendor/v8/src/messages.js +30 -7
- data/vendor/v8/src/mips/assembler-mips-inl.h +155 -35
- data/vendor/v8/src/mips/assembler-mips.cc +1093 -219
- data/vendor/v8/src/mips/assembler-mips.h +552 -153
- data/vendor/v8/src/mips/builtins-mips.cc +43 -100
- data/vendor/v8/src/mips/code-stubs-mips.cc +752 -0
- data/vendor/v8/src/mips/code-stubs-mips.h +511 -0
- data/vendor/v8/src/mips/codegen-mips-inl.h +8 -14
- data/vendor/v8/src/mips/codegen-mips.cc +672 -896
- data/vendor/v8/src/mips/codegen-mips.h +271 -69
- data/vendor/v8/src/mips/constants-mips.cc +44 -20
- data/vendor/v8/src/mips/constants-mips.h +238 -40
- data/vendor/v8/src/mips/cpu-mips.cc +20 -3
- data/vendor/v8/src/mips/debug-mips.cc +35 -7
- data/vendor/v8/src/mips/deoptimizer-mips.cc +91 -0
- data/vendor/v8/src/mips/disasm-mips.cc +329 -93
- data/vendor/v8/src/mips/frames-mips.cc +2 -50
- data/vendor/v8/src/mips/frames-mips.h +24 -9
- data/vendor/v8/src/mips/full-codegen-mips.cc +473 -23
- data/vendor/v8/src/mips/ic-mips.cc +81 -45
- data/vendor/v8/src/mips/jump-target-mips.cc +11 -106
- data/vendor/v8/src/mips/lithium-codegen-mips.h +65 -0
- data/vendor/v8/src/mips/lithium-mips.h +304 -0
- data/vendor/v8/src/mips/macro-assembler-mips.cc +2391 -390
- data/vendor/v8/src/mips/macro-assembler-mips.h +718 -121
- data/vendor/v8/src/mips/regexp-macro-assembler-mips.cc +478 -0
- data/vendor/v8/src/mips/regexp-macro-assembler-mips.h +250 -0
- data/vendor/v8/src/mips/register-allocator-mips-inl.h +0 -3
- data/vendor/v8/src/mips/register-allocator-mips.h +3 -2
- data/vendor/v8/src/mips/simulator-mips.cc +1009 -221
- data/vendor/v8/src/mips/simulator-mips.h +119 -36
- data/vendor/v8/src/mips/stub-cache-mips.cc +331 -148
- data/vendor/v8/src/mips/{fast-codegen-mips.cc → virtual-frame-mips-inl.h} +11 -30
- data/vendor/v8/src/mips/virtual-frame-mips.cc +137 -149
- data/vendor/v8/src/mips/virtual-frame-mips.h +294 -312
- data/vendor/v8/src/mirror-debugger.js +9 -8
- data/vendor/v8/src/mksnapshot.cc +2 -2
- data/vendor/v8/src/objects-debug.cc +16 -16
- data/vendor/v8/src/objects-inl.h +421 -195
- data/vendor/v8/src/objects-printer.cc +7 -7
- data/vendor/v8/src/objects-visiting.cc +1 -1
- data/vendor/v8/src/objects-visiting.h +33 -12
- data/vendor/v8/src/objects.cc +935 -658
- data/vendor/v8/src/objects.h +234 -139
- data/vendor/v8/src/parser.cc +484 -439
- data/vendor/v8/src/parser.h +35 -14
- data/vendor/v8/src/platform-cygwin.cc +173 -107
- data/vendor/v8/src/platform-freebsd.cc +224 -72
- data/vendor/v8/src/platform-linux.cc +234 -95
- data/vendor/v8/src/platform-macos.cc +215 -82
- data/vendor/v8/src/platform-nullos.cc +9 -3
- data/vendor/v8/src/platform-openbsd.cc +22 -7
- data/vendor/v8/src/platform-posix.cc +30 -5
- data/vendor/v8/src/platform-solaris.cc +120 -38
- data/vendor/v8/src/platform-tls-mac.h +62 -0
- data/vendor/v8/src/platform-tls-win32.h +62 -0
- data/vendor/v8/src/platform-tls.h +50 -0
- data/vendor/v8/src/platform-win32.cc +195 -97
- data/vendor/v8/src/platform.h +72 -15
- data/vendor/v8/src/preparse-data.cc +2 -0
- data/vendor/v8/src/preparser-api.cc +8 -2
- data/vendor/v8/src/preparser.cc +1 -1
- data/vendor/v8/src/prettyprinter.cc +43 -52
- data/vendor/v8/src/prettyprinter.h +1 -1
- data/vendor/v8/src/profile-generator-inl.h +0 -28
- data/vendor/v8/src/profile-generator.cc +942 -685
- data/vendor/v8/src/profile-generator.h +210 -176
- data/vendor/v8/src/property.cc +6 -0
- data/vendor/v8/src/property.h +14 -3
- data/vendor/v8/src/regexp-macro-assembler-irregexp.cc +1 -1
- data/vendor/v8/src/regexp-macro-assembler.cc +28 -19
- data/vendor/v8/src/regexp-macro-assembler.h +11 -6
- data/vendor/v8/src/regexp-stack.cc +18 -10
- data/vendor/v8/src/regexp-stack.h +45 -21
- data/vendor/v8/src/regexp.js +3 -3
- data/vendor/v8/src/register-allocator-inl.h +3 -3
- data/vendor/v8/src/register-allocator.cc +1 -7
- data/vendor/v8/src/register-allocator.h +5 -15
- data/vendor/v8/src/rewriter.cc +2 -1
- data/vendor/v8/src/runtime-profiler.cc +158 -128
- data/vendor/v8/src/runtime-profiler.h +131 -15
- data/vendor/v8/src/runtime.cc +2409 -1692
- data/vendor/v8/src/runtime.h +93 -17
- data/vendor/v8/src/safepoint-table.cc +3 -0
- data/vendor/v8/src/safepoint-table.h +9 -3
- data/vendor/v8/src/scanner-base.cc +21 -28
- data/vendor/v8/src/scanner-base.h +22 -11
- data/vendor/v8/src/scanner.cc +3 -5
- data/vendor/v8/src/scanner.h +4 -2
- data/vendor/v8/src/scopeinfo.cc +11 -16
- data/vendor/v8/src/scopeinfo.h +26 -15
- data/vendor/v8/src/scopes.cc +67 -37
- data/vendor/v8/src/scopes.h +26 -12
- data/vendor/v8/src/serialize.cc +193 -154
- data/vendor/v8/src/serialize.h +41 -36
- data/vendor/v8/src/small-pointer-list.h +163 -0
- data/vendor/v8/src/snapshot-common.cc +1 -1
- data/vendor/v8/src/snapshot.h +3 -1
- data/vendor/v8/src/spaces-inl.h +30 -25
- data/vendor/v8/src/spaces.cc +263 -370
- data/vendor/v8/src/spaces.h +178 -166
- data/vendor/v8/src/string-search.cc +4 -3
- data/vendor/v8/src/string-search.h +21 -20
- data/vendor/v8/src/string-stream.cc +32 -24
- data/vendor/v8/src/string.js +7 -7
- data/vendor/v8/src/stub-cache.cc +324 -248
- data/vendor/v8/src/stub-cache.h +181 -155
- data/vendor/v8/src/token.cc +3 -3
- data/vendor/v8/src/token.h +3 -3
- data/vendor/v8/src/top.cc +218 -390
- data/vendor/v8/src/type-info.cc +98 -32
- data/vendor/v8/src/type-info.h +10 -3
- data/vendor/v8/src/unicode.cc +1 -1
- data/vendor/v8/src/unicode.h +1 -1
- data/vendor/v8/src/utils.h +3 -0
- data/vendor/v8/src/v8-counters.cc +18 -11
- data/vendor/v8/src/v8-counters.h +34 -13
- data/vendor/v8/src/v8.cc +66 -121
- data/vendor/v8/src/v8.h +7 -4
- data/vendor/v8/src/v8globals.h +18 -12
- data/vendor/v8/src/{memory.h → v8memory.h} +0 -0
- data/vendor/v8/src/v8natives.js +59 -18
- data/vendor/v8/src/v8threads.cc +127 -114
- data/vendor/v8/src/v8threads.h +42 -35
- data/vendor/v8/src/v8utils.h +2 -39
- data/vendor/v8/src/variables.h +1 -1
- data/vendor/v8/src/version.cc +26 -5
- data/vendor/v8/src/version.h +4 -0
- data/vendor/v8/src/virtual-frame-heavy-inl.h +2 -4
- data/vendor/v8/src/virtual-frame-light-inl.h +5 -4
- data/vendor/v8/src/vm-state-inl.h +21 -17
- data/vendor/v8/src/vm-state.h +7 -5
- data/vendor/v8/src/win32-headers.h +1 -0
- data/vendor/v8/src/x64/assembler-x64-inl.h +12 -11
- data/vendor/v8/src/x64/assembler-x64.cc +80 -40
- data/vendor/v8/src/x64/assembler-x64.h +67 -17
- data/vendor/v8/src/x64/builtins-x64.cc +34 -33
- data/vendor/v8/src/x64/code-stubs-x64.cc +636 -377
- data/vendor/v8/src/x64/code-stubs-x64.h +14 -48
- data/vendor/v8/src/x64/codegen-x64-inl.h +1 -1
- data/vendor/v8/src/x64/codegen-x64.cc +158 -136
- data/vendor/v8/src/x64/codegen-x64.h +4 -1
- data/vendor/v8/src/x64/cpu-x64.cc +7 -5
- data/vendor/v8/src/x64/debug-x64.cc +8 -6
- data/vendor/v8/src/x64/deoptimizer-x64.cc +195 -20
- data/vendor/v8/src/x64/disasm-x64.cc +42 -23
- data/vendor/v8/src/x64/frames-x64.cc +1 -1
- data/vendor/v8/src/x64/frames-x64.h +2 -2
- data/vendor/v8/src/x64/full-codegen-x64.cc +780 -218
- data/vendor/v8/src/x64/ic-x64.cc +77 -79
- data/vendor/v8/src/x64/jump-target-x64.cc +1 -1
- data/vendor/v8/src/x64/lithium-codegen-x64.cc +698 -181
- data/vendor/v8/src/x64/lithium-codegen-x64.h +31 -6
- data/vendor/v8/src/x64/lithium-x64.cc +136 -54
- data/vendor/v8/src/x64/lithium-x64.h +142 -51
- data/vendor/v8/src/x64/macro-assembler-x64.cc +456 -187
- data/vendor/v8/src/x64/macro-assembler-x64.h +166 -34
- data/vendor/v8/src/x64/regexp-macro-assembler-x64.cc +44 -28
- data/vendor/v8/src/x64/regexp-macro-assembler-x64.h +8 -4
- data/vendor/v8/src/x64/register-allocator-x64-inl.h +3 -3
- data/vendor/v8/src/x64/register-allocator-x64.cc +12 -8
- data/vendor/v8/src/x64/simulator-x64.h +5 -5
- data/vendor/v8/src/x64/stub-cache-x64.cc +299 -344
- data/vendor/v8/src/x64/virtual-frame-x64.cc +37 -13
- data/vendor/v8/src/x64/virtual-frame-x64.h +13 -7
- data/vendor/v8/src/zone-inl.h +49 -3
- data/vendor/v8/src/zone.cc +42 -41
- data/vendor/v8/src/zone.h +37 -34
- data/vendor/v8/test/benchmarks/testcfg.py +100 -0
- data/vendor/v8/test/cctest/SConscript +5 -4
- data/vendor/v8/test/cctest/cctest.h +3 -2
- data/vendor/v8/test/cctest/cctest.status +6 -11
- data/vendor/v8/test/cctest/test-accessors.cc +3 -3
- data/vendor/v8/test/cctest/test-alloc.cc +39 -33
- data/vendor/v8/test/cctest/test-api.cc +1092 -205
- data/vendor/v8/test/cctest/test-assembler-arm.cc +39 -25
- data/vendor/v8/test/cctest/test-assembler-ia32.cc +36 -37
- data/vendor/v8/test/cctest/test-assembler-mips.cc +1098 -40
- data/vendor/v8/test/cctest/test-assembler-x64.cc +32 -25
- data/vendor/v8/test/cctest/test-ast.cc +1 -0
- data/vendor/v8/test/cctest/test-circular-queue.cc +8 -5
- data/vendor/v8/test/cctest/test-compiler.cc +24 -24
- data/vendor/v8/test/cctest/test-cpu-profiler.cc +140 -5
- data/vendor/v8/test/cctest/test-dataflow.cc +1 -0
- data/vendor/v8/test/cctest/test-debug.cc +136 -77
- data/vendor/v8/test/cctest/test-decls.cc +1 -1
- data/vendor/v8/test/cctest/test-deoptimization.cc +25 -24
- data/vendor/v8/test/cctest/test-disasm-arm.cc +9 -4
- data/vendor/v8/test/cctest/test-disasm-ia32.cc +10 -8
- data/vendor/v8/test/cctest/test-func-name-inference.cc +10 -4
- data/vendor/v8/test/cctest/test-heap-profiler.cc +226 -164
- data/vendor/v8/test/cctest/test-heap.cc +240 -217
- data/vendor/v8/test/cctest/test-liveedit.cc +1 -0
- data/vendor/v8/test/cctest/test-log-stack-tracer.cc +18 -20
- data/vendor/v8/test/cctest/test-log.cc +114 -108
- data/vendor/v8/test/cctest/test-macro-assembler-x64.cc +247 -177
- data/vendor/v8/test/cctest/test-mark-compact.cc +129 -90
- data/vendor/v8/test/cctest/test-parsing.cc +15 -14
- data/vendor/v8/test/cctest/test-platform-linux.cc +1 -0
- data/vendor/v8/test/cctest/test-platform-tls.cc +66 -0
- data/vendor/v8/test/cctest/test-platform-win32.cc +1 -0
- data/vendor/v8/test/cctest/test-profile-generator.cc +1 -1
- data/vendor/v8/test/cctest/test-regexp.cc +53 -41
- data/vendor/v8/test/cctest/test-reloc-info.cc +18 -11
- data/vendor/v8/test/cctest/test-serialize.cc +44 -43
- data/vendor/v8/test/cctest/test-sockets.cc +8 -3
- data/vendor/v8/test/cctest/test-spaces.cc +47 -29
- data/vendor/v8/test/cctest/test-strings.cc +20 -20
- data/vendor/v8/test/cctest/test-thread-termination.cc +8 -3
- data/vendor/v8/test/cctest/test-threads.cc +5 -3
- data/vendor/v8/test/cctest/test-utils.cc +5 -4
- data/vendor/v8/test/cctest/testcfg.py +7 -3
- data/vendor/v8/test/es5conform/es5conform.status +2 -77
- data/vendor/v8/test/es5conform/testcfg.py +1 -1
- data/vendor/v8/test/message/testcfg.py +1 -1
- data/vendor/v8/test/mjsunit/accessors-on-global-object.js +3 -3
- data/vendor/v8/test/mjsunit/array-concat.js +43 -1
- data/vendor/v8/test/mjsunit/array-join.js +25 -0
- data/vendor/v8/test/mjsunit/bitops-info.js +7 -1
- data/vendor/v8/test/mjsunit/compiler/array-length.js +2 -2
- data/vendor/v8/test/mjsunit/compiler/global-accessors.js +47 -0
- data/vendor/v8/test/mjsunit/compiler/pic.js +1 -1
- data/vendor/v8/test/mjsunit/compiler/regress-loadfield.js +65 -0
- data/vendor/v8/test/mjsunit/math-sqrt.js +5 -1
- data/vendor/v8/test/mjsunit/mjsunit.js +59 -8
- data/vendor/v8/test/mjsunit/mjsunit.status +0 -12
- data/vendor/v8/test/mjsunit/mul-exhaustive.js +129 -11
- data/vendor/v8/test/mjsunit/negate-zero.js +1 -1
- data/vendor/v8/test/mjsunit/object-freeze.js +5 -13
- data/vendor/v8/test/mjsunit/object-prevent-extensions.js +9 -50
- data/vendor/v8/test/mjsunit/object-seal.js +4 -13
- data/vendor/v8/test/mjsunit/override-eval-with-non-function.js +36 -0
- data/vendor/v8/test/mjsunit/regress/regress-1145.js +54 -0
- data/vendor/v8/test/mjsunit/regress/regress-1172-bis.js +37 -0
- data/vendor/v8/test/mjsunit/regress/regress-1181.js +54 -0
- data/vendor/v8/test/mjsunit/regress/regress-1207.js +35 -0
- data/vendor/v8/test/mjsunit/regress/regress-1209.js +34 -0
- data/vendor/v8/test/mjsunit/regress/regress-1210.js +48 -0
- data/vendor/v8/test/mjsunit/regress/regress-1213.js +43 -0
- data/vendor/v8/test/mjsunit/regress/regress-1218.js +29 -0
- data/vendor/v8/test/mjsunit/regress/regress-1229.js +79 -0
- data/vendor/v8/test/mjsunit/regress/regress-1233.js +47 -0
- data/vendor/v8/test/mjsunit/regress/regress-1236.js +34 -0
- data/vendor/v8/test/mjsunit/regress/regress-1237.js +36 -0
- data/vendor/v8/test/mjsunit/regress/regress-1240.js +39 -0
- data/vendor/v8/test/mjsunit/regress/regress-1257.js +58 -0
- data/vendor/v8/test/mjsunit/regress/regress-1278.js +69 -0
- data/vendor/v8/test/mjsunit/regress/regress-create-exception.js +1 -0
- data/vendor/v8/test/mjsunit/regress/regress-lazy-deopt-reloc.js +52 -0
- data/vendor/v8/test/mjsunit/sin-cos.js +15 -10
- data/vendor/v8/test/mjsunit/smi-negative-zero.js +2 -2
- data/vendor/v8/test/mjsunit/str-to-num.js +1 -1
- data/vendor/v8/test/mjsunit/strict-mode.js +435 -0
- data/vendor/v8/test/mjsunit/testcfg.py +23 -6
- data/vendor/v8/test/mozilla/mozilla.status +0 -2
- data/vendor/v8/test/mozilla/testcfg.py +1 -1
- data/vendor/v8/test/preparser/empty.js +28 -0
- data/vendor/v8/test/preparser/functions-only.js +38 -0
- data/vendor/v8/test/preparser/non-alphanum.js +34 -0
- data/vendor/v8/test/preparser/symbols-only.js +49 -0
- data/vendor/v8/test/preparser/testcfg.py +90 -0
- data/vendor/v8/test/sputnik/testcfg.py +1 -1
- data/vendor/v8/test/test262/README +16 -0
- data/vendor/v8/test/test262/harness-adapt.js +80 -0
- data/vendor/v8/test/test262/test262.status +1506 -0
- data/vendor/v8/test/test262/testcfg.py +123 -0
- data/vendor/v8/tools/freebsd-tick-processor +10 -0
- data/vendor/v8/tools/gyp/v8.gyp +8 -33
- data/vendor/v8/tools/linux-tick-processor +5 -3
- data/vendor/v8/tools/test.py +37 -14
- data/vendor/v8/tools/tickprocessor.js +22 -8
- data/vendor/v8/tools/visual_studio/v8_base.vcproj +13 -1
- data/vendor/v8/tools/visual_studio/v8_base_arm.vcproj +5 -1
- data/vendor/v8/tools/visual_studio/v8_base_x64.vcproj +5 -1
- data/vendor/v8/tools/visual_studio/x64.vsprops +1 -0
- metadata +1495 -1341
- data/ext/extconf.rb +0 -22
- data/ext/mustang.cpp +0 -58
- data/vendor/v8/src/top.h +0 -608
data/vendor/v8/src/hydrogen.cc
CHANGED
@@ -25,6 +25,7 @@
|
|
25
25
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
26
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
27
|
|
28
|
+
#include "v8.h"
|
28
29
|
#include "hydrogen.h"
|
29
30
|
|
30
31
|
#include "codegen.h"
|
@@ -42,6 +43,8 @@
|
|
42
43
|
#include "x64/lithium-codegen-x64.h"
|
43
44
|
#elif V8_TARGET_ARCH_ARM
|
44
45
|
#include "arm/lithium-codegen-arm.h"
|
46
|
+
#elif V8_TARGET_ARCH_MIPS
|
47
|
+
#include "mips/lithium-codegen-mips.h"
|
45
48
|
#else
|
46
49
|
#error Unsupported target architecture.
|
47
50
|
#endif
|
@@ -92,7 +95,7 @@ void HBasicBlock::AddPhi(HPhi* phi) {
|
|
92
95
|
void HBasicBlock::RemovePhi(HPhi* phi) {
|
93
96
|
ASSERT(phi->block() == this);
|
94
97
|
ASSERT(phis_.Contains(phi));
|
95
|
-
ASSERT(phi->HasNoUses());
|
98
|
+
ASSERT(phi->HasNoUses() || !phi->is_live());
|
96
99
|
phi->ClearOperands();
|
97
100
|
phis_.RemoveElement(phi);
|
98
101
|
phi->SetBlock(NULL);
|
@@ -113,6 +116,21 @@ void HBasicBlock::AddInstruction(HInstruction* instr) {
|
|
113
116
|
}
|
114
117
|
|
115
118
|
|
119
|
+
HDeoptimize* HBasicBlock::CreateDeoptimize() {
|
120
|
+
ASSERT(HasEnvironment());
|
121
|
+
HEnvironment* environment = last_environment();
|
122
|
+
|
123
|
+
HDeoptimize* instr = new HDeoptimize(environment->length());
|
124
|
+
|
125
|
+
for (int i = 0; i < environment->length(); i++) {
|
126
|
+
HValue* val = environment->values()->at(i);
|
127
|
+
instr->AddEnvironmentValue(val);
|
128
|
+
}
|
129
|
+
|
130
|
+
return instr;
|
131
|
+
}
|
132
|
+
|
133
|
+
|
116
134
|
HSimulate* HBasicBlock::CreateSimulate(int id) {
|
117
135
|
ASSERT(HasEnvironment());
|
118
136
|
HEnvironment* environment = last_environment();
|
@@ -150,6 +168,10 @@ void HBasicBlock::Finish(HControlInstruction* end) {
|
|
150
168
|
|
151
169
|
|
152
170
|
void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) {
|
171
|
+
if (block->IsInlineReturnTarget()) {
|
172
|
+
AddInstruction(new HLeaveInlined);
|
173
|
+
last_environment_ = last_environment()->outer();
|
174
|
+
}
|
153
175
|
AddSimulate(AstNode::kNoNumber);
|
154
176
|
HGoto* instr = new HGoto(block);
|
155
177
|
instr->set_include_stack_check(include_stack_check);
|
@@ -157,6 +179,18 @@ void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) {
|
|
157
179
|
}
|
158
180
|
|
159
181
|
|
182
|
+
void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
|
183
|
+
ASSERT(target->IsInlineReturnTarget());
|
184
|
+
ASSERT(return_value != NULL);
|
185
|
+
AddInstruction(new HLeaveInlined);
|
186
|
+
last_environment_ = last_environment()->outer();
|
187
|
+
last_environment()->Push(return_value);
|
188
|
+
AddSimulate(AstNode::kNoNumber);
|
189
|
+
HGoto* instr = new HGoto(target);
|
190
|
+
Finish(instr);
|
191
|
+
}
|
192
|
+
|
193
|
+
|
160
194
|
void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
|
161
195
|
ASSERT(!HasEnvironment());
|
162
196
|
ASSERT(first() == NULL);
|
@@ -286,6 +320,13 @@ void HBasicBlock::Verify() {
|
|
286
320
|
// Check that every block is finished.
|
287
321
|
ASSERT(IsFinished());
|
288
322
|
ASSERT(block_id() >= 0);
|
323
|
+
|
324
|
+
// Check that the incoming edges are in edge split form.
|
325
|
+
if (predecessors_.length() > 1) {
|
326
|
+
for (int i = 0; i < predecessors_.length(); ++i) {
|
327
|
+
ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL);
|
328
|
+
}
|
329
|
+
}
|
289
330
|
}
|
290
331
|
#endif
|
291
332
|
|
@@ -473,158 +514,81 @@ HConstant* HGraph::GetConstantMinus1() {
|
|
473
514
|
|
474
515
|
|
475
516
|
HConstant* HGraph::GetConstantTrue() {
|
476
|
-
return GetConstant(&constant_true_,
|
517
|
+
return GetConstant(&constant_true_, isolate()->heap()->true_value());
|
477
518
|
}
|
478
519
|
|
479
520
|
|
480
521
|
HConstant* HGraph::GetConstantFalse() {
|
481
|
-
return GetConstant(&constant_false_,
|
522
|
+
return GetConstant(&constant_false_, isolate()->heap()->false_value());
|
482
523
|
}
|
483
524
|
|
484
525
|
|
485
|
-
|
486
|
-
|
487
|
-
|
526
|
+
HBasicBlock* HGraphBuilder::CreateJoin(HBasicBlock* first,
|
527
|
+
HBasicBlock* second,
|
528
|
+
int join_id) {
|
488
529
|
if (first == NULL) {
|
489
|
-
|
530
|
+
return second;
|
490
531
|
} else if (second == NULL) {
|
491
|
-
|
532
|
+
return first;
|
492
533
|
} else {
|
493
534
|
HBasicBlock* join_block = graph_->CreateBasicBlock();
|
494
535
|
first->Goto(join_block);
|
495
536
|
second->Goto(join_block);
|
496
537
|
join_block->SetJoinId(join_id);
|
497
|
-
|
538
|
+
return join_block;
|
498
539
|
}
|
499
540
|
}
|
500
541
|
|
501
542
|
|
502
|
-
|
503
|
-
|
543
|
+
HBasicBlock* HGraphBuilder::JoinContinue(IterationStatement* statement,
|
544
|
+
HBasicBlock* exit_block,
|
545
|
+
HBasicBlock* continue_block) {
|
504
546
|
if (continue_block != NULL) {
|
547
|
+
if (exit_block != NULL) exit_block->Goto(continue_block);
|
505
548
|
continue_block->SetJoinId(statement->ContinueId());
|
549
|
+
return continue_block;
|
506
550
|
}
|
507
|
-
|
508
|
-
JoinBlocks(exit_block(), continue_block, statement->ContinueId());
|
551
|
+
return exit_block;
|
509
552
|
}
|
510
553
|
|
511
554
|
|
512
|
-
HBasicBlock*
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
void HSubgraph::AppendEndless(IterationStatement* statement,
|
524
|
-
HBasicBlock* body_entry,
|
525
|
-
HBasicBlock* body_exit,
|
526
|
-
HBasicBlock* break_block) {
|
527
|
-
if (exit_block() != NULL) {
|
528
|
-
exit_block()->Goto(body_entry, false);
|
529
|
-
}
|
530
|
-
if (body_exit != NULL) {
|
531
|
-
body_exit->Goto(body_entry, true);
|
555
|
+
HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement,
|
556
|
+
HBasicBlock* loop_entry,
|
557
|
+
HBasicBlock* body_exit,
|
558
|
+
HBasicBlock* loop_successor,
|
559
|
+
HBasicBlock* break_block) {
|
560
|
+
if (body_exit != NULL) body_exit->Goto(loop_entry, true);
|
561
|
+
loop_entry->PostProcessLoopHeader(statement);
|
562
|
+
if (break_block != NULL) {
|
563
|
+
if (loop_successor != NULL) loop_successor->Goto(break_block);
|
564
|
+
break_block->SetJoinId(statement->ExitId());
|
565
|
+
return break_block;
|
532
566
|
}
|
533
|
-
|
534
|
-
exit_block_ = break_block;
|
535
|
-
body_entry->PostProcessLoopHeader(statement);
|
567
|
+
return loop_successor;
|
536
568
|
}
|
537
569
|
|
538
570
|
|
539
|
-
void
|
540
|
-
|
541
|
-
|
542
|
-
HBasicBlock* exit_block,
|
543
|
-
HBasicBlock* break_block) {
|
544
|
-
if (this->exit_block() != NULL) {
|
545
|
-
this->exit_block()->Goto(body_entry, false);
|
546
|
-
}
|
547
|
-
if (go_back != NULL) {
|
548
|
-
go_back->Goto(body_entry, true);
|
549
|
-
}
|
550
|
-
if (break_block != NULL) break_block->SetJoinId(statement->ExitId());
|
551
|
-
exit_block_ =
|
552
|
-
JoinBlocks(exit_block, break_block, statement->ExitId());
|
553
|
-
body_entry->PostProcessLoopHeader(statement);
|
554
|
-
}
|
555
|
-
|
556
|
-
|
557
|
-
void HSubgraph::AppendWhile(IterationStatement* statement,
|
558
|
-
HBasicBlock* condition_entry,
|
559
|
-
HBasicBlock* exit_block,
|
560
|
-
HBasicBlock* body_exit,
|
561
|
-
HBasicBlock* break_block,
|
562
|
-
HBasicBlock* loop_entry,
|
563
|
-
HBasicBlock* loop_exit) {
|
564
|
-
if (this->exit_block() != NULL) {
|
565
|
-
this->exit_block()->Goto(condition_entry, false);
|
566
|
-
}
|
567
|
-
|
568
|
-
if (break_block != NULL) break_block->SetJoinId(statement->ExitId());
|
569
|
-
exit_block_ =
|
570
|
-
JoinBlocks(exit_block, break_block, statement->ExitId());
|
571
|
-
|
572
|
-
if (loop_entry != NULL) {
|
573
|
-
if (body_exit != NULL) {
|
574
|
-
body_exit->Goto(loop_entry, true);
|
575
|
-
}
|
576
|
-
loop_entry->SetJoinId(statement->EntryId());
|
577
|
-
exit_block_ = JoinBlocks(exit_block_, loop_exit, statement->ExitId());
|
578
|
-
} else {
|
579
|
-
if (body_exit != NULL) {
|
580
|
-
body_exit->Goto(condition_entry, true);
|
581
|
-
}
|
582
|
-
}
|
583
|
-
condition_entry->PostProcessLoopHeader(statement);
|
584
|
-
}
|
585
|
-
|
586
|
-
|
587
|
-
void HSubgraph::Append(BreakableStatement* stmt,
|
588
|
-
HBasicBlock* entry_block,
|
589
|
-
HBasicBlock* exit_block,
|
590
|
-
HBasicBlock* break_block) {
|
591
|
-
exit_block_->Goto(entry_block);
|
592
|
-
exit_block_ = exit_block;
|
593
|
-
|
594
|
-
if (stmt != NULL) {
|
595
|
-
entry_block->SetJoinId(stmt->EntryId());
|
596
|
-
if (break_block != NULL) break_block->SetJoinId(stmt->EntryId());
|
597
|
-
exit_block_ = JoinBlocks(exit_block, break_block, stmt->ExitId());
|
598
|
-
}
|
599
|
-
}
|
600
|
-
|
601
|
-
|
602
|
-
void HSubgraph::FinishExit(HControlInstruction* instruction) {
|
603
|
-
ASSERT(exit_block() != NULL);
|
604
|
-
exit_block_->Finish(instruction);
|
605
|
-
exit_block_->ClearEnvironment();
|
606
|
-
exit_block_ = NULL;
|
571
|
+
void HBasicBlock::FinishExit(HControlInstruction* instruction) {
|
572
|
+
Finish(instruction);
|
573
|
+
ClearEnvironment();
|
607
574
|
}
|
608
575
|
|
609
576
|
|
610
577
|
HGraph::HGraph(CompilationInfo* info)
|
611
|
-
:
|
578
|
+
: isolate_(info->isolate()),
|
612
579
|
next_block_id_(0),
|
613
|
-
|
580
|
+
entry_block_(NULL),
|
614
581
|
blocks_(8),
|
615
582
|
values_(16),
|
616
583
|
phi_list_(NULL) {
|
617
584
|
start_environment_ = new HEnvironment(NULL, info->scope(), info->closure());
|
618
585
|
start_environment_->set_ast_id(info->function()->id());
|
586
|
+
entry_block_ = CreateBasicBlock();
|
587
|
+
entry_block_->SetInitialEnvironment(start_environment_);
|
619
588
|
}
|
620
589
|
|
621
590
|
|
622
|
-
|
623
|
-
return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount;
|
624
|
-
}
|
625
|
-
|
626
|
-
|
627
|
-
Handle<Code> HGraph::Compile() {
|
591
|
+
Handle<Code> HGraph::Compile(CompilationInfo* info) {
|
628
592
|
int values = GetMaximumValueID();
|
629
593
|
if (values > LAllocator::max_initial_value_ids()) {
|
630
594
|
if (FLAG_trace_bailout) PrintF("Function is too big\n");
|
@@ -632,7 +596,7 @@ Handle<Code> HGraph::Compile() {
|
|
632
596
|
}
|
633
597
|
|
634
598
|
LAllocator allocator(values, this);
|
635
|
-
LChunkBuilder builder(this, &allocator);
|
599
|
+
LChunkBuilder builder(info, this, &allocator);
|
636
600
|
LChunk* chunk = builder.Build();
|
637
601
|
if (chunk == NULL) return Handle<Code>::null();
|
638
602
|
|
@@ -642,8 +606,8 @@ Handle<Code> HGraph::Compile() {
|
|
642
606
|
|
643
607
|
if (!FLAG_use_lithium) return Handle<Code>::null();
|
644
608
|
|
645
|
-
MacroAssembler assembler(NULL, 0);
|
646
|
-
LCodeGen generator(chunk, &assembler, info
|
609
|
+
MacroAssembler assembler(info->isolate(), NULL, 0);
|
610
|
+
LCodeGen generator(chunk, &assembler, info);
|
647
611
|
|
648
612
|
if (FLAG_eliminate_empty_blocks) {
|
649
613
|
chunk->MarkEmptyBlocks();
|
@@ -653,13 +617,13 @@ Handle<Code> HGraph::Compile() {
|
|
653
617
|
if (FLAG_trace_codegen) {
|
654
618
|
PrintF("Crankshaft Compiler - ");
|
655
619
|
}
|
656
|
-
CodeGenerator::MakeCodePrologue(info
|
620
|
+
CodeGenerator::MakeCodePrologue(info);
|
657
621
|
Code::Flags flags =
|
658
622
|
Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP);
|
659
623
|
Handle<Code> code =
|
660
|
-
CodeGenerator::MakeCodeEpilogue(&assembler, flags, info
|
624
|
+
CodeGenerator::MakeCodeEpilogue(&assembler, flags, info);
|
661
625
|
generator.FinishCode(code);
|
662
|
-
CodeGenerator::PrintCode(code, info
|
626
|
+
CodeGenerator::PrintCode(code, info);
|
663
627
|
return code;
|
664
628
|
}
|
665
629
|
return Handle<Code>::null();
|
@@ -674,20 +638,14 @@ HBasicBlock* HGraph::CreateBasicBlock() {
|
|
674
638
|
|
675
639
|
|
676
640
|
void HGraph::Canonicalize() {
|
641
|
+
if (!FLAG_use_canonicalizing) return;
|
677
642
|
HPhase phase("Canonicalize", this);
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
if (value != NULL) {
|
685
|
-
insn->ReplaceAndDelete(value);
|
686
|
-
} else {
|
687
|
-
insn->Delete();
|
688
|
-
}
|
689
|
-
}
|
690
|
-
}
|
643
|
+
for (int i = 0; i < blocks()->length(); ++i) {
|
644
|
+
HInstruction* instr = blocks()->at(i)->first();
|
645
|
+
while (instr != NULL) {
|
646
|
+
HValue* value = instr->Canonicalize();
|
647
|
+
if (value != instr) instr->ReplaceAndDelete(value);
|
648
|
+
instr = instr->next();
|
691
649
|
}
|
692
650
|
}
|
693
651
|
}
|
@@ -701,7 +659,7 @@ void HGraph::OrderBlocks() {
|
|
701
659
|
HBasicBlock* start = blocks_[0];
|
702
660
|
Postorder(start, &visited, &reverse_result, NULL);
|
703
661
|
|
704
|
-
blocks_.
|
662
|
+
blocks_.Rewind(0);
|
705
663
|
int index = 0;
|
706
664
|
for (int i = reverse_result.length() - 1; i >= 0; --i) {
|
707
665
|
HBasicBlock* b = reverse_result[i];
|
@@ -766,8 +724,7 @@ void HGraph::AssignDominators() {
|
|
766
724
|
|
767
725
|
|
768
726
|
void HGraph::EliminateRedundantPhis() {
|
769
|
-
HPhase phase("
|
770
|
-
ZoneList<HValue*> uses_to_replace(2);
|
727
|
+
HPhase phase("Redundant phi elimination", this);
|
771
728
|
|
772
729
|
// Worklist of phis that can potentially be eliminated. Initialized
|
773
730
|
// with all phi nodes. When elimination of a phi node modifies
|
@@ -790,26 +747,57 @@ void HGraph::EliminateRedundantPhis() {
|
|
790
747
|
if (value != NULL) {
|
791
748
|
// Iterate through uses finding the ones that should be
|
792
749
|
// replaced.
|
793
|
-
|
794
|
-
|
795
|
-
HValue* use = uses->
|
796
|
-
if (
|
797
|
-
|
750
|
+
SmallPointerList<HValue>* uses = phi->uses();
|
751
|
+
while (!uses->is_empty()) {
|
752
|
+
HValue* use = uses->RemoveLast();
|
753
|
+
if (use != NULL) {
|
754
|
+
phi->ReplaceAtUse(use, value);
|
755
|
+
if (use->IsPhi()) worklist.Add(HPhi::cast(use));
|
798
756
|
}
|
799
757
|
}
|
800
|
-
// Replace the uses and add phis modified to the work list.
|
801
|
-
for (int i = 0; i < uses_to_replace.length(); ++i) {
|
802
|
-
HValue* use = uses_to_replace[i];
|
803
|
-
phi->ReplaceAtUse(use, value);
|
804
|
-
if (use->IsPhi()) worklist.Add(HPhi::cast(use));
|
805
|
-
}
|
806
|
-
uses_to_replace.Rewind(0);
|
807
758
|
block->RemovePhi(phi);
|
808
|
-
}
|
809
|
-
|
759
|
+
}
|
760
|
+
}
|
761
|
+
}
|
762
|
+
|
763
|
+
|
764
|
+
void HGraph::EliminateUnreachablePhis() {
|
765
|
+
HPhase phase("Unreachable phi elimination", this);
|
766
|
+
|
767
|
+
// Initialize worklist.
|
768
|
+
ZoneList<HPhi*> phi_list(blocks_.length());
|
769
|
+
ZoneList<HPhi*> worklist(blocks_.length());
|
770
|
+
for (int i = 0; i < blocks_.length(); ++i) {
|
771
|
+
for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
|
772
|
+
HPhi* phi = blocks_[i]->phis()->at(j);
|
773
|
+
phi_list.Add(phi);
|
810
774
|
// We can't eliminate phis in the receiver position in the environment
|
811
775
|
// because in case of throwing an error we need this value to
|
812
776
|
// construct a stack trace.
|
777
|
+
if (phi->HasRealUses() || phi->IsReceiver()) {
|
778
|
+
phi->set_is_live(true);
|
779
|
+
worklist.Add(phi);
|
780
|
+
}
|
781
|
+
}
|
782
|
+
}
|
783
|
+
|
784
|
+
// Iteratively mark live phis.
|
785
|
+
while (!worklist.is_empty()) {
|
786
|
+
HPhi* phi = worklist.RemoveLast();
|
787
|
+
for (int i = 0; i < phi->OperandCount(); i++) {
|
788
|
+
HValue* operand = phi->OperandAt(i);
|
789
|
+
if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) {
|
790
|
+
HPhi::cast(operand)->set_is_live(true);
|
791
|
+
worklist.Add(HPhi::cast(operand));
|
792
|
+
}
|
793
|
+
}
|
794
|
+
}
|
795
|
+
|
796
|
+
// Remove unreachable phis.
|
797
|
+
for (int i = 0; i < phi_list.length(); i++) {
|
798
|
+
HPhi* phi = phi_list[i];
|
799
|
+
if (!phi->is_live()) {
|
800
|
+
HBasicBlock* block = phi->block();
|
813
801
|
block->RemovePhi(phi);
|
814
802
|
block->RecordDeletedPhi(phi->merged_index());
|
815
803
|
}
|
@@ -818,11 +806,11 @@ void HGraph::EliminateRedundantPhis() {
|
|
818
806
|
|
819
807
|
|
820
808
|
bool HGraph::CollectPhis() {
|
821
|
-
|
822
|
-
phi_list_ = new ZoneList<HPhi*>(
|
823
|
-
for (int i = 0; i <
|
824
|
-
for (int j = 0; j <
|
825
|
-
HPhi* phi =
|
809
|
+
int block_count = blocks_.length();
|
810
|
+
phi_list_ = new ZoneList<HPhi*>(block_count);
|
811
|
+
for (int i = 0; i < block_count; ++i) {
|
812
|
+
for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
|
813
|
+
HPhi* phi = blocks_[i]->phis()->at(j);
|
826
814
|
phi_list_->Add(phi);
|
827
815
|
// We don't support phi uses of arguments for now.
|
828
816
|
if (phi->CheckFlag(HValue::kIsArguments)) return false;
|
@@ -931,13 +919,15 @@ void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) {
|
|
931
919
|
ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
|
932
920
|
if (test->value()->IsCompare()) {
|
933
921
|
HCompare* compare = HCompare::cast(test->value());
|
934
|
-
|
935
|
-
|
936
|
-
|
922
|
+
if (compare->GetInputRepresentation().IsInteger32()) {
|
923
|
+
Token::Value op = compare->token();
|
924
|
+
if (test->SecondSuccessor() == dest) {
|
925
|
+
op = Token::NegateCompareOp(op);
|
926
|
+
}
|
927
|
+
Token::Value inverted_op = Token::InvertCompareOp(op);
|
928
|
+
InferControlFlowRange(op, compare->left(), compare->right());
|
929
|
+
InferControlFlowRange(inverted_op, compare->right(), compare->left());
|
937
930
|
}
|
938
|
-
Token::Value inverted_op = Token::InvertCompareOp(op);
|
939
|
-
InferControlFlowRange(op, compare->left(), compare->right());
|
940
|
-
InferControlFlowRange(inverted_op, compare->right(), compare->left());
|
941
931
|
}
|
942
932
|
}
|
943
933
|
|
@@ -947,8 +937,8 @@ void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) {
|
|
947
937
|
void HRangeAnalysis::InferControlFlowRange(Token::Value op,
|
948
938
|
HValue* value,
|
949
939
|
HValue* other) {
|
950
|
-
Range
|
951
|
-
|
940
|
+
Range temp_range;
|
941
|
+
Range* range = other->range() != NULL ? other->range() : &temp_range;
|
952
942
|
Range* new_range = NULL;
|
953
943
|
|
954
944
|
TraceRange("Control flow range infer %d %s %d\n",
|
@@ -1040,8 +1030,8 @@ HValueMap::HValueMap(const HValueMap* other)
|
|
1040
1030
|
lists_size_(other->lists_size_),
|
1041
1031
|
count_(other->count_),
|
1042
1032
|
present_flags_(other->present_flags_),
|
1043
|
-
array_(
|
1044
|
-
lists_(
|
1033
|
+
array_(ZONE->NewArray<HValueMapListElement>(other->array_size_)),
|
1034
|
+
lists_(ZONE->NewArray<HValueMapListElement>(other->lists_size_)),
|
1045
1035
|
free_list_head_(other->free_list_head_) {
|
1046
1036
|
memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement));
|
1047
1037
|
memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
|
@@ -1120,7 +1110,7 @@ void HValueMap::Resize(int new_size) {
|
|
1120
1110
|
}
|
1121
1111
|
|
1122
1112
|
HValueMapListElement* new_array =
|
1123
|
-
|
1113
|
+
ZONE->NewArray<HValueMapListElement>(new_size);
|
1124
1114
|
memset(new_array, 0, sizeof(HValueMapListElement) * new_size);
|
1125
1115
|
|
1126
1116
|
HValueMapListElement* old_array = array_;
|
@@ -1158,7 +1148,7 @@ void HValueMap::ResizeLists(int new_size) {
|
|
1158
1148
|
ASSERT(new_size > lists_size_);
|
1159
1149
|
|
1160
1150
|
HValueMapListElement* new_lists =
|
1161
|
-
|
1151
|
+
ZONE->NewArray<HValueMapListElement>(new_size);
|
1162
1152
|
memset(new_lists, 0, sizeof(HValueMapListElement) * new_size);
|
1163
1153
|
|
1164
1154
|
HValueMapListElement* old_lists = lists_;
|
@@ -1256,16 +1246,17 @@ void HStackCheckEliminator::RemoveStackCheck(HBasicBlock* block) {
|
|
1256
1246
|
|
1257
1247
|
class HGlobalValueNumberer BASE_EMBEDDED {
|
1258
1248
|
public:
|
1259
|
-
explicit HGlobalValueNumberer(HGraph* graph)
|
1249
|
+
explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info)
|
1260
1250
|
: graph_(graph),
|
1251
|
+
info_(info),
|
1261
1252
|
block_side_effects_(graph_->blocks()->length()),
|
1262
1253
|
loop_side_effects_(graph_->blocks()->length()) {
|
1263
|
-
ASSERT(
|
1254
|
+
ASSERT(info->isolate()->heap()->allow_allocation(false));
|
1264
1255
|
block_side_effects_.AddBlock(0, graph_->blocks()->length());
|
1265
1256
|
loop_side_effects_.AddBlock(0, graph_->blocks()->length());
|
1266
1257
|
}
|
1267
1258
|
~HGlobalValueNumberer() {
|
1268
|
-
ASSERT(!
|
1259
|
+
ASSERT(!info_->isolate()->heap()->allow_allocation(true));
|
1269
1260
|
}
|
1270
1261
|
|
1271
1262
|
void Analyze();
|
@@ -1277,9 +1268,14 @@ class HGlobalValueNumberer BASE_EMBEDDED {
|
|
1277
1268
|
void ProcessLoopBlock(HBasicBlock* block,
|
1278
1269
|
HBasicBlock* before_loop,
|
1279
1270
|
int loop_kills);
|
1271
|
+
bool AllowCodeMotion();
|
1280
1272
|
bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);
|
1281
1273
|
|
1274
|
+
HGraph* graph() { return graph_; }
|
1275
|
+
CompilationInfo* info() { return info_; }
|
1276
|
+
|
1282
1277
|
HGraph* graph_;
|
1278
|
+
CompilationInfo* info_;
|
1283
1279
|
|
1284
1280
|
// A map of block IDs to their side effects.
|
1285
1281
|
ZoneList<int> block_side_effects_;
|
@@ -1380,10 +1376,15 @@ void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block,
|
|
1380
1376
|
}
|
1381
1377
|
|
1382
1378
|
|
1379
|
+
bool HGlobalValueNumberer::AllowCodeMotion() {
|
1380
|
+
return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount;
|
1381
|
+
}
|
1382
|
+
|
1383
|
+
|
1383
1384
|
bool HGlobalValueNumberer::ShouldMove(HInstruction* instr,
|
1384
1385
|
HBasicBlock* loop_header) {
|
1385
1386
|
// If we've disabled code motion, don't move any instructions.
|
1386
|
-
if (!
|
1387
|
+
if (!AllowCodeMotion()) return false;
|
1387
1388
|
|
1388
1389
|
// If --aggressive-loop-invariant-motion, move everything except change
|
1389
1390
|
// instructions.
|
@@ -1443,8 +1444,7 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
|
|
1443
1444
|
instr->Mnemonic(),
|
1444
1445
|
other->id(),
|
1445
1446
|
other->Mnemonic());
|
1446
|
-
instr->
|
1447
|
-
instr->Delete();
|
1447
|
+
instr->ReplaceAndDelete(other);
|
1448
1448
|
} else {
|
1449
1449
|
map->Add(instr);
|
1450
1450
|
}
|
@@ -1744,8 +1744,7 @@ void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
|
|
1744
1744
|
|
1745
1745
|
void HGraph::InsertRepresentationChangeForUse(HValue* value,
|
1746
1746
|
HValue* use,
|
1747
|
-
Representation to
|
1748
|
-
bool is_truncating) {
|
1747
|
+
Representation to) {
|
1749
1748
|
// Insert the representation change right before its use. For phi-uses we
|
1750
1749
|
// insert at the end of the corresponding predecessor.
|
1751
1750
|
HInstruction* next = NULL;
|
@@ -1762,6 +1761,7 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
|
|
1762
1761
|
// information we treat constants like normal instructions and insert the
|
1763
1762
|
// change instructions for them.
|
1764
1763
|
HInstruction* new_value = NULL;
|
1764
|
+
bool is_truncating = use->CheckFlag(HValue::kTruncatingToInt32);
|
1765
1765
|
if (value->IsConstant()) {
|
1766
1766
|
HConstant* constant = HConstant::cast(value);
|
1767
1767
|
// Try to create a new copy of the constant with the new representation.
|
@@ -1771,7 +1771,7 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
|
|
1771
1771
|
}
|
1772
1772
|
|
1773
1773
|
if (new_value == NULL) {
|
1774
|
-
new_value = new HChange(value, value->representation(), to);
|
1774
|
+
new_value = new HChange(value, value->representation(), to, is_truncating);
|
1775
1775
|
}
|
1776
1776
|
|
1777
1777
|
new_value->InsertBefore(next);
|
@@ -1798,15 +1798,18 @@ int CompareConversionUses(HValue* a,
|
|
1798
1798
|
}
|
1799
1799
|
|
1800
1800
|
|
1801
|
-
void HGraph::
|
1801
|
+
void HGraph::InsertRepresentationChangesForValue(
|
1802
|
+
HValue* current,
|
1803
|
+
ZoneList<HValue*>* to_convert,
|
1804
|
+
ZoneList<Representation>* to_convert_reps) {
|
1802
1805
|
Representation r = current->representation();
|
1803
1806
|
if (r.IsNone()) return;
|
1804
1807
|
if (current->uses()->length() == 0) return;
|
1805
1808
|
|
1806
1809
|
// Collect the representation changes in a sorted list. This allows
|
1807
1810
|
// us to avoid duplicate changes without searching the list.
|
1808
|
-
|
1809
|
-
|
1811
|
+
ASSERT(to_convert->is_empty());
|
1812
|
+
ASSERT(to_convert_reps->is_empty());
|
1810
1813
|
for (int i = 0; i < current->uses()->length(); ++i) {
|
1811
1814
|
HValue* use = current->uses()->at(i);
|
1812
1815
|
// The occurrences index means the index within the operand array of "use"
|
@@ -1826,10 +1829,10 @@ void HGraph::InsertRepresentationChanges(HValue* current) {
|
|
1826
1829
|
Representation req = use->RequiredInputRepresentation(operand_index);
|
1827
1830
|
if (req.IsNone() || req.Equals(r)) continue;
|
1828
1831
|
int index = 0;
|
1829
|
-
while (to_convert
|
1830
|
-
CompareConversionUses(to_convert
|
1832
|
+
while (index < to_convert->length() &&
|
1833
|
+
CompareConversionUses(to_convert->at(index),
|
1831
1834
|
use,
|
1832
|
-
to_convert_reps
|
1835
|
+
to_convert_reps->at(index),
|
1833
1836
|
req) < 0) {
|
1834
1837
|
++index;
|
1835
1838
|
}
|
@@ -1839,21 +1842,22 @@ void HGraph::InsertRepresentationChanges(HValue* current) {
|
|
1839
1842
|
current->id(),
|
1840
1843
|
use->id());
|
1841
1844
|
}
|
1842
|
-
to_convert
|
1843
|
-
to_convert_reps
|
1845
|
+
to_convert->InsertAt(index, use);
|
1846
|
+
to_convert_reps->InsertAt(index, req);
|
1844
1847
|
}
|
1845
1848
|
|
1846
|
-
for (int i = 0; i < to_convert
|
1847
|
-
HValue* use = to_convert
|
1848
|
-
Representation r_to = to_convert_reps
|
1849
|
-
|
1850
|
-
InsertRepresentationChangeForUse(current, use, r_to, is_truncating);
|
1849
|
+
for (int i = 0; i < to_convert->length(); ++i) {
|
1850
|
+
HValue* use = to_convert->at(i);
|
1851
|
+
Representation r_to = to_convert_reps->at(i);
|
1852
|
+
InsertRepresentationChangeForUse(current, use, r_to);
|
1851
1853
|
}
|
1852
1854
|
|
1853
1855
|
if (current->uses()->is_empty()) {
|
1854
1856
|
ASSERT(current->IsConstant());
|
1855
1857
|
current->Delete();
|
1856
1858
|
}
|
1859
|
+
to_convert->Rewind(0);
|
1860
|
+
to_convert_reps->Rewind(0);
|
1857
1861
|
}
|
1858
1862
|
|
1859
1863
|
|
@@ -1889,17 +1893,19 @@ void HGraph::InsertRepresentationChanges() {
|
|
1889
1893
|
}
|
1890
1894
|
}
|
1891
1895
|
|
1896
|
+
ZoneList<HValue*> value_list(4);
|
1897
|
+
ZoneList<Representation> rep_list(4);
|
1892
1898
|
for (int i = 0; i < blocks_.length(); ++i) {
|
1893
1899
|
// Process phi instructions first.
|
1894
1900
|
for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
|
1895
1901
|
HPhi* phi = blocks_[i]->phis()->at(j);
|
1896
|
-
|
1902
|
+
InsertRepresentationChangesForValue(phi, &value_list, &rep_list);
|
1897
1903
|
}
|
1898
1904
|
|
1899
1905
|
// Process normal instructions.
|
1900
1906
|
HInstruction* current = blocks_[i]->first();
|
1901
1907
|
while (current != NULL) {
|
1902
|
-
|
1908
|
+
InsertRepresentationChangesForValue(current, &value_list, &rep_list);
|
1903
1909
|
current = current->next();
|
1904
1910
|
}
|
1905
1911
|
}
|
@@ -1930,10 +1936,54 @@ void HGraph::ComputeMinusZeroChecks() {
|
|
1930
1936
|
}
|
1931
1937
|
|
1932
1938
|
|
1939
|
+
// Implementation of utility class to encapsulate the translation state for
|
1940
|
+
// a (possibly inlined) function.
|
1941
|
+
FunctionState::FunctionState(HGraphBuilder* owner,
|
1942
|
+
CompilationInfo* info,
|
1943
|
+
TypeFeedbackOracle* oracle)
|
1944
|
+
: owner_(owner),
|
1945
|
+
compilation_info_(info),
|
1946
|
+
oracle_(oracle),
|
1947
|
+
call_context_(NULL),
|
1948
|
+
function_return_(NULL),
|
1949
|
+
test_context_(NULL),
|
1950
|
+
outer_(owner->function_state()) {
|
1951
|
+
if (outer_ != NULL) {
|
1952
|
+
// State for an inline function.
|
1953
|
+
if (owner->ast_context()->IsTest()) {
|
1954
|
+
HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
|
1955
|
+
HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
|
1956
|
+
if_true->MarkAsInlineReturnTarget();
|
1957
|
+
if_false->MarkAsInlineReturnTarget();
|
1958
|
+
// The AstContext constructor pushed on the context stack. This newed
|
1959
|
+
// instance is the reason that AstContext can't be BASE_EMBEDDED.
|
1960
|
+
test_context_ = new TestContext(owner, if_true, if_false);
|
1961
|
+
} else {
|
1962
|
+
function_return_ = owner->graph()->CreateBasicBlock();
|
1963
|
+
function_return()->MarkAsInlineReturnTarget();
|
1964
|
+
}
|
1965
|
+
// Set this after possibly allocating a new TestContext above.
|
1966
|
+
call_context_ = owner->ast_context();
|
1967
|
+
}
|
1968
|
+
|
1969
|
+
// Push on the state stack.
|
1970
|
+
owner->set_function_state(this);
|
1971
|
+
}
|
1972
|
+
|
1973
|
+
|
1974
|
+
FunctionState::~FunctionState() {
|
1975
|
+
delete test_context_;
|
1976
|
+
owner_->set_function_state(outer_);
|
1977
|
+
}
|
1978
|
+
|
1979
|
+
|
1933
1980
|
// Implementation of utility classes to represent an expression's context in
|
1934
1981
|
// the AST.
|
1935
1982
|
AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind)
|
1936
|
-
: owner_(owner),
|
1983
|
+
: owner_(owner),
|
1984
|
+
kind_(kind),
|
1985
|
+
outer_(owner->ast_context()),
|
1986
|
+
for_typeof_(false) {
|
1937
1987
|
owner->set_ast_context(this); // Push.
|
1938
1988
|
#ifdef DEBUG
|
1939
1989
|
original_length_ = owner->environment()->length();
|
@@ -2015,20 +2065,8 @@ void TestContext::BuildBranch(HValue* value) {
|
|
2015
2065
|
HTest* test = new HTest(value, empty_true, empty_false);
|
2016
2066
|
builder->current_block()->Finish(test);
|
2017
2067
|
|
2018
|
-
|
2019
|
-
|
2020
|
-
if (true_target->IsInlineReturnTarget()) {
|
2021
|
-
empty_true->AddLeaveInlined(no_return_value, true_target);
|
2022
|
-
} else {
|
2023
|
-
empty_true->Goto(true_target);
|
2024
|
-
}
|
2025
|
-
|
2026
|
-
HBasicBlock* false_target = if_false();
|
2027
|
-
if (false_target->IsInlineReturnTarget()) {
|
2028
|
-
empty_false->AddLeaveInlined(no_return_value, false_target);
|
2029
|
-
} else {
|
2030
|
-
empty_false->Goto(false_target);
|
2031
|
-
}
|
2068
|
+
empty_true->Goto(if_true(), false);
|
2069
|
+
empty_false->Goto(if_false(), false);
|
2032
2070
|
builder->set_current_block(NULL);
|
2033
2071
|
}
|
2034
2072
|
|
@@ -2068,40 +2106,10 @@ void TestContext::BuildBranch(HValue* value) {
|
|
2068
2106
|
} while (false)
|
2069
2107
|
|
2070
2108
|
|
2071
|
-
// 'thing' could be an expression, statement, or list of statements.
|
2072
|
-
#define ADD_TO_SUBGRAPH(graph, thing) \
|
2073
|
-
do { \
|
2074
|
-
AddToSubgraph(graph, thing); \
|
2075
|
-
if (HasStackOverflow()) return; \
|
2076
|
-
} while (false)
|
2077
|
-
|
2078
|
-
|
2079
|
-
class HGraphBuilder::SubgraphScope BASE_EMBEDDED {
|
2080
|
-
public:
|
2081
|
-
SubgraphScope(HGraphBuilder* builder, HSubgraph* new_subgraph)
|
2082
|
-
: builder_(builder) {
|
2083
|
-
old_subgraph_ = builder_->current_subgraph_;
|
2084
|
-
subgraph_ = new_subgraph;
|
2085
|
-
builder_->current_subgraph_ = subgraph_;
|
2086
|
-
}
|
2087
|
-
|
2088
|
-
~SubgraphScope() {
|
2089
|
-
builder_->current_subgraph_ = old_subgraph_;
|
2090
|
-
}
|
2091
|
-
|
2092
|
-
HSubgraph* subgraph() const { return subgraph_; }
|
2093
|
-
|
2094
|
-
private:
|
2095
|
-
HGraphBuilder* builder_;
|
2096
|
-
HSubgraph* old_subgraph_;
|
2097
|
-
HSubgraph* subgraph_;
|
2098
|
-
};
|
2099
|
-
|
2100
|
-
|
2101
2109
|
void HGraphBuilder::Bailout(const char* reason) {
|
2102
2110
|
if (FLAG_trace_bailout) {
|
2103
|
-
SmartPointer<char>
|
2104
|
-
PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *
|
2111
|
+
SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
|
2112
|
+
PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason);
|
2105
2113
|
}
|
2106
2114
|
SetStackOverflow();
|
2107
2115
|
}
|
@@ -2119,6 +2127,14 @@ void HGraphBuilder::VisitForValue(Expression* expr) {
|
|
2119
2127
|
}
|
2120
2128
|
|
2121
2129
|
|
2130
|
+
void HGraphBuilder::VisitForTypeOf(Expression* expr) {
|
2131
|
+
ValueContext for_value(this);
|
2132
|
+
for_value.set_for_typeof(true);
|
2133
|
+
Visit(expr);
|
2134
|
+
}
|
2135
|
+
|
2136
|
+
|
2137
|
+
|
2122
2138
|
void HGraphBuilder::VisitForControl(Expression* expr,
|
2123
2139
|
HBasicBlock* true_block,
|
2124
2140
|
HBasicBlock* false_block) {
|
@@ -2148,88 +2164,87 @@ void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) {
|
|
2148
2164
|
}
|
2149
2165
|
|
2150
2166
|
|
2151
|
-
HGraph* HGraphBuilder::CreateGraph(
|
2152
|
-
|
2153
|
-
|
2167
|
+
HGraph* HGraphBuilder::CreateGraph() {
|
2168
|
+
graph_ = new HGraph(info());
|
2169
|
+
if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info());
|
2154
2170
|
|
2155
2171
|
{
|
2156
2172
|
HPhase phase("Block building");
|
2157
|
-
|
2158
|
-
current_subgraph_ = graph_;
|
2173
|
+
current_block_ = graph()->entry_block();
|
2159
2174
|
|
2160
|
-
Scope* scope = info->scope();
|
2175
|
+
Scope* scope = info()->scope();
|
2176
|
+
if (scope->HasIllegalRedeclaration()) {
|
2177
|
+
Bailout("function with illegal redeclaration");
|
2178
|
+
return NULL;
|
2179
|
+
}
|
2161
2180
|
SetupScope(scope);
|
2162
2181
|
VisitDeclarations(scope->declarations());
|
2163
|
-
|
2164
2182
|
AddInstruction(new HStackCheck());
|
2165
2183
|
|
2166
|
-
|
2167
|
-
|
2168
|
-
|
2184
|
+
// Add an edge to the body entry. This is warty: the graph's start
|
2185
|
+
// environment will be used by the Lithium translation as the initial
|
2186
|
+
// environment on graph entry, but it has now been mutated by the
|
2187
|
+
// Hydrogen translation of the instructions in the start block. This
|
2188
|
+
// environment uses values which have not been defined yet. These
|
2189
|
+
// Hydrogen instructions will then be replayed by the Lithium
|
2190
|
+
// translation, so they cannot have an environment effect. The edge to
|
2191
|
+
// the body's entry block (along with some special logic for the start
|
2192
|
+
// block in HInstruction::InsertAfter) seals the start block from
|
2193
|
+
// getting unwanted instructions inserted.
|
2194
|
+
//
|
2195
|
+
// TODO(kmillikin): Fix this. Stop mutating the initial environment.
|
2196
|
+
// Make the Hydrogen instructions in the initial block into Hydrogen
|
2197
|
+
// values (but not instructions), present in the initial environment and
|
2198
|
+
// not replayed by the Lithium translation.
|
2199
|
+
HEnvironment* initial_env = environment()->CopyWithoutHistory();
|
2200
|
+
HBasicBlock* body_entry = CreateBasicBlock(initial_env);
|
2201
|
+
current_block()->Goto(body_entry);
|
2202
|
+
body_entry->SetJoinId(info()->function()->id());
|
2203
|
+
set_current_block(body_entry);
|
2204
|
+
VisitStatements(info()->function()->body());
|
2169
2205
|
if (HasStackOverflow()) return NULL;
|
2170
|
-
current_subgraph_->Append(NULL,
|
2171
|
-
body->entry_block(),
|
2172
|
-
body->exit_block(),
|
2173
|
-
NULL);
|
2174
|
-
body->entry_block()->SetJoinId(info->function()->id());
|
2175
2206
|
|
2176
|
-
if (
|
2177
|
-
|
2207
|
+
if (current_block() != NULL) {
|
2208
|
+
HReturn* instr = new HReturn(graph()->GetConstantUndefined());
|
2209
|
+
current_block()->FinishExit(instr);
|
2210
|
+
set_current_block(NULL);
|
2178
2211
|
}
|
2179
2212
|
}
|
2180
2213
|
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
if (
|
2214
|
+
graph()->OrderBlocks();
|
2215
|
+
graph()->AssignDominators();
|
2216
|
+
graph()->EliminateRedundantPhis();
|
2217
|
+
if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis();
|
2218
|
+
if (!graph()->CollectPhis()) {
|
2185
2219
|
Bailout("Phi-use of arguments object");
|
2186
2220
|
return NULL;
|
2187
2221
|
}
|
2188
2222
|
|
2189
|
-
HInferRepresentation rep(
|
2223
|
+
HInferRepresentation rep(graph());
|
2190
2224
|
rep.Analyze();
|
2191
2225
|
|
2192
2226
|
if (FLAG_use_range) {
|
2193
|
-
HRangeAnalysis rangeAnalysis(
|
2227
|
+
HRangeAnalysis rangeAnalysis(graph());
|
2194
2228
|
rangeAnalysis.Analyze();
|
2195
2229
|
}
|
2196
2230
|
|
2197
|
-
|
2198
|
-
|
2199
|
-
|
2200
|
-
|
2231
|
+
graph()->InitializeInferredTypes();
|
2232
|
+
graph()->Canonicalize();
|
2233
|
+
graph()->InsertRepresentationChanges();
|
2234
|
+
graph()->ComputeMinusZeroChecks();
|
2201
2235
|
|
2202
2236
|
// Eliminate redundant stack checks on backwards branches.
|
2203
|
-
HStackCheckEliminator sce(
|
2237
|
+
HStackCheckEliminator sce(graph());
|
2204
2238
|
sce.Process();
|
2205
2239
|
|
2206
2240
|
// Perform common subexpression elimination and loop-invariant code motion.
|
2207
2241
|
if (FLAG_use_gvn) {
|
2208
|
-
HPhase phase("Global value numbering",
|
2209
|
-
HGlobalValueNumberer gvn(
|
2242
|
+
HPhase phase("Global value numbering", graph());
|
2243
|
+
HGlobalValueNumberer gvn(graph(), info());
|
2210
2244
|
gvn.Analyze();
|
2211
2245
|
}
|
2212
2246
|
|
2213
|
-
return
|
2214
|
-
}
|
2215
|
-
|
2216
|
-
|
2217
|
-
void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) {
|
2218
|
-
SubgraphScope scope(this, graph);
|
2219
|
-
Visit(stmt);
|
2220
|
-
}
|
2221
|
-
|
2222
|
-
|
2223
|
-
void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) {
|
2224
|
-
SubgraphScope scope(this, graph);
|
2225
|
-
VisitForValue(expr);
|
2226
|
-
}
|
2227
|
-
|
2228
|
-
|
2229
|
-
void HGraphBuilder::AddToSubgraph(HSubgraph* graph,
|
2230
|
-
ZoneList<Statement*>* stmts) {
|
2231
|
-
SubgraphScope scope(this, graph);
|
2232
|
-
VisitStatements(stmts);
|
2247
|
+
return graph();
|
2233
2248
|
}
|
2234
2249
|
|
2235
2250
|
|
@@ -2277,8 +2292,8 @@ void HGraphBuilder::SetupScope(Scope* scope) {
|
|
2277
2292
|
// We don't yet handle the function name for named function expressions.
|
2278
2293
|
if (scope->function() != NULL) BAILOUT("named function expression");
|
2279
2294
|
|
2280
|
-
HConstant* undefined_constant =
|
2281
|
-
|
2295
|
+
HConstant* undefined_constant = new HConstant(
|
2296
|
+
isolate()->factory()->undefined_value(), Representation::Tagged());
|
2282
2297
|
AddInstruction(undefined_constant);
|
2283
2298
|
graph_->set_undefined_constant(undefined_constant);
|
2284
2299
|
|
@@ -2299,14 +2314,17 @@ void HGraphBuilder::SetupScope(Scope* scope) {
|
|
2299
2314
|
// not have declarations).
|
2300
2315
|
if (scope->arguments() != NULL) {
|
2301
2316
|
if (!scope->arguments()->IsStackAllocated() ||
|
2302
|
-
|
2317
|
+
(scope->arguments_shadow() != NULL &&
|
2318
|
+
!scope->arguments_shadow()->IsStackAllocated())) {
|
2303
2319
|
BAILOUT("context-allocated arguments");
|
2304
2320
|
}
|
2305
2321
|
HArgumentsObject* object = new HArgumentsObject;
|
2306
2322
|
AddInstruction(object);
|
2307
2323
|
graph()->SetArgumentsObject(object);
|
2308
2324
|
environment()->Bind(scope->arguments(), object);
|
2309
|
-
|
2325
|
+
if (scope->arguments_shadow() != NULL) {
|
2326
|
+
environment()->Bind(scope->arguments_shadow(), object);
|
2327
|
+
}
|
2310
2328
|
}
|
2311
2329
|
}
|
2312
2330
|
|
@@ -2326,65 +2344,26 @@ HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
|
|
2326
2344
|
}
|
2327
2345
|
|
2328
2346
|
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2333
|
-
|
2334
|
-
|
2335
|
-
HSubgraph* subgraph = new HSubgraph(graph());
|
2336
|
-
subgraph->Initialize(CreateBasicBlock(inner));
|
2337
|
-
return subgraph;
|
2338
|
-
}
|
2339
|
-
|
2340
|
-
|
2341
|
-
HSubgraph* HGraphBuilder::CreateGotoSubgraph(HEnvironment* env) {
|
2342
|
-
HSubgraph* subgraph = new HSubgraph(graph());
|
2343
|
-
HEnvironment* new_env = env->CopyWithoutHistory();
|
2344
|
-
subgraph->Initialize(CreateBasicBlock(new_env));
|
2345
|
-
return subgraph;
|
2346
|
-
}
|
2347
|
-
|
2348
|
-
|
2349
|
-
HSubgraph* HGraphBuilder::CreateEmptySubgraph() {
|
2350
|
-
HSubgraph* subgraph = new HSubgraph(graph());
|
2351
|
-
subgraph->Initialize(graph()->CreateBasicBlock());
|
2352
|
-
return subgraph;
|
2353
|
-
}
|
2354
|
-
|
2355
|
-
|
2356
|
-
HSubgraph* HGraphBuilder::CreateBranchSubgraph(HEnvironment* env) {
|
2357
|
-
HSubgraph* subgraph = new HSubgraph(graph());
|
2358
|
-
HEnvironment* new_env = env->Copy();
|
2359
|
-
subgraph->Initialize(CreateBasicBlock(new_env));
|
2360
|
-
return subgraph;
|
2361
|
-
}
|
2362
|
-
|
2363
|
-
|
2364
|
-
HSubgraph* HGraphBuilder::CreateLoopHeaderSubgraph(HEnvironment* env) {
|
2365
|
-
HSubgraph* subgraph = new HSubgraph(graph());
|
2366
|
-
HBasicBlock* block = graph()->CreateBasicBlock();
|
2367
|
-
HEnvironment* new_env = env->CopyAsLoopHeader(block);
|
2368
|
-
block->SetInitialEnvironment(new_env);
|
2369
|
-
subgraph->Initialize(block);
|
2370
|
-
subgraph->entry_block()->AttachLoopInformation();
|
2371
|
-
return subgraph;
|
2347
|
+
HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
|
2348
|
+
HBasicBlock* header = graph()->CreateBasicBlock();
|
2349
|
+
HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
|
2350
|
+
header->SetInitialEnvironment(entry_env);
|
2351
|
+
header->AttachLoopInformation();
|
2352
|
+
return header;
|
2372
2353
|
}
|
2373
2354
|
|
2374
2355
|
|
2375
2356
|
void HGraphBuilder::VisitBlock(Block* stmt) {
|
2376
|
-
|
2377
|
-
|
2378
|
-
BreakAndContinueInfo break_info(stmt);
|
2379
|
-
{ BreakAndContinueScope push(&break_info, this);
|
2380
|
-
ADD_TO_SUBGRAPH(block_graph, stmt->statements());
|
2381
|
-
}
|
2382
|
-
subgraph()->Append(stmt,
|
2383
|
-
block_graph->entry_block(),
|
2384
|
-
block_graph->exit_block(),
|
2385
|
-
break_info.break_block());
|
2386
|
-
} else {
|
2357
|
+
BreakAndContinueInfo break_info(stmt);
|
2358
|
+
{ BreakAndContinueScope push(&break_info, this);
|
2387
2359
|
VisitStatements(stmt->statements());
|
2360
|
+
CHECK_BAILOUT;
|
2361
|
+
}
|
2362
|
+
HBasicBlock* break_block = break_info.break_block();
|
2363
|
+
if (break_block != NULL) {
|
2364
|
+
if (current_block() != NULL) current_block()->Goto(break_block);
|
2365
|
+
break_block->SetJoinId(stmt->ExitId());
|
2366
|
+
set_current_block(break_block);
|
2388
2367
|
}
|
2389
2368
|
}
|
2390
2369
|
|
@@ -2406,21 +2385,23 @@ void HGraphBuilder::VisitIfStatement(IfStatement* stmt) {
|
|
2406
2385
|
AddSimulate(stmt->ElseId());
|
2407
2386
|
Visit(stmt->else_statement());
|
2408
2387
|
} else {
|
2409
|
-
|
2410
|
-
|
2411
|
-
VISIT_FOR_CONTROL(stmt->condition(),
|
2412
|
-
|
2413
|
-
|
2388
|
+
HBasicBlock* cond_true = graph()->CreateBasicBlock();
|
2389
|
+
HBasicBlock* cond_false = graph()->CreateBasicBlock();
|
2390
|
+
VISIT_FOR_CONTROL(stmt->condition(), cond_true, cond_false);
|
2391
|
+
cond_true->SetJoinId(stmt->ThenId());
|
2392
|
+
cond_false->SetJoinId(stmt->ElseId());
|
2414
2393
|
|
2415
|
-
|
2416
|
-
|
2394
|
+
set_current_block(cond_true);
|
2395
|
+
Visit(stmt->then_statement());
|
2396
|
+
CHECK_BAILOUT;
|
2397
|
+
HBasicBlock* other = current_block();
|
2417
2398
|
|
2418
|
-
|
2419
|
-
|
2399
|
+
set_current_block(cond_false);
|
2400
|
+
Visit(stmt->else_statement());
|
2401
|
+
CHECK_BAILOUT;
|
2420
2402
|
|
2421
|
-
|
2422
|
-
|
2423
|
-
stmt->id());
|
2403
|
+
HBasicBlock* join = CreateJoin(other, current_block(), stmt->id());
|
2404
|
+
set_current_block(join);
|
2424
2405
|
}
|
2425
2406
|
}
|
2426
2407
|
|
@@ -2476,7 +2457,8 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
|
|
2476
2457
|
// Not an inlined return, so an actual one.
|
2477
2458
|
VISIT_FOR_VALUE(stmt->expression());
|
2478
2459
|
HValue* result = environment()->Pop();
|
2479
|
-
|
2460
|
+
current_block()->FinishExit(new HReturn(result));
|
2461
|
+
set_current_block(NULL);
|
2480
2462
|
} else {
|
2481
2463
|
// Return from an inlined function, visit the subexpression in the
|
2482
2464
|
// expression context of the call.
|
@@ -2485,20 +2467,16 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
|
|
2485
2467
|
VisitForControl(stmt->expression(),
|
2486
2468
|
test->if_true(),
|
2487
2469
|
test->if_false());
|
2470
|
+
} else if (context->IsEffect()) {
|
2471
|
+
VISIT_FOR_EFFECT(stmt->expression());
|
2472
|
+
current_block()->Goto(function_return(), false);
|
2488
2473
|
} else {
|
2489
|
-
|
2490
|
-
|
2491
|
-
|
2492
|
-
|
2493
|
-
} else {
|
2494
|
-
ASSERT(context->IsValue());
|
2495
|
-
VISIT_FOR_VALUE(stmt->expression());
|
2496
|
-
return_value = environment()->Pop();
|
2497
|
-
}
|
2498
|
-
current_block()->AddLeaveInlined(return_value,
|
2499
|
-
function_return_);
|
2500
|
-
set_current_block(NULL);
|
2474
|
+
ASSERT(context->IsValue());
|
2475
|
+
VISIT_FOR_VALUE(stmt->expression());
|
2476
|
+
HValue* return_value = environment()->Pop();
|
2477
|
+
current_block()->AddLeaveInlined(return_value, function_return());
|
2501
2478
|
}
|
2479
|
+
set_current_block(NULL);
|
2502
2480
|
}
|
2503
2481
|
}
|
2504
2482
|
|
@@ -2513,378 +2491,270 @@ void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
|
|
2513
2491
|
}
|
2514
2492
|
|
2515
2493
|
|
2516
|
-
HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph,
|
2517
|
-
HValue* switch_value,
|
2518
|
-
CaseClause* clause) {
|
2519
|
-
AddToSubgraph(subgraph, clause->label());
|
2520
|
-
if (HasStackOverflow()) return NULL;
|
2521
|
-
HValue* clause_value = subgraph->exit_block()->last_environment()->Pop();
|
2522
|
-
HCompare* compare = new HCompare(switch_value,
|
2523
|
-
clause_value,
|
2524
|
-
Token::EQ_STRICT);
|
2525
|
-
compare->SetInputRepresentation(Representation::Integer32());
|
2526
|
-
subgraph->exit_block()->AddInstruction(compare);
|
2527
|
-
return compare;
|
2528
|
-
}
|
2529
|
-
|
2530
|
-
|
2531
2494
|
void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
|
2495
|
+
// We only optimize switch statements with smi-literal smi comparisons,
|
2496
|
+
// with a bounded number of clauses.
|
2497
|
+
const int kCaseClauseLimit = 128;
|
2498
|
+
ZoneList<CaseClause*>* clauses = stmt->cases();
|
2499
|
+
int clause_count = clauses->length();
|
2500
|
+
if (clause_count > kCaseClauseLimit) {
|
2501
|
+
BAILOUT("SwitchStatement: too many clauses");
|
2502
|
+
}
|
2503
|
+
|
2532
2504
|
VISIT_FOR_VALUE(stmt->tag());
|
2533
|
-
// TODO(3168478): simulate added for tag should be enough.
|
2534
2505
|
AddSimulate(stmt->EntryId());
|
2535
|
-
HValue*
|
2536
|
-
|
2537
|
-
ZoneList<CaseClause*>* clauses = stmt->cases();
|
2538
|
-
int num_clauses = clauses->length();
|
2539
|
-
if (num_clauses == 0) return;
|
2540
|
-
if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses");
|
2506
|
+
HValue* tag_value = Pop();
|
2507
|
+
HBasicBlock* first_test_block = current_block();
|
2541
2508
|
|
2542
|
-
|
2543
|
-
|
2509
|
+
// 1. Build all the tests, with dangling true branches. Unconditionally
|
2510
|
+
// deoptimize if we encounter a non-smi comparison.
|
2511
|
+
for (int i = 0; i < clause_count; ++i) {
|
2544
2512
|
CaseClause* clause = clauses->at(i);
|
2545
2513
|
if (clause->is_default()) continue;
|
2546
|
-
clause->RecordTypeFeedback(oracle());
|
2547
|
-
if (!clause->IsSmiCompare()) {
|
2548
|
-
if (i == 0) BAILOUT("SwitchStatement: no smi compares");
|
2549
|
-
// We will deoptimize if the first non-smi compare is reached.
|
2550
|
-
num_smi_clauses = i;
|
2551
|
-
break;
|
2552
|
-
}
|
2553
2514
|
if (!clause->label()->IsSmiLiteral()) {
|
2554
2515
|
BAILOUT("SwitchStatement: non-literal switch label");
|
2555
2516
|
}
|
2556
|
-
}
|
2557
|
-
|
2558
|
-
// The single exit block of the whole switch statement.
|
2559
|
-
HBasicBlock* single_exit_block = graph_->CreateBasicBlock();
|
2560
|
-
|
2561
|
-
// Build a series of empty subgraphs for the comparisons.
|
2562
|
-
// The default clause does not have a comparison subgraph.
|
2563
|
-
ZoneList<HSubgraph*> compare_graphs(num_smi_clauses);
|
2564
|
-
for (int i = 0; i < num_smi_clauses; i++) {
|
2565
|
-
if (clauses->at(i)->is_default()) {
|
2566
|
-
compare_graphs.Add(NULL);
|
2567
|
-
} else {
|
2568
|
-
compare_graphs.Add(CreateEmptySubgraph());
|
2569
|
-
}
|
2570
|
-
}
|
2571
2517
|
|
2572
|
-
|
2573
|
-
|
2574
|
-
|
2575
|
-
|
2576
|
-
|
2577
|
-
|
2578
|
-
// Finish the previous graph by connecting it to the current.
|
2579
|
-
HSubgraph* subgraph = compare_graphs.at(i);
|
2580
|
-
if (prev_compare_inst == NULL) {
|
2581
|
-
ASSERT(prev_graph == current_subgraph_);
|
2582
|
-
prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block()));
|
2583
|
-
} else {
|
2584
|
-
HBasicBlock* empty = graph()->CreateBasicBlock();
|
2585
|
-
prev_graph->exit_block()->Finish(new HTest(prev_compare_inst,
|
2586
|
-
empty,
|
2587
|
-
subgraph->entry_block()));
|
2518
|
+
// Unconditionally deoptimize on the first non-smi compare.
|
2519
|
+
clause->RecordTypeFeedback(oracle());
|
2520
|
+
if (!clause->IsSmiCompare()) {
|
2521
|
+
current_block()->FinishExitWithDeoptimization();
|
2522
|
+
set_current_block(NULL);
|
2523
|
+
break;
|
2588
2524
|
}
|
2589
2525
|
|
2590
|
-
//
|
2591
|
-
|
2592
|
-
|
2593
|
-
|
2594
|
-
|
2595
|
-
|
2596
|
-
|
2597
|
-
|
2598
|
-
|
2599
|
-
|
2600
|
-
|
2601
|
-
|
2602
|
-
|
2603
|
-
|
2604
|
-
|
2605
|
-
|
2606
|
-
|
2607
|
-
|
2608
|
-
|
2609
|
-
|
2610
|
-
|
2611
|
-
|
2612
|
-
|
2613
|
-
|
2614
|
-
|
2615
|
-
|
2526
|
+
// Otherwise generate a compare and branch.
|
2527
|
+
VISIT_FOR_VALUE(clause->label());
|
2528
|
+
HValue* label_value = Pop();
|
2529
|
+
HCompare* compare = new HCompare(tag_value, label_value, Token::EQ_STRICT);
|
2530
|
+
compare->SetInputRepresentation(Representation::Integer32());
|
2531
|
+
ASSERT(!compare->HasSideEffects());
|
2532
|
+
AddInstruction(compare);
|
2533
|
+
HBasicBlock* body_block = graph()->CreateBasicBlock();
|
2534
|
+
HBasicBlock* next_test_block = graph()->CreateBasicBlock();
|
2535
|
+
HTest* branch = new HTest(compare, body_block, next_test_block);
|
2536
|
+
current_block()->Finish(branch);
|
2537
|
+
set_current_block(next_test_block);
|
2538
|
+
}
|
2539
|
+
|
2540
|
+
// Save the current block to use for the default or to join with the
|
2541
|
+
// exit. This block is NULL if we deoptimized.
|
2542
|
+
HBasicBlock* last_block = current_block();
|
2543
|
+
|
2544
|
+
// 2. Loop over the clauses and the linked list of tests in lockstep,
|
2545
|
+
// translating the clause bodies.
|
2546
|
+
HBasicBlock* curr_test_block = first_test_block;
|
2547
|
+
HBasicBlock* fall_through_block = NULL;
|
2548
|
+
BreakAndContinueInfo break_info(stmt);
|
2549
|
+
{ BreakAndContinueScope push(&break_info, this);
|
2550
|
+
for (int i = 0; i < clause_count; ++i) {
|
2551
|
+
CaseClause* clause = clauses->at(i);
|
2552
|
+
|
2553
|
+
// Identify the block where normal (non-fall-through) control flow
|
2554
|
+
// goes to.
|
2555
|
+
HBasicBlock* normal_block = NULL;
|
2556
|
+
if (clause->is_default() && last_block != NULL) {
|
2557
|
+
normal_block = last_block;
|
2558
|
+
last_block = NULL; // Cleared to indicate we've handled it.
|
2559
|
+
} else if (!curr_test_block->end()->IsDeoptimize()) {
|
2560
|
+
normal_block = curr_test_block->end()->FirstSuccessor();
|
2561
|
+
curr_test_block = curr_test_block->end()->SecondSuccessor();
|
2562
|
+
}
|
2616
2563
|
|
2617
|
-
|
2618
|
-
|
2619
|
-
|
2620
|
-
|
2621
|
-
|
2622
|
-
|
2623
|
-
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
2627
|
-
|
2628
|
-
|
2629
|
-
if (!last_false_block->IsFinished()) {
|
2630
|
-
// Default clause: Connect it to the last false block.
|
2631
|
-
subgraph = CreateEmptySubgraph();
|
2632
|
-
last_false_block->Finish(new HGoto(subgraph->entry_block()));
|
2564
|
+
// Identify a block to emit the body into.
|
2565
|
+
if (normal_block == NULL) {
|
2566
|
+
if (fall_through_block == NULL) {
|
2567
|
+
// (a) Unreachable.
|
2568
|
+
if (clause->is_default()) {
|
2569
|
+
continue; // Might still be reachable clause bodies.
|
2570
|
+
} else {
|
2571
|
+
break;
|
2572
|
+
}
|
2573
|
+
} else {
|
2574
|
+
// (b) Reachable only as fall through.
|
2575
|
+
set_current_block(fall_through_block);
|
2633
2576
|
}
|
2577
|
+
} else if (fall_through_block == NULL) {
|
2578
|
+
// (c) Reachable only normally.
|
2579
|
+
set_current_block(normal_block);
|
2634
2580
|
} else {
|
2635
|
-
|
2636
|
-
|
2637
|
-
|
2638
|
-
|
2639
|
-
|
2640
|
-
empty->Finish(new HGoto(subgraph->entry_block()));
|
2581
|
+
// (d) Reachable both ways.
|
2582
|
+
HBasicBlock* join = CreateJoin(fall_through_block,
|
2583
|
+
normal_block,
|
2584
|
+
clause->EntryId());
|
2585
|
+
set_current_block(join);
|
2641
2586
|
}
|
2642
|
-
}
|
2643
|
-
|
2644
|
-
// Check for fall-through from previous statement block.
|
2645
|
-
if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) {
|
2646
|
-
if (subgraph == NULL) subgraph = CreateEmptySubgraph();
|
2647
|
-
previous_subgraph->exit_block()->
|
2648
|
-
Finish(new HGoto(subgraph->entry_block()));
|
2649
|
-
}
|
2650
2587
|
|
2651
|
-
|
2652
|
-
|
2653
|
-
|
2654
|
-
ADD_TO_SUBGRAPH(subgraph, clause->statements());
|
2655
|
-
}
|
2656
|
-
if (break_info.break_block() != NULL) {
|
2657
|
-
break_info.break_block()->SetJoinId(stmt->ExitId());
|
2658
|
-
break_info.break_block()->Finish(new HGoto(single_exit_block));
|
2659
|
-
}
|
2588
|
+
VisitStatements(clause->statements());
|
2589
|
+
CHECK_BAILOUT;
|
2590
|
+
fall_through_block = current_block();
|
2660
2591
|
}
|
2661
|
-
|
2662
|
-
previous_subgraph = subgraph;
|
2663
|
-
}
|
2664
|
-
|
2665
|
-
// If the last statement block has a fall-through, connect it to the
|
2666
|
-
// single exit block.
|
2667
|
-
if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) {
|
2668
|
-
previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block));
|
2669
2592
|
}
|
2670
2593
|
|
2671
|
-
//
|
2672
|
-
|
2673
|
-
|
2674
|
-
|
2675
|
-
|
2676
|
-
|
2677
|
-
|
2594
|
+
// Create an up-to-3-way join. Use the break block if it exists since
|
2595
|
+
// it's already a join block.
|
2596
|
+
HBasicBlock* break_block = break_info.break_block();
|
2597
|
+
if (break_block == NULL) {
|
2598
|
+
set_current_block(CreateJoin(fall_through_block,
|
2599
|
+
last_block,
|
2600
|
+
stmt->ExitId()));
|
2678
2601
|
} else {
|
2679
|
-
|
2602
|
+
if (fall_through_block != NULL) fall_through_block->Goto(break_block);
|
2603
|
+
if (last_block != NULL) last_block->Goto(break_block);
|
2604
|
+
break_block->SetJoinId(stmt->ExitId());
|
2605
|
+
set_current_block(break_block);
|
2680
2606
|
}
|
2681
2607
|
}
|
2682
2608
|
|
2683
|
-
|
2609
|
+
|
2610
|
+
bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) {
|
2684
2611
|
return statement->OsrEntryId() == info()->osr_ast_id();
|
2685
2612
|
}
|
2686
2613
|
|
2687
2614
|
|
2688
|
-
void
|
2689
|
-
if (!
|
2615
|
+
void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) {
|
2616
|
+
if (!HasOsrEntryAt(statement)) return;
|
2690
2617
|
|
2691
2618
|
HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
|
2692
2619
|
HBasicBlock* osr_entry = graph()->CreateBasicBlock();
|
2693
2620
|
HValue* true_value = graph()->GetConstantTrue();
|
2694
2621
|
HTest* test = new HTest(true_value, non_osr_entry, osr_entry);
|
2695
|
-
|
2622
|
+
current_block()->Finish(test);
|
2696
2623
|
|
2697
2624
|
HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
|
2698
2625
|
non_osr_entry->Goto(loop_predecessor);
|
2699
2626
|
|
2627
|
+
set_current_block(osr_entry);
|
2700
2628
|
int osr_entry_id = statement->OsrEntryId();
|
2701
2629
|
// We want the correct environment at the OsrEntry instruction. Build
|
2702
2630
|
// it explicitly. The expression stack should be empty.
|
2703
|
-
int count =
|
2704
|
-
ASSERT(count ==
|
2705
|
-
|
2631
|
+
int count = environment()->length();
|
2632
|
+
ASSERT(count ==
|
2633
|
+
(environment()->parameter_count() + environment()->local_count()));
|
2706
2634
|
for (int i = 0; i < count; ++i) {
|
2707
2635
|
HUnknownOSRValue* unknown = new HUnknownOSRValue;
|
2708
|
-
|
2709
|
-
|
2636
|
+
AddInstruction(unknown);
|
2637
|
+
environment()->Bind(i, unknown);
|
2710
2638
|
}
|
2711
2639
|
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2640
|
+
AddSimulate(osr_entry_id);
|
2641
|
+
AddInstruction(new HOsrEntry(osr_entry_id));
|
2642
|
+
current_block()->Goto(loop_predecessor);
|
2715
2643
|
loop_predecessor->SetJoinId(statement->EntryId());
|
2716
|
-
|
2644
|
+
set_current_block(loop_predecessor);
|
2717
2645
|
}
|
2718
2646
|
|
2719
2647
|
|
2720
2648
|
void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
2721
2649
|
ASSERT(current_block() != NULL);
|
2722
|
-
|
2650
|
+
PreProcessOsrEntry(stmt);
|
2651
|
+
HBasicBlock* loop_entry = CreateLoopHeaderBlock();
|
2652
|
+
current_block()->Goto(loop_entry, false);
|
2653
|
+
set_current_block(loop_entry);
|
2723
2654
|
|
2724
|
-
HSubgraph* body_graph = CreateLoopHeaderSubgraph(environment());
|
2725
2655
|
BreakAndContinueInfo break_info(stmt);
|
2726
2656
|
{ BreakAndContinueScope push(&break_info, this);
|
2727
|
-
|
2657
|
+
Visit(stmt->body());
|
2658
|
+
CHECK_BAILOUT;
|
2728
2659
|
}
|
2729
|
-
|
2730
|
-
|
2731
|
-
|
2732
|
-
|
2733
|
-
|
2734
|
-
|
2735
|
-
|
2736
|
-
|
2737
|
-
|
2738
|
-
|
2739
|
-
|
2740
|
-
|
2741
|
-
VISIT_FOR_CONTROL(stmt->cond(),
|
2742
|
-
go_back->entry_block(),
|
2743
|
-
exit->entry_block());
|
2744
|
-
go_back->entry_block()->SetJoinId(stmt->BackEdgeId());
|
2745
|
-
exit->entry_block()->SetJoinId(stmt->ExitId());
|
2746
|
-
}
|
2747
|
-
subgraph()->AppendDoWhile(stmt,
|
2748
|
-
body_graph->entry_block(),
|
2749
|
-
go_back->exit_block(),
|
2750
|
-
exit->exit_block(),
|
2751
|
-
break_info.break_block());
|
2660
|
+
HBasicBlock* body_exit =
|
2661
|
+
JoinContinue(stmt, current_block(), break_info.continue_block());
|
2662
|
+
HBasicBlock* loop_successor = NULL;
|
2663
|
+
if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) {
|
2664
|
+
set_current_block(body_exit);
|
2665
|
+
// The block for a true condition, the actual predecessor block of the
|
2666
|
+
// back edge.
|
2667
|
+
body_exit = graph()->CreateBasicBlock();
|
2668
|
+
loop_successor = graph()->CreateBasicBlock();
|
2669
|
+
VISIT_FOR_CONTROL(stmt->cond(), body_exit, loop_successor);
|
2670
|
+
body_exit->SetJoinId(stmt->BackEdgeId());
|
2671
|
+
loop_successor->SetJoinId(stmt->ExitId());
|
2752
2672
|
}
|
2673
|
+
HBasicBlock* loop_exit = CreateLoop(stmt,
|
2674
|
+
loop_entry,
|
2675
|
+
body_exit,
|
2676
|
+
loop_successor,
|
2677
|
+
break_info.break_block());
|
2678
|
+
set_current_block(loop_exit);
|
2753
2679
|
}
|
2754
2680
|
|
2755
2681
|
|
2756
2682
|
void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
|
2757
2683
|
ASSERT(current_block() != NULL);
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
2765
|
-
if (stmt->cond()->ToBooleanIsTrue()) {
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
2771
|
-
|
2772
|
-
SubgraphScope scope(this, cond_graph);
|
2773
|
-
VISIT_FOR_CONTROL(stmt->cond(),
|
2774
|
-
body_graph->entry_block(),
|
2775
|
-
exit_graph->entry_block());
|
2776
|
-
body_graph->entry_block()->SetJoinId(stmt->BodyId());
|
2777
|
-
exit_graph->entry_block()->SetJoinId(stmt->ExitId());
|
2778
|
-
}
|
2684
|
+
PreProcessOsrEntry(stmt);
|
2685
|
+
HBasicBlock* loop_entry = CreateLoopHeaderBlock();
|
2686
|
+
current_block()->Goto(loop_entry, false);
|
2687
|
+
set_current_block(loop_entry);
|
2688
|
+
|
2689
|
+
// If the condition is constant true, do not generate a branch.
|
2690
|
+
HBasicBlock* loop_successor = NULL;
|
2691
|
+
if (!stmt->cond()->ToBooleanIsTrue()) {
|
2692
|
+
HBasicBlock* body_entry = graph()->CreateBasicBlock();
|
2693
|
+
loop_successor = graph()->CreateBasicBlock();
|
2694
|
+
VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor);
|
2695
|
+
body_entry->SetJoinId(stmt->BodyId());
|
2696
|
+
loop_successor->SetJoinId(stmt->ExitId());
|
2697
|
+
set_current_block(body_entry);
|
2779
2698
|
}
|
2780
2699
|
|
2781
2700
|
BreakAndContinueInfo break_info(stmt);
|
2782
2701
|
{ BreakAndContinueScope push(&break_info, this);
|
2783
|
-
|
2702
|
+
Visit(stmt->body());
|
2703
|
+
CHECK_BAILOUT;
|
2784
2704
|
}
|
2785
|
-
|
2786
|
-
|
2787
|
-
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
2793
|
-
} else {
|
2794
|
-
// TODO(fschneider): Implement peeling for endless loops as well.
|
2795
|
-
subgraph()->AppendEndless(stmt,
|
2796
|
-
body_graph->entry_block(),
|
2797
|
-
body_graph->exit_block(),
|
2798
|
-
break_info.break_block());
|
2799
|
-
}
|
2800
|
-
}
|
2801
|
-
|
2802
|
-
|
2803
|
-
void HGraphBuilder::AppendPeeledWhile(IterationStatement* stmt,
|
2804
|
-
HBasicBlock* condition_entry,
|
2805
|
-
HBasicBlock* exit_block,
|
2806
|
-
HBasicBlock* body_exit,
|
2807
|
-
HBasicBlock* break_block) {
|
2808
|
-
HBasicBlock* loop_entry = NULL;
|
2809
|
-
HBasicBlock* loop_exit = NULL;
|
2810
|
-
if (FLAG_use_peeling && body_exit != NULL && stmt != peeled_statement_) {
|
2811
|
-
// Save the last peeled iteration statement to prevent infinite recursion.
|
2812
|
-
IterationStatement* outer_peeled_statement = peeled_statement_;
|
2813
|
-
peeled_statement_ = stmt;
|
2814
|
-
HSubgraph* loop = CreateGotoSubgraph(body_exit->last_environment());
|
2815
|
-
ADD_TO_SUBGRAPH(loop, stmt);
|
2816
|
-
peeled_statement_ = outer_peeled_statement;
|
2817
|
-
loop_entry = loop->entry_block();
|
2818
|
-
loop_exit = loop->exit_block();
|
2819
|
-
}
|
2820
|
-
subgraph()->AppendWhile(stmt,
|
2821
|
-
condition_entry,
|
2822
|
-
exit_block,
|
2823
|
-
body_exit,
|
2824
|
-
break_block,
|
2825
|
-
loop_entry,
|
2826
|
-
loop_exit);
|
2705
|
+
HBasicBlock* body_exit =
|
2706
|
+
JoinContinue(stmt, current_block(), break_info.continue_block());
|
2707
|
+
HBasicBlock* loop_exit = CreateLoop(stmt,
|
2708
|
+
loop_entry,
|
2709
|
+
body_exit,
|
2710
|
+
loop_successor,
|
2711
|
+
break_info.break_block());
|
2712
|
+
set_current_block(loop_exit);
|
2827
2713
|
}
|
2828
2714
|
|
2829
2715
|
|
2830
2716
|
void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
|
2831
|
-
|
2832
|
-
if (stmt->init() != NULL && peeled_statement_ != stmt) {
|
2717
|
+
if (stmt->init() != NULL) {
|
2833
2718
|
Visit(stmt->init());
|
2834
2719
|
CHECK_BAILOUT;
|
2835
2720
|
}
|
2836
2721
|
ASSERT(current_block() != NULL);
|
2837
|
-
|
2722
|
+
PreProcessOsrEntry(stmt);
|
2723
|
+
HBasicBlock* loop_entry = CreateLoopHeaderBlock();
|
2724
|
+
current_block()->Goto(loop_entry, false);
|
2725
|
+
set_current_block(loop_entry);
|
2838
2726
|
|
2839
|
-
|
2840
|
-
HSubgraph* body_graph = NULL;
|
2841
|
-
HSubgraph* exit_graph = NULL;
|
2727
|
+
HBasicBlock* loop_successor = NULL;
|
2842
2728
|
if (stmt->cond() != NULL) {
|
2843
|
-
|
2844
|
-
|
2845
|
-
|
2846
|
-
|
2847
|
-
|
2848
|
-
|
2849
|
-
body_graph->entry_block(),
|
2850
|
-
exit_graph->entry_block());
|
2851
|
-
body_graph->entry_block()->SetJoinId(stmt->BodyId());
|
2852
|
-
exit_graph->entry_block()->SetJoinId(stmt->ExitId());
|
2853
|
-
}
|
2854
|
-
} else {
|
2855
|
-
body_graph = CreateLoopHeaderSubgraph(environment());
|
2729
|
+
HBasicBlock* body_entry = graph()->CreateBasicBlock();
|
2730
|
+
loop_successor = graph()->CreateBasicBlock();
|
2731
|
+
VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor);
|
2732
|
+
body_entry->SetJoinId(stmt->BodyId());
|
2733
|
+
loop_successor->SetJoinId(stmt->ExitId());
|
2734
|
+
set_current_block(body_entry);
|
2856
2735
|
}
|
2736
|
+
|
2857
2737
|
BreakAndContinueInfo break_info(stmt);
|
2858
2738
|
{ BreakAndContinueScope push(&break_info, this);
|
2859
|
-
|
2739
|
+
Visit(stmt->body());
|
2740
|
+
CHECK_BAILOUT;
|
2860
2741
|
}
|
2742
|
+
HBasicBlock* body_exit =
|
2743
|
+
JoinContinue(stmt, current_block(), break_info.continue_block());
|
2861
2744
|
|
2862
|
-
|
2863
|
-
|
2864
|
-
|
2865
|
-
|
2866
|
-
|
2867
|
-
CreateGotoSubgraph(body_graph->exit_block()->last_environment());
|
2868
|
-
ADD_TO_SUBGRAPH(next_graph, stmt->next());
|
2869
|
-
body_graph->Append(NULL,
|
2870
|
-
next_graph->entry_block(),
|
2871
|
-
next_graph->exit_block(),
|
2872
|
-
NULL);
|
2873
|
-
next_graph->entry_block()->SetJoinId(stmt->ContinueId());
|
2745
|
+
if (stmt->next() != NULL && body_exit != NULL) {
|
2746
|
+
set_current_block(body_exit);
|
2747
|
+
Visit(stmt->next());
|
2748
|
+
CHECK_BAILOUT;
|
2749
|
+
body_exit = current_block();
|
2874
2750
|
}
|
2875
2751
|
|
2876
|
-
|
2877
|
-
|
2878
|
-
|
2879
|
-
|
2880
|
-
|
2881
|
-
|
2882
|
-
} else {
|
2883
|
-
subgraph()->AppendEndless(stmt,
|
2884
|
-
body_graph->entry_block(),
|
2885
|
-
body_graph->exit_block(),
|
2886
|
-
break_info.break_block());
|
2887
|
-
}
|
2752
|
+
HBasicBlock* loop_exit = CreateLoop(stmt,
|
2753
|
+
loop_entry,
|
2754
|
+
body_exit,
|
2755
|
+
loop_successor,
|
2756
|
+
break_info.break_block());
|
2757
|
+
set_current_block(loop_exit);
|
2888
2758
|
}
|
2889
2759
|
|
2890
2760
|
|
@@ -2908,9 +2778,33 @@ void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
|
|
2908
2778
|
}
|
2909
2779
|
|
2910
2780
|
|
2781
|
+
static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
|
2782
|
+
Code* unoptimized_code, FunctionLiteral* expr) {
|
2783
|
+
int start_position = expr->start_position();
|
2784
|
+
RelocIterator it(unoptimized_code);
|
2785
|
+
for (;!it.done(); it.next()) {
|
2786
|
+
RelocInfo* rinfo = it.rinfo();
|
2787
|
+
if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
|
2788
|
+
Object* obj = rinfo->target_object();
|
2789
|
+
if (obj->IsSharedFunctionInfo()) {
|
2790
|
+
SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
|
2791
|
+
if (shared->start_position() == start_position) {
|
2792
|
+
return Handle<SharedFunctionInfo>(shared);
|
2793
|
+
}
|
2794
|
+
}
|
2795
|
+
}
|
2796
|
+
|
2797
|
+
return Handle<SharedFunctionInfo>();
|
2798
|
+
}
|
2799
|
+
|
2800
|
+
|
2911
2801
|
void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
|
2912
2802
|
Handle<SharedFunctionInfo> shared_info =
|
2913
|
-
|
2803
|
+
SearchSharedFunctionInfo(info()->shared_info()->code(),
|
2804
|
+
expr);
|
2805
|
+
if (shared_info.is_null()) {
|
2806
|
+
shared_info = Compiler::BuildFunctionInfo(expr, info()->script());
|
2807
|
+
}
|
2914
2808
|
CHECK_BAILOUT;
|
2915
2809
|
HFunctionLiteral* instr =
|
2916
2810
|
new HFunctionLiteral(shared_info, expr->pretenure());
|
@@ -2925,48 +2819,46 @@ void HGraphBuilder::VisitSharedFunctionInfoLiteral(
|
|
2925
2819
|
|
2926
2820
|
|
2927
2821
|
void HGraphBuilder::VisitConditional(Conditional* expr) {
|
2928
|
-
|
2929
|
-
|
2930
|
-
VISIT_FOR_CONTROL(expr->condition(),
|
2931
|
-
|
2932
|
-
|
2933
|
-
|
2934
|
-
|
2935
|
-
|
2822
|
+
HBasicBlock* cond_true = graph()->CreateBasicBlock();
|
2823
|
+
HBasicBlock* cond_false = graph()->CreateBasicBlock();
|
2824
|
+
VISIT_FOR_CONTROL(expr->condition(), cond_true, cond_false);
|
2825
|
+
cond_true->SetJoinId(expr->ThenId());
|
2826
|
+
cond_false->SetJoinId(expr->ElseId());
|
2827
|
+
|
2828
|
+
// Visit the true and false subexpressions in the same AST context as the
|
2829
|
+
// whole expression.
|
2830
|
+
set_current_block(cond_true);
|
2831
|
+
Visit(expr->then_expression());
|
2832
|
+
CHECK_BAILOUT;
|
2833
|
+
HBasicBlock* other = current_block();
|
2936
2834
|
|
2937
|
-
|
2938
|
-
|
2835
|
+
set_current_block(cond_false);
|
2836
|
+
Visit(expr->else_expression());
|
2837
|
+
CHECK_BAILOUT;
|
2939
2838
|
|
2940
|
-
|
2941
|
-
|
2942
|
-
|
2943
|
-
|
2839
|
+
if (!ast_context()->IsTest()) {
|
2840
|
+
HBasicBlock* join = CreateJoin(other, current_block(), expr->id());
|
2841
|
+
set_current_block(join);
|
2842
|
+
if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
|
2843
|
+
}
|
2944
2844
|
}
|
2945
2845
|
|
2946
2846
|
|
2947
|
-
|
2948
|
-
|
2949
|
-
|
2950
|
-
|
2951
|
-
BAILOUT("global this reference");
|
2847
|
+
HGraphBuilder::GlobalPropertyAccess HGraphBuilder::LookupGlobalProperty(
|
2848
|
+
Variable* var, LookupResult* lookup, bool is_store) {
|
2849
|
+
if (var->is_this() || !info()->has_global_object()) {
|
2850
|
+
return kUseGeneric;
|
2952
2851
|
}
|
2953
|
-
|
2954
|
-
BAILOUT("no global object to optimize VariableProxy");
|
2955
|
-
}
|
2956
|
-
Handle<GlobalObject> global(graph()->info()->global_object());
|
2852
|
+
Handle<GlobalObject> global(info()->global_object());
|
2957
2853
|
global->Lookup(*var->name(), lookup);
|
2958
|
-
if (!lookup->IsProperty()
|
2959
|
-
|
2960
|
-
|
2961
|
-
|
2962
|
-
|
2963
|
-
}
|
2964
|
-
if (is_store && lookup->IsReadOnly()) {
|
2965
|
-
BAILOUT("read-only global variable");
|
2966
|
-
}
|
2967
|
-
if (lookup->holder() != *global) {
|
2968
|
-
BAILOUT("global property on prototype of global object");
|
2854
|
+
if (!lookup->IsProperty() ||
|
2855
|
+
lookup->type() != NORMAL ||
|
2856
|
+
(is_store && lookup->IsReadOnly()) ||
|
2857
|
+
lookup->holder() != *global) {
|
2858
|
+
return kUseGeneric;
|
2969
2859
|
}
|
2860
|
+
|
2861
|
+
return kUseCell;
|
2970
2862
|
}
|
2971
2863
|
|
2972
2864
|
|
@@ -2974,7 +2866,7 @@ HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) {
|
|
2974
2866
|
ASSERT(var->IsContextSlot());
|
2975
2867
|
HInstruction* context = new HContext;
|
2976
2868
|
AddInstruction(context);
|
2977
|
-
int length =
|
2869
|
+
int length = info()->scope()->ContextChainLength(var->scope());
|
2978
2870
|
while (length-- > 0) {
|
2979
2871
|
context = new HOuterContext(context);
|
2980
2872
|
AddInstruction(context);
|
@@ -3002,19 +2894,33 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
|
3002
2894
|
ast_context()->ReturnInstruction(instr, expr->id());
|
3003
2895
|
} else if (variable->is_global()) {
|
3004
2896
|
LookupResult lookup;
|
3005
|
-
|
3006
|
-
CHECK_BAILOUT;
|
2897
|
+
GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false);
|
3007
2898
|
|
3008
|
-
|
3009
|
-
|
3010
|
-
|
3011
|
-
|
3012
|
-
|
2899
|
+
if (type == kUseCell &&
|
2900
|
+
info()->global_object()->IsAccessCheckNeeded()) {
|
2901
|
+
type = kUseGeneric;
|
2902
|
+
}
|
2903
|
+
|
2904
|
+
if (type == kUseCell) {
|
2905
|
+
Handle<GlobalObject> global(info()->global_object());
|
2906
|
+
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
|
2907
|
+
bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
|
2908
|
+
HLoadGlobalCell* instr = new HLoadGlobalCell(cell, check_hole);
|
2909
|
+
ast_context()->ReturnInstruction(instr, expr->id());
|
2910
|
+
} else {
|
2911
|
+
HContext* context = new HContext;
|
2912
|
+
AddInstruction(context);
|
2913
|
+
HGlobalObject* global_object = new HGlobalObject(context);
|
2914
|
+
AddInstruction(global_object);
|
2915
|
+
HLoadGlobalGeneric* instr =
|
2916
|
+
new HLoadGlobalGeneric(context,
|
2917
|
+
global_object,
|
2918
|
+
variable->name(),
|
2919
|
+
ast_context()->is_for_typeof());
|
2920
|
+
instr->set_position(expr->position());
|
2921
|
+
ASSERT(instr->HasSideEffects());
|
2922
|
+
ast_context()->ReturnInstruction(instr, expr->id());
|
3013
2923
|
}
|
3014
|
-
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
|
3015
|
-
bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
|
3016
|
-
HLoadGlobal* instr = new HLoadGlobal(cell, check_hole);
|
3017
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
3018
2924
|
} else {
|
3019
2925
|
BAILOUT("reference to a variable which requires dynamic lookup");
|
3020
2926
|
}
|
@@ -3042,7 +2948,8 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|
3042
2948
|
expr->constant_properties(),
|
3043
2949
|
expr->fast_elements(),
|
3044
2950
|
expr->literal_index(),
|
3045
|
-
expr->depth()
|
2951
|
+
expr->depth(),
|
2952
|
+
expr->has_function()));
|
3046
2953
|
// The object is expected in the bailout environment during computation
|
3047
2954
|
// of the property values and is the value of the entire expression.
|
3048
2955
|
PushAndAdd(literal);
|
@@ -3083,7 +2990,19 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|
3083
2990
|
default: UNREACHABLE();
|
3084
2991
|
}
|
3085
2992
|
}
|
3086
|
-
|
2993
|
+
|
2994
|
+
if (expr->has_function()) {
|
2995
|
+
// Return the result of the transformation to fast properties
|
2996
|
+
// instead of the original since this operation changes the map
|
2997
|
+
// of the object. This makes sure that the original object won't
|
2998
|
+
// be used by other optimized code before it is transformed
|
2999
|
+
// (e.g. because of code motion).
|
3000
|
+
HToFastProperties* result = new HToFastProperties(Pop());
|
3001
|
+
AddInstruction(result);
|
3002
|
+
ast_context()->ReturnValue(result);
|
3003
|
+
} else {
|
3004
|
+
ast_context()->ReturnValue(Pop());
|
3005
|
+
}
|
3087
3006
|
}
|
3088
3007
|
|
3089
3008
|
|
@@ -3131,55 +3050,6 @@ void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
|
|
3131
3050
|
}
|
3132
3051
|
|
3133
3052
|
|
3134
|
-
HBasicBlock* HGraphBuilder::BuildTypeSwitch(HValue* receiver,
|
3135
|
-
ZoneMapList* maps,
|
3136
|
-
ZoneList<HSubgraph*>* body_graphs,
|
3137
|
-
HSubgraph* default_graph,
|
3138
|
-
int join_id) {
|
3139
|
-
ASSERT(maps->length() == body_graphs->length());
|
3140
|
-
HBasicBlock* join_block = graph()->CreateBasicBlock();
|
3141
|
-
AddInstruction(new HCheckNonSmi(receiver));
|
3142
|
-
|
3143
|
-
for (int i = 0; i < maps->length(); ++i) {
|
3144
|
-
// Build the branches, connect all the target subgraphs to the join
|
3145
|
-
// block. Use the default as a target of the last branch.
|
3146
|
-
HSubgraph* if_true = body_graphs->at(i);
|
3147
|
-
HSubgraph* if_false = (i == maps->length() - 1)
|
3148
|
-
? default_graph
|
3149
|
-
: CreateBranchSubgraph(environment());
|
3150
|
-
HCompareMap* compare =
|
3151
|
-
new HCompareMap(receiver,
|
3152
|
-
maps->at(i),
|
3153
|
-
if_true->entry_block(),
|
3154
|
-
if_false->entry_block());
|
3155
|
-
current_block()->Finish(compare);
|
3156
|
-
|
3157
|
-
if (if_true->exit_block() != NULL) {
|
3158
|
-
// In an effect context the value of the type switch is not needed.
|
3159
|
-
// There is no need to merge it at the join block only to discard it.
|
3160
|
-
if (ast_context()->IsEffect()) {
|
3161
|
-
if_true->exit_block()->last_environment()->Drop(1);
|
3162
|
-
}
|
3163
|
-
if_true->exit_block()->Goto(join_block);
|
3164
|
-
}
|
3165
|
-
|
3166
|
-
set_current_block(if_false->exit_block());
|
3167
|
-
}
|
3168
|
-
|
3169
|
-
// Connect the default if necessary.
|
3170
|
-
if (current_block() != NULL) {
|
3171
|
-
if (ast_context()->IsEffect()) {
|
3172
|
-
environment()->Drop(1);
|
3173
|
-
}
|
3174
|
-
current_block()->Goto(join_block);
|
3175
|
-
}
|
3176
|
-
|
3177
|
-
if (join_block->predecessors()->is_empty()) return NULL;
|
3178
|
-
join_block->SetJoinId(join_id);
|
3179
|
-
return join_block;
|
3180
|
-
}
|
3181
|
-
|
3182
|
-
|
3183
3053
|
// Sets the lookup result and returns true if the store can be inlined.
|
3184
3054
|
static bool ComputeStoredField(Handle<Map> type,
|
3185
3055
|
Handle<String> name,
|
@@ -3275,66 +3145,73 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
|
|
3275
3145
|
HValue* value,
|
3276
3146
|
ZoneMapList* types,
|
3277
3147
|
Handle<String> name) {
|
3278
|
-
|
3279
|
-
|
3280
|
-
|
3281
|
-
|
3282
|
-
|
3283
|
-
|
3284
|
-
//
|
3285
|
-
// TODO(ager): We should recognize when the prototype chains for
|
3286
|
-
// different maps are identical. In that case we can avoid
|
3287
|
-
// repeatedly generating the same prototype map checks.
|
3288
|
-
for (int i = 0; i < number_of_types; ++i) {
|
3148
|
+
// TODO(ager): We should recognize when the prototype chains for different
|
3149
|
+
// maps are identical. In that case we can avoid repeatedly generating the
|
3150
|
+
// same prototype map checks.
|
3151
|
+
int count = 0;
|
3152
|
+
HBasicBlock* join = NULL;
|
3153
|
+
for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) {
|
3289
3154
|
Handle<Map> map = types->at(i);
|
3290
3155
|
LookupResult lookup;
|
3291
3156
|
if (ComputeStoredField(map, name, &lookup)) {
|
3292
|
-
|
3293
|
-
|
3157
|
+
if (count == 0) {
|
3158
|
+
AddInstruction(new HCheckNonSmi(object)); // Only needed once.
|
3159
|
+
join = graph()->CreateBasicBlock();
|
3160
|
+
}
|
3161
|
+
++count;
|
3162
|
+
HBasicBlock* if_true = graph()->CreateBasicBlock();
|
3163
|
+
HBasicBlock* if_false = graph()->CreateBasicBlock();
|
3164
|
+
HCompareMap* compare = new HCompareMap(object, map, if_true, if_false);
|
3165
|
+
current_block()->Finish(compare);
|
3166
|
+
|
3167
|
+
set_current_block(if_true);
|
3294
3168
|
HInstruction* instr =
|
3295
3169
|
BuildStoreNamedField(object, name, value, map, &lookup, false);
|
3296
|
-
Push(value);
|
3297
3170
|
instr->set_position(expr->position());
|
3171
|
+
// Goto will add the HSimulate for the store.
|
3298
3172
|
AddInstruction(instr);
|
3299
|
-
|
3300
|
-
|
3301
|
-
|
3302
|
-
|
3173
|
+
if (!ast_context()->IsEffect()) Push(value);
|
3174
|
+
current_block()->Goto(join);
|
3175
|
+
|
3176
|
+
set_current_block(if_false);
|
3303
3177
|
}
|
3304
3178
|
}
|
3305
3179
|
|
3306
|
-
//
|
3307
|
-
//
|
3308
|
-
|
3180
|
+
// Finish up. Unconditionally deoptimize if we've handled all the maps we
|
3181
|
+
// know about and do not want to handle ones we've never seen. Otherwise
|
3182
|
+
// use a generic IC.
|
3183
|
+
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
|
3184
|
+
current_block()->FinishExitWithDeoptimization();
|
3185
|
+
} else {
|
3309
3186
|
HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
|
3310
|
-
Push(value);
|
3311
3187
|
instr->set_position(expr->position());
|
3312
3188
|
AddInstruction(instr);
|
3313
|
-
if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
|
3314
|
-
ast_context()->ReturnValue(Pop());
|
3315
|
-
} else {
|
3316
|
-
// Build subgraph for generic store through IC.
|
3317
|
-
HSubgraph* default_graph = CreateBranchSubgraph(environment());
|
3318
|
-
{ SubgraphScope scope(this, default_graph);
|
3319
|
-
if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
|
3320
|
-
default_graph->FinishExit(new HDeoptimize());
|
3321
|
-
} else {
|
3322
|
-
HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
|
3323
|
-
Push(value);
|
3324
|
-
instr->set_position(expr->position());
|
3325
|
-
AddInstruction(instr);
|
3326
|
-
}
|
3327
|
-
}
|
3328
3189
|
|
3329
|
-
|
3330
|
-
|
3331
|
-
|
3332
|
-
|
3333
|
-
|
3334
|
-
|
3335
|
-
|
3190
|
+
if (join != NULL) {
|
3191
|
+
if (!ast_context()->IsEffect()) Push(value);
|
3192
|
+
current_block()->Goto(join);
|
3193
|
+
} else {
|
3194
|
+
// The HSimulate for the store should not see the stored value in
|
3195
|
+
// effect contexts (it is not materialized at expr->id() in the
|
3196
|
+
// unoptimized code).
|
3197
|
+
if (instr->HasSideEffects()) {
|
3198
|
+
if (ast_context()->IsEffect()) {
|
3199
|
+
AddSimulate(expr->id());
|
3200
|
+
} else {
|
3201
|
+
Push(value);
|
3202
|
+
AddSimulate(expr->id());
|
3203
|
+
Drop(1);
|
3204
|
+
}
|
3205
|
+
}
|
3206
|
+
ast_context()->ReturnValue(value);
|
3207
|
+
return;
|
3336
3208
|
}
|
3337
3209
|
}
|
3210
|
+
|
3211
|
+
ASSERT(join != NULL);
|
3212
|
+
join->SetJoinId(expr->id());
|
3213
|
+
set_current_block(join);
|
3214
|
+
if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
|
3338
3215
|
}
|
3339
3216
|
|
3340
3217
|
|
@@ -3381,11 +3258,14 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
|
|
3381
3258
|
|
3382
3259
|
if (expr->IsMonomorphic()) {
|
3383
3260
|
Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
|
3384
|
-
// An object has either fast elements or
|
3385
|
-
// both. Pixel array maps that are assigned to pixel array elements
|
3386
|
-
// always created with the fast elements flag cleared.
|
3387
|
-
if (receiver_type->
|
3388
|
-
instr =
|
3261
|
+
// An object has either fast elements or external array elements, but
|
3262
|
+
// never both. Pixel array maps that are assigned to pixel array elements
|
3263
|
+
// are always created with the fast elements flag cleared.
|
3264
|
+
if (receiver_type->has_external_array_elements()) {
|
3265
|
+
instr = BuildStoreKeyedSpecializedArrayElement(object,
|
3266
|
+
key,
|
3267
|
+
value,
|
3268
|
+
expr);
|
3389
3269
|
} else if (receiver_type->has_fast_elements()) {
|
3390
3270
|
instr = BuildStoreKeyedFastElement(object, key, value, expr);
|
3391
3271
|
}
|
@@ -3411,16 +3291,18 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
|
|
3411
3291
|
int position,
|
3412
3292
|
int ast_id) {
|
3413
3293
|
LookupResult lookup;
|
3414
|
-
|
3415
|
-
|
3416
|
-
|
3417
|
-
|
3418
|
-
|
3419
|
-
|
3420
|
-
|
3421
|
-
|
3422
|
-
|
3423
|
-
|
3294
|
+
GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
|
3295
|
+
if (type == kUseCell) {
|
3296
|
+
bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
|
3297
|
+
Handle<GlobalObject> global(info()->global_object());
|
3298
|
+
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
|
3299
|
+
HInstruction* instr = new HStoreGlobal(value, cell, check_hole);
|
3300
|
+
instr->set_position(position);
|
3301
|
+
AddInstruction(instr);
|
3302
|
+
if (instr->HasSideEffects()) AddSimulate(ast_id);
|
3303
|
+
} else {
|
3304
|
+
BAILOUT("global store only supported for cells");
|
3305
|
+
}
|
3424
3306
|
}
|
3425
3307
|
|
3426
3308
|
|
@@ -3604,71 +3486,8 @@ void HGraphBuilder::VisitThrow(Throw* expr) {
|
|
3604
3486
|
instr->set_position(expr->position());
|
3605
3487
|
AddInstruction(instr);
|
3606
3488
|
AddSimulate(expr->id());
|
3607
|
-
|
3608
|
-
|
3609
|
-
|
3610
|
-
|
3611
|
-
void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
|
3612
|
-
HValue* object,
|
3613
|
-
ZoneMapList* types,
|
3614
|
-
Handle<String> name) {
|
3615
|
-
int number_of_types = Min(types->length(), kMaxLoadPolymorphism);
|
3616
|
-
ZoneMapList maps(number_of_types);
|
3617
|
-
ZoneList<HSubgraph*> subgraphs(number_of_types);
|
3618
|
-
bool needs_generic = (types->length() > kMaxLoadPolymorphism);
|
3619
|
-
|
3620
|
-
// Build subgraphs for each of the specific maps.
|
3621
|
-
//
|
3622
|
-
// TODO(ager): We should recognize when the prototype chains for
|
3623
|
-
// different maps are identical. In that case we can avoid
|
3624
|
-
// repeatedly generating the same prototype map checks.
|
3625
|
-
for (int i = 0; i < number_of_types; ++i) {
|
3626
|
-
Handle<Map> map = types->at(i);
|
3627
|
-
LookupResult lookup;
|
3628
|
-
map->LookupInDescriptors(NULL, *name, &lookup);
|
3629
|
-
if (lookup.IsProperty() && lookup.type() == FIELD) {
|
3630
|
-
HSubgraph* subgraph = CreateBranchSubgraph(environment());
|
3631
|
-
SubgraphScope scope(this, subgraph);
|
3632
|
-
HLoadNamedField* instr =
|
3633
|
-
BuildLoadNamedField(object, expr, map, &lookup, false);
|
3634
|
-
instr->set_position(expr->position());
|
3635
|
-
instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads.
|
3636
|
-
PushAndAdd(instr);
|
3637
|
-
maps.Add(map);
|
3638
|
-
subgraphs.Add(subgraph);
|
3639
|
-
} else {
|
3640
|
-
needs_generic = true;
|
3641
|
-
}
|
3642
|
-
}
|
3643
|
-
|
3644
|
-
// If none of the properties were named fields we generate a
|
3645
|
-
// generic load.
|
3646
|
-
if (maps.length() == 0) {
|
3647
|
-
HInstruction* instr = BuildLoadNamedGeneric(object, expr);
|
3648
|
-
instr->set_position(expr->position());
|
3649
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
3650
|
-
} else {
|
3651
|
-
// Build subgraph for generic load through IC.
|
3652
|
-
HSubgraph* default_graph = CreateBranchSubgraph(environment());
|
3653
|
-
{ SubgraphScope scope(this, default_graph);
|
3654
|
-
if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
|
3655
|
-
default_graph->FinishExit(new HDeoptimize());
|
3656
|
-
} else {
|
3657
|
-
HInstruction* instr = BuildLoadNamedGeneric(object, expr);
|
3658
|
-
instr->set_position(expr->position());
|
3659
|
-
PushAndAdd(instr);
|
3660
|
-
}
|
3661
|
-
}
|
3662
|
-
|
3663
|
-
HBasicBlock* new_exit_block =
|
3664
|
-
BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id());
|
3665
|
-
set_current_block(new_exit_block);
|
3666
|
-
// In an effect context, we did not materialized the value in the
|
3667
|
-
// predecessor environments so there's no need to handle it here.
|
3668
|
-
if (current_block() != NULL && !ast_context()->IsEffect()) {
|
3669
|
-
ast_context()->ReturnValue(Pop());
|
3670
|
-
}
|
3671
|
-
}
|
3489
|
+
current_block()->FinishExit(new HAbnormalExit);
|
3490
|
+
set_current_block(NULL);
|
3672
3491
|
}
|
3673
3492
|
|
3674
3493
|
|
@@ -3761,25 +3580,28 @@ HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
|
|
3761
3580
|
}
|
3762
3581
|
|
3763
3582
|
|
3764
|
-
HInstruction* HGraphBuilder::
|
3765
|
-
|
3766
|
-
|
3583
|
+
HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement(
|
3584
|
+
HValue* object,
|
3585
|
+
HValue* key,
|
3586
|
+
Property* expr) {
|
3767
3587
|
ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
|
3768
3588
|
AddInstruction(new HCheckNonSmi(object));
|
3769
3589
|
Handle<Map> map = expr->GetMonomorphicReceiverType();
|
3770
3590
|
ASSERT(!map->has_fast_elements());
|
3771
|
-
ASSERT(map->
|
3591
|
+
ASSERT(map->has_external_array_elements());
|
3772
3592
|
AddInstruction(new HCheckMap(object, map));
|
3773
3593
|
HLoadElements* elements = new HLoadElements(object);
|
3774
3594
|
AddInstruction(elements);
|
3775
|
-
HInstruction* length = new
|
3595
|
+
HInstruction* length = new HExternalArrayLength(elements);
|
3776
3596
|
AddInstruction(length);
|
3777
3597
|
AddInstruction(new HBoundsCheck(key, length));
|
3778
|
-
|
3779
|
-
new
|
3598
|
+
HLoadExternalArrayPointer* external_elements =
|
3599
|
+
new HLoadExternalArrayPointer(elements);
|
3780
3600
|
AddInstruction(external_elements);
|
3781
|
-
|
3782
|
-
new
|
3601
|
+
HLoadKeyedSpecializedArrayElement* pixel_array_value =
|
3602
|
+
new HLoadKeyedSpecializedArrayElement(external_elements,
|
3603
|
+
key,
|
3604
|
+
expr->GetExternalArrayType());
|
3783
3605
|
return pixel_array_value;
|
3784
3606
|
}
|
3785
3607
|
|
@@ -3803,7 +3625,8 @@ HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
|
|
3803
3625
|
ASSERT(map->has_fast_elements());
|
3804
3626
|
AddInstruction(new HCheckMap(object, map));
|
3805
3627
|
HInstruction* elements = AddInstruction(new HLoadElements(object));
|
3806
|
-
AddInstruction(new HCheckMap(elements,
|
3628
|
+
AddInstruction(new HCheckMap(elements,
|
3629
|
+
isolate()->factory()->fixed_array_map()));
|
3807
3630
|
bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
|
3808
3631
|
HInstruction* length = NULL;
|
3809
3632
|
if (is_array) {
|
@@ -3816,25 +3639,29 @@ HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
|
|
3816
3639
|
}
|
3817
3640
|
|
3818
3641
|
|
3819
|
-
HInstruction* HGraphBuilder::
|
3642
|
+
HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement(
|
3820
3643
|
HValue* object,
|
3821
3644
|
HValue* key,
|
3822
3645
|
HValue* val,
|
3823
|
-
|
3646
|
+
Assignment* expr) {
|
3824
3647
|
ASSERT(expr->IsMonomorphic());
|
3825
3648
|
AddInstruction(new HCheckNonSmi(object));
|
3826
3649
|
Handle<Map> map = expr->GetMonomorphicReceiverType();
|
3827
3650
|
ASSERT(!map->has_fast_elements());
|
3828
|
-
ASSERT(map->
|
3651
|
+
ASSERT(map->has_external_array_elements());
|
3829
3652
|
AddInstruction(new HCheckMap(object, map));
|
3830
3653
|
HLoadElements* elements = new HLoadElements(object);
|
3831
3654
|
AddInstruction(elements);
|
3832
|
-
HInstruction* length = AddInstruction(new
|
3655
|
+
HInstruction* length = AddInstruction(new HExternalArrayLength(elements));
|
3833
3656
|
AddInstruction(new HBoundsCheck(key, length));
|
3834
|
-
|
3835
|
-
new
|
3657
|
+
HLoadExternalArrayPointer* external_elements =
|
3658
|
+
new HLoadExternalArrayPointer(elements);
|
3836
3659
|
AddInstruction(external_elements);
|
3837
|
-
return new
|
3660
|
+
return new HStoreKeyedSpecializedArrayElement(
|
3661
|
+
external_elements,
|
3662
|
+
key,
|
3663
|
+
val,
|
3664
|
+
expr->GetExternalArrayType());
|
3838
3665
|
}
|
3839
3666
|
|
3840
3667
|
|
@@ -3853,9 +3680,11 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
|
|
3853
3680
|
HInstruction* elements = AddInstruction(new HArgumentsElements);
|
3854
3681
|
result = new HArgumentsLength(elements);
|
3855
3682
|
} else {
|
3683
|
+
Push(graph()->GetArgumentsObject());
|
3856
3684
|
VisitForValue(expr->key());
|
3857
3685
|
if (HasStackOverflow()) return false;
|
3858
3686
|
HValue* key = Pop();
|
3687
|
+
Drop(1); // Arguments object.
|
3859
3688
|
HInstruction* elements = AddInstruction(new HArgumentsElements);
|
3860
3689
|
HInstruction* length = AddInstruction(new HArgumentsLength(elements));
|
3861
3690
|
AddInstruction(new HBoundsCheck(key, length));
|
@@ -3888,6 +3717,13 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
|
3888
3717
|
FIRST_STRING_TYPE,
|
3889
3718
|
LAST_STRING_TYPE));
|
3890
3719
|
instr = new HStringLength(string);
|
3720
|
+
} else if (expr->IsStringAccess()) {
|
3721
|
+
VISIT_FOR_VALUE(expr->key());
|
3722
|
+
HValue* index = Pop();
|
3723
|
+
HValue* string = Pop();
|
3724
|
+
HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
|
3725
|
+
AddInstruction(char_code);
|
3726
|
+
instr = new HStringCharFromCode(char_code);
|
3891
3727
|
|
3892
3728
|
} else if (expr->IsFunctionPrototype()) {
|
3893
3729
|
HValue* function = Pop();
|
@@ -3902,9 +3738,8 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
|
3902
3738
|
if (expr->IsMonomorphic()) {
|
3903
3739
|
instr = BuildLoadNamed(obj, expr, types->first(), name);
|
3904
3740
|
} else if (types != NULL && types->length() > 1) {
|
3905
|
-
|
3906
|
-
|
3907
|
-
|
3741
|
+
AddInstruction(new HCheckNonSmi(obj));
|
3742
|
+
instr = new HLoadNamedFieldPolymorphic(obj, types, name);
|
3908
3743
|
} else {
|
3909
3744
|
instr = BuildLoadNamedGeneric(obj, expr);
|
3910
3745
|
}
|
@@ -3920,8 +3755,8 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
|
3920
3755
|
// An object has either fast elements or pixel array elements, but never
|
3921
3756
|
// both. Pixel array maps that are assigned to pixel array elements are
|
3922
3757
|
// always created with the fast elements flag cleared.
|
3923
|
-
if (receiver_type->
|
3924
|
-
instr =
|
3758
|
+
if (receiver_type->has_external_array_elements()) {
|
3759
|
+
instr = BuildLoadKeyedSpecializedArrayElement(obj, key, expr);
|
3925
3760
|
} else if (receiver_type->has_fast_elements()) {
|
3926
3761
|
instr = BuildLoadKeyedFastElement(obj, key, expr);
|
3927
3762
|
}
|
@@ -3958,22 +3793,26 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
|
|
3958
3793
|
HValue* receiver,
|
3959
3794
|
ZoneMapList* types,
|
3960
3795
|
Handle<String> name) {
|
3961
|
-
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
|
3962
|
-
int number_of_types = Min(types->length(), kMaxCallPolymorphism);
|
3963
|
-
ZoneMapList maps(number_of_types);
|
3964
|
-
ZoneList<HSubgraph*> subgraphs(number_of_types);
|
3965
|
-
bool needs_generic = (types->length() > kMaxCallPolymorphism);
|
3966
|
-
|
3967
|
-
// Build subgraphs for each of the specific maps.
|
3968
|
-
//
|
3969
3796
|
// TODO(ager): We should recognize when the prototype chains for different
|
3970
3797
|
// maps are identical. In that case we can avoid repeatedly generating the
|
3971
3798
|
// same prototype map checks.
|
3972
|
-
|
3799
|
+
int argument_count = expr->arguments()->length() + 1; // Includes receiver.
|
3800
|
+
int count = 0;
|
3801
|
+
HBasicBlock* join = NULL;
|
3802
|
+
for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) {
|
3973
3803
|
Handle<Map> map = types->at(i);
|
3974
3804
|
if (expr->ComputeTarget(map, name)) {
|
3975
|
-
|
3976
|
-
|
3805
|
+
if (count == 0) {
|
3806
|
+
AddInstruction(new HCheckNonSmi(receiver)); // Only needed once.
|
3807
|
+
join = graph()->CreateBasicBlock();
|
3808
|
+
}
|
3809
|
+
++count;
|
3810
|
+
HBasicBlock* if_true = graph()->CreateBasicBlock();
|
3811
|
+
HBasicBlock* if_false = graph()->CreateBasicBlock();
|
3812
|
+
HCompareMap* compare = new HCompareMap(receiver, map, if_true, if_false);
|
3813
|
+
current_block()->Finish(compare);
|
3814
|
+
|
3815
|
+
set_current_block(if_true);
|
3977
3816
|
AddCheckConstantFunction(expr, receiver, map, false);
|
3978
3817
|
if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
|
3979
3818
|
PrintF("Trying to inline the polymorphic call to %s\n",
|
@@ -3984,63 +3823,69 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
|
|
3984
3823
|
// during hydrogen processing.
|
3985
3824
|
CHECK_BAILOUT;
|
3986
3825
|
HCallConstantFunction* call =
|
3987
|
-
|
3826
|
+
new HCallConstantFunction(expr->target(), argument_count);
|
3988
3827
|
call->set_position(expr->position());
|
3989
3828
|
PreProcessCall(call);
|
3990
|
-
|
3829
|
+
AddInstruction(call);
|
3830
|
+
if (!ast_context()->IsEffect()) Push(call);
|
3991
3831
|
}
|
3992
|
-
|
3993
|
-
|
3994
|
-
|
3995
|
-
needs_generic = true;
|
3832
|
+
|
3833
|
+
if (current_block() != NULL) current_block()->Goto(join);
|
3834
|
+
set_current_block(if_false);
|
3996
3835
|
}
|
3997
3836
|
}
|
3998
3837
|
|
3999
|
-
//
|
4000
|
-
//
|
4001
|
-
|
3838
|
+
// Finish up. Unconditionally deoptimize if we've handled all the maps we
|
3839
|
+
// know about and do not want to handle ones we've never seen. Otherwise
|
3840
|
+
// use a generic IC.
|
3841
|
+
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
|
3842
|
+
current_block()->FinishExitWithDeoptimization();
|
3843
|
+
} else {
|
4002
3844
|
HContext* context = new HContext;
|
4003
3845
|
AddInstruction(context);
|
4004
3846
|
HCallNamed* call = new HCallNamed(context, name, argument_count);
|
4005
3847
|
call->set_position(expr->position());
|
4006
3848
|
PreProcessCall(call);
|
4007
|
-
ast_context()->ReturnInstruction(call, expr->id());
|
4008
|
-
} else {
|
4009
|
-
// Build subgraph for generic call through IC.
|
4010
|
-
HSubgraph* default_graph = CreateBranchSubgraph(environment());
|
4011
|
-
{ SubgraphScope scope(this, default_graph);
|
4012
|
-
if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
|
4013
|
-
default_graph->FinishExit(new HDeoptimize());
|
4014
|
-
} else {
|
4015
|
-
HContext* context = new HContext;
|
4016
|
-
AddInstruction(context);
|
4017
|
-
HCallNamed* call = new HCallNamed(context, name, argument_count);
|
4018
|
-
call->set_position(expr->position());
|
4019
|
-
PreProcessCall(call);
|
4020
|
-
PushAndAdd(call);
|
4021
|
-
}
|
4022
|
-
}
|
4023
3849
|
|
4024
|
-
|
4025
|
-
|
4026
|
-
|
4027
|
-
|
4028
|
-
|
4029
|
-
|
4030
|
-
|
3850
|
+
if (join != NULL) {
|
3851
|
+
AddInstruction(call);
|
3852
|
+
if (!ast_context()->IsEffect()) Push(call);
|
3853
|
+
current_block()->Goto(join);
|
3854
|
+
} else {
|
3855
|
+
ast_context()->ReturnInstruction(call, expr->id());
|
3856
|
+
return;
|
4031
3857
|
}
|
4032
3858
|
}
|
3859
|
+
|
3860
|
+
// We assume that control flow is always live after an expression. So
|
3861
|
+
// even without predecessors to the join block, we set it as the exit
|
3862
|
+
// block and continue by adding instructions there.
|
3863
|
+
ASSERT(join != NULL);
|
3864
|
+
set_current_block(join);
|
3865
|
+
if (join->HasPredecessor()) {
|
3866
|
+
join->SetJoinId(expr->id());
|
3867
|
+
if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
|
3868
|
+
}
|
4033
3869
|
}
|
4034
3870
|
|
4035
3871
|
|
4036
|
-
void HGraphBuilder::TraceInline(Handle<JSFunction> target,
|
4037
|
-
|
4038
|
-
|
4039
|
-
|
4040
|
-
|
4041
|
-
|
4042
|
-
|
4043
|
-
|
3872
|
+
void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) {
|
3873
|
+
if (FLAG_trace_inlining) {
|
3874
|
+
if (reason == NULL) {
|
3875
|
+
// We are currently in the context of inlined function thus we have
|
3876
|
+
// to go to an outer FunctionState to get caller.
|
3877
|
+
SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
|
3878
|
+
SmartPointer<char> caller =
|
3879
|
+
function_state()->outer()->compilation_info()->function()->
|
3880
|
+
debug_name()->ToCString();
|
3881
|
+
PrintF("Inlined %s called from %s.\n", *callee, *caller);
|
3882
|
+
} else {
|
3883
|
+
SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
|
3884
|
+
SmartPointer<char> caller =
|
3885
|
+
info()->function()->debug_name()->ToCString();
|
3886
|
+
PrintF("Did not inline %s called from %s (%s).\n",
|
3887
|
+
*callee, *caller, reason);
|
3888
|
+
}
|
4044
3889
|
}
|
4045
3890
|
}
|
4046
3891
|
|
@@ -4055,148 +3900,156 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
4055
3900
|
// Do a quick check on source code length to avoid parsing large
|
4056
3901
|
// inlining candidates.
|
4057
3902
|
if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) {
|
4058
|
-
|
3903
|
+
TraceInline(target, "target text too big");
|
4059
3904
|
return false;
|
4060
3905
|
}
|
4061
3906
|
|
4062
3907
|
// Target must be inlineable.
|
4063
|
-
if (!target->IsInlineable())
|
3908
|
+
if (!target->IsInlineable()) {
|
3909
|
+
TraceInline(target, "target not inlineable");
|
3910
|
+
return false;
|
3911
|
+
}
|
4064
3912
|
|
4065
3913
|
// No context change required.
|
4066
|
-
CompilationInfo* outer_info =
|
3914
|
+
CompilationInfo* outer_info = info();
|
4067
3915
|
if (target->context() != outer_info->closure()->context() ||
|
4068
3916
|
outer_info->scope()->contains_with() ||
|
4069
3917
|
outer_info->scope()->num_heap_slots() > 0) {
|
3918
|
+
TraceInline(target, "target requires context change");
|
4070
3919
|
return false;
|
4071
3920
|
}
|
4072
3921
|
|
4073
3922
|
// Don't inline deeper than two calls.
|
4074
3923
|
HEnvironment* env = environment();
|
4075
|
-
if (env->outer() != NULL && env->outer()->outer() != NULL)
|
3924
|
+
if (env->outer() != NULL && env->outer()->outer() != NULL) {
|
3925
|
+
TraceInline(target, "inline depth limit reached");
|
3926
|
+
return false;
|
3927
|
+
}
|
4076
3928
|
|
4077
3929
|
// Don't inline recursive functions.
|
4078
|
-
if (target->shared() == outer_info->closure()->shared())
|
3930
|
+
if (target->shared() == outer_info->closure()->shared()) {
|
3931
|
+
TraceInline(target, "target is recursive");
|
3932
|
+
return false;
|
3933
|
+
}
|
4079
3934
|
|
4080
3935
|
// We don't want to add more than a certain number of nodes from inlining.
|
4081
3936
|
if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) {
|
4082
|
-
|
3937
|
+
TraceInline(target, "cumulative AST node limit reached");
|
4083
3938
|
return false;
|
4084
3939
|
}
|
4085
3940
|
|
4086
3941
|
int count_before = AstNode::Count();
|
4087
3942
|
|
4088
3943
|
// Parse and allocate variables.
|
4089
|
-
CompilationInfo
|
4090
|
-
if (!ParserApi::Parse(&
|
4091
|
-
!Scope::Analyze(&
|
4092
|
-
if (
|
3944
|
+
CompilationInfo target_info(target);
|
3945
|
+
if (!ParserApi::Parse(&target_info) ||
|
3946
|
+
!Scope::Analyze(&target_info)) {
|
3947
|
+
if (target_info.isolate()->has_pending_exception()) {
|
3948
|
+
// Parse or scope error, never optimize this function.
|
4093
3949
|
SetStackOverflow();
|
3950
|
+
target->shared()->set_optimization_disabled(true);
|
4094
3951
|
}
|
3952
|
+
TraceInline(target, "parse failure");
|
4095
3953
|
return false;
|
4096
3954
|
}
|
4097
|
-
|
4098
|
-
|
3955
|
+
|
3956
|
+
if (target_info.scope()->num_heap_slots() > 0) {
|
3957
|
+
TraceInline(target, "target has context-allocated variables");
|
3958
|
+
return false;
|
3959
|
+
}
|
3960
|
+
FunctionLiteral* function = target_info.function();
|
4099
3961
|
|
4100
3962
|
// Count the number of AST nodes added by inlining this call.
|
4101
3963
|
int nodes_added = AstNode::Count() - count_before;
|
4102
3964
|
if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) {
|
4103
|
-
|
3965
|
+
TraceInline(target, "target AST is too large");
|
4104
3966
|
return false;
|
4105
3967
|
}
|
4106
3968
|
|
4107
3969
|
// Check if we can handle all declarations in the inlined functions.
|
4108
|
-
VisitDeclarations(
|
3970
|
+
VisitDeclarations(target_info.scope()->declarations());
|
4109
3971
|
if (HasStackOverflow()) {
|
3972
|
+
TraceInline(target, "target has non-trivial declaration");
|
4110
3973
|
ClearStackOverflow();
|
4111
3974
|
return false;
|
4112
3975
|
}
|
4113
3976
|
|
4114
3977
|
// Don't inline functions that uses the arguments object or that
|
4115
3978
|
// have a mismatching number of parameters.
|
4116
|
-
Handle<SharedFunctionInfo>
|
3979
|
+
Handle<SharedFunctionInfo> target_shared(target->shared());
|
4117
3980
|
int arity = expr->arguments()->length();
|
4118
3981
|
if (function->scope()->arguments() != NULL ||
|
4119
|
-
arity !=
|
3982
|
+
arity != target_shared->formal_parameter_count()) {
|
3983
|
+
TraceInline(target, "target requires special argument handling");
|
4120
3984
|
return false;
|
4121
3985
|
}
|
4122
3986
|
|
4123
3987
|
// All statements in the body must be inlineable.
|
4124
3988
|
for (int i = 0, count = function->body()->length(); i < count; ++i) {
|
4125
|
-
if (!function->body()->at(i)->IsInlineable())
|
3989
|
+
if (!function->body()->at(i)->IsInlineable()) {
|
3990
|
+
TraceInline(target, "target contains unsupported syntax");
|
3991
|
+
return false;
|
3992
|
+
}
|
4126
3993
|
}
|
4127
3994
|
|
4128
3995
|
// Generate the deoptimization data for the unoptimized version of
|
4129
3996
|
// the target function if we don't already have it.
|
4130
|
-
if (!
|
3997
|
+
if (!target_shared->has_deoptimization_support()) {
|
4131
3998
|
// Note that we compile here using the same AST that we will use for
|
4132
3999
|
// generating the optimized inline code.
|
4133
|
-
|
4134
|
-
if (!FullCodeGenerator::MakeCode(&
|
4135
|
-
|
4136
|
-
|
4137
|
-
|
4000
|
+
target_info.EnableDeoptimizationSupport();
|
4001
|
+
if (!FullCodeGenerator::MakeCode(&target_info)) {
|
4002
|
+
TraceInline(target, "could not generate deoptimization info");
|
4003
|
+
return false;
|
4004
|
+
}
|
4005
|
+
target_shared->EnableDeoptimizationSupport(*target_info.code());
|
4006
|
+
Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG,
|
4007
|
+
&target_info,
|
4008
|
+
target_shared);
|
4138
4009
|
}
|
4139
4010
|
|
4011
|
+
// ----------------------------------------------------------------
|
4140
4012
|
// Save the pending call context and type feedback oracle. Set up new ones
|
4141
4013
|
// for the inlined function.
|
4142
|
-
ASSERT(
|
4143
|
-
|
4144
|
-
|
4145
|
-
TypeFeedbackOracle* saved_oracle = oracle();
|
4146
|
-
// On-stack replacement cannot target inlined functions. Since we don't
|
4147
|
-
// use a separate CompilationInfo structure for the inlined function, we
|
4148
|
-
// save and restore the AST ID in the original compilation info.
|
4149
|
-
int saved_osr_ast_id = graph()->info()->osr_ast_id();
|
4150
|
-
|
4151
|
-
TestContext* test_context = NULL;
|
4152
|
-
if (ast_context()->IsTest()) {
|
4153
|
-
// Inlined body is treated as if it occurs in an 'inlined' call context
|
4154
|
-
// with true and false blocks that will forward to the real ones.
|
4155
|
-
HBasicBlock* if_true = graph()->CreateBasicBlock();
|
4156
|
-
HBasicBlock* if_false = graph()->CreateBasicBlock();
|
4157
|
-
if_true->MarkAsInlineReturnTarget();
|
4158
|
-
if_false->MarkAsInlineReturnTarget();
|
4159
|
-
// AstContext constructor pushes on the context stack.
|
4160
|
-
test_context = new TestContext(this, if_true, if_false);
|
4161
|
-
function_return_ = NULL;
|
4162
|
-
} else {
|
4163
|
-
// Inlined body is treated as if it occurs in the original call context.
|
4164
|
-
function_return_ = graph()->CreateBasicBlock();
|
4165
|
-
function_return_->MarkAsInlineReturnTarget();
|
4166
|
-
}
|
4167
|
-
call_context_ = ast_context();
|
4168
|
-
TypeFeedbackOracle new_oracle(
|
4169
|
-
Handle<Code>(shared->code()),
|
4014
|
+
ASSERT(target_shared->has_deoptimization_support());
|
4015
|
+
TypeFeedbackOracle target_oracle(
|
4016
|
+
Handle<Code>(target_shared->code()),
|
4170
4017
|
Handle<Context>(target->context()->global_context()));
|
4171
|
-
|
4172
|
-
graph()->info()->SetOsrAstId(AstNode::kNoNumber);
|
4018
|
+
FunctionState target_state(this, &target_info, &target_oracle);
|
4173
4019
|
|
4174
|
-
|
4175
|
-
|
4176
|
-
|
4020
|
+
HConstant* undefined = graph()->GetConstantUndefined();
|
4021
|
+
HEnvironment* inner_env =
|
4022
|
+
environment()->CopyForInlining(target, function, true, undefined);
|
4023
|
+
HBasicBlock* body_entry = CreateBasicBlock(inner_env);
|
4024
|
+
current_block()->Goto(body_entry);
|
4025
|
+
|
4026
|
+
body_entry->SetJoinId(expr->ReturnId());
|
4027
|
+
set_current_block(body_entry);
|
4028
|
+
AddInstruction(new HEnterInlined(target, function));
|
4029
|
+
VisitStatements(function->body());
|
4177
4030
|
if (HasStackOverflow()) {
|
4178
4031
|
// Bail out if the inline function did, as we cannot residualize a call
|
4179
4032
|
// instead.
|
4180
|
-
|
4181
|
-
call_context_ = saved_call_context;
|
4182
|
-
function_return_ = saved_function_return;
|
4183
|
-
oracle_ = saved_oracle;
|
4184
|
-
graph()->info()->SetOsrAstId(saved_osr_ast_id);
|
4033
|
+
TraceInline(target, "inline graph construction failed");
|
4185
4034
|
return false;
|
4186
4035
|
}
|
4187
4036
|
|
4188
4037
|
// Update inlined nodes count.
|
4189
4038
|
inlined_count_ += nodes_added;
|
4190
4039
|
|
4191
|
-
|
4040
|
+
TraceInline(target, NULL);
|
4192
4041
|
|
4193
|
-
if (
|
4042
|
+
if (current_block() != NULL) {
|
4194
4043
|
// Add a return of undefined if control can fall off the body. In a
|
4195
4044
|
// test context, undefined is false.
|
4196
|
-
|
4197
|
-
|
4198
|
-
ASSERT(
|
4199
|
-
|
4045
|
+
if (inlined_test_context() == NULL) {
|
4046
|
+
ASSERT(function_return() != NULL);
|
4047
|
+
ASSERT(call_context()->IsEffect() || call_context()->IsValue());
|
4048
|
+
if (call_context()->IsEffect()) {
|
4049
|
+
current_block()->Goto(function_return(), false);
|
4050
|
+
} else {
|
4051
|
+
current_block()->AddLeaveInlined(undefined, function_return());
|
4052
|
+
}
|
4200
4053
|
} else {
|
4201
4054
|
// The graph builder assumes control can reach both branches of a
|
4202
4055
|
// test, so we materialize the undefined value and test it rather than
|
@@ -4205,46 +4058,29 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
4205
4058
|
// TODO(3168478): refactor to avoid this.
|
4206
4059
|
HBasicBlock* empty_true = graph()->CreateBasicBlock();
|
4207
4060
|
HBasicBlock* empty_false = graph()->CreateBasicBlock();
|
4208
|
-
HTest* test = new HTest(
|
4209
|
-
|
4061
|
+
HTest* test = new HTest(undefined, empty_true, empty_false);
|
4062
|
+
current_block()->Finish(test);
|
4210
4063
|
|
4211
|
-
|
4212
|
-
|
4213
|
-
empty_false->AddLeaveInlined(no_return_value, test_context->if_false());
|
4064
|
+
empty_true->Goto(inlined_test_context()->if_true(), false);
|
4065
|
+
empty_false->Goto(inlined_test_context()->if_false(), false);
|
4214
4066
|
}
|
4215
|
-
body->set_exit_block(NULL);
|
4216
4067
|
}
|
4217
4068
|
|
4218
|
-
// Record the environment at the inlined function call.
|
4219
|
-
AddSimulate(expr->ReturnId());
|
4220
|
-
|
4221
|
-
// Jump to the function entry (without re-recording the environment).
|
4222
|
-
current_block()->Finish(new HGoto(body->entry_block()));
|
4223
|
-
|
4224
4069
|
// Fix up the function exits.
|
4225
|
-
if (
|
4226
|
-
HBasicBlock* if_true =
|
4227
|
-
HBasicBlock* if_false =
|
4070
|
+
if (inlined_test_context() != NULL) {
|
4071
|
+
HBasicBlock* if_true = inlined_test_context()->if_true();
|
4072
|
+
HBasicBlock* if_false = inlined_test_context()->if_false();
|
4228
4073
|
if_true->SetJoinId(expr->id());
|
4229
4074
|
if_false->SetJoinId(expr->id());
|
4230
|
-
ASSERT(ast_context() ==
|
4231
|
-
|
4075
|
+
ASSERT(ast_context() == inlined_test_context());
|
4076
|
+
// Pop the return test context from the expression context stack.
|
4077
|
+
ClearInlinedTestContext();
|
4232
4078
|
|
4233
4079
|
// Forward to the real test context.
|
4234
|
-
HValue* const no_return_value = NULL;
|
4235
4080
|
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
|
4236
|
-
if (true_target->IsInlineReturnTarget()) {
|
4237
|
-
if_true->AddLeaveInlined(no_return_value, true_target);
|
4238
|
-
} else {
|
4239
|
-
if_true->Goto(true_target);
|
4240
|
-
}
|
4241
|
-
|
4242
4081
|
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
|
4243
|
-
|
4244
|
-
|
4245
|
-
} else {
|
4246
|
-
if_false->Goto(false_target);
|
4247
|
-
}
|
4082
|
+
if_true->Goto(true_target, false);
|
4083
|
+
if_false->Goto(false_target, false);
|
4248
4084
|
|
4249
4085
|
// TODO(kmillikin): Come up with a better way to handle this. It is too
|
4250
4086
|
// subtle. NULL here indicates that the enclosing context has no control
|
@@ -4252,29 +4088,14 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
4252
4088
|
set_current_block(NULL);
|
4253
4089
|
|
4254
4090
|
} else {
|
4255
|
-
|
4256
|
-
set_current_block(
|
4091
|
+
function_return()->SetJoinId(expr->id());
|
4092
|
+
set_current_block(function_return());
|
4257
4093
|
}
|
4258
4094
|
|
4259
|
-
call_context_ = saved_call_context;
|
4260
|
-
function_return_ = saved_function_return;
|
4261
|
-
oracle_ = saved_oracle;
|
4262
|
-
graph()->info()->SetOsrAstId(saved_osr_ast_id);
|
4263
|
-
|
4264
4095
|
return true;
|
4265
4096
|
}
|
4266
4097
|
|
4267
4098
|
|
4268
|
-
void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
|
4269
|
-
ASSERT(target->IsInlineReturnTarget());
|
4270
|
-
AddInstruction(new HLeaveInlined);
|
4271
|
-
HEnvironment* outer = last_environment()->outer();
|
4272
|
-
if (return_value != NULL) outer->Push(return_value);
|
4273
|
-
UpdateEnvironment(outer);
|
4274
|
-
Goto(target);
|
4275
|
-
}
|
4276
|
-
|
4277
|
-
|
4278
4099
|
bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
|
4279
4100
|
HValue* receiver,
|
4280
4101
|
Handle<Map> receiver_map,
|
@@ -4286,6 +4107,7 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
|
|
4286
4107
|
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
|
4287
4108
|
switch (id) {
|
4288
4109
|
case kStringCharCodeAt:
|
4110
|
+
case kStringCharAt:
|
4289
4111
|
if (argument_count == 2 && check_type == STRING_CHECK) {
|
4290
4112
|
HValue* index = Pop();
|
4291
4113
|
HValue* string = Pop();
|
@@ -4293,7 +4115,13 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
|
|
4293
4115
|
AddInstruction(new HCheckPrototypeMaps(
|
4294
4116
|
oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
|
4295
4117
|
expr->holder()));
|
4296
|
-
HStringCharCodeAt*
|
4118
|
+
HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
|
4119
|
+
if (id == kStringCharCodeAt) {
|
4120
|
+
ast_context()->ReturnInstruction(char_code, expr->id());
|
4121
|
+
return true;
|
4122
|
+
}
|
4123
|
+
AddInstruction(char_code);
|
4124
|
+
HStringCharFromCode* result = new HStringCharFromCode(char_code);
|
4297
4125
|
ast_context()->ReturnInstruction(result, expr->id());
|
4298
4126
|
return true;
|
4299
4127
|
}
|
@@ -4368,7 +4196,7 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
|
|
4368
4196
|
Property* prop = callee->AsProperty();
|
4369
4197
|
ASSERT(prop != NULL);
|
4370
4198
|
|
4371
|
-
if (
|
4199
|
+
if (info()->scope()->arguments() == NULL) return false;
|
4372
4200
|
|
4373
4201
|
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
|
4374
4202
|
if (!name->IsEqualTo(CStrVector("apply"))) return false;
|
@@ -4405,13 +4233,6 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
|
|
4405
4233
|
}
|
4406
4234
|
|
4407
4235
|
|
4408
|
-
static bool HasCustomCallGenerator(Handle<JSFunction> function) {
|
4409
|
-
SharedFunctionInfo* info = function->shared();
|
4410
|
-
return info->HasBuiltinFunctionId() &&
|
4411
|
-
CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id());
|
4412
|
-
}
|
4413
|
-
|
4414
|
-
|
4415
4236
|
void HGraphBuilder::VisitCall(Call* expr) {
|
4416
4237
|
Expression* callee = expr->expression();
|
4417
4238
|
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
|
@@ -4469,11 +4290,11 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|
4469
4290
|
return;
|
4470
4291
|
}
|
4471
4292
|
|
4472
|
-
if (HasCustomCallGenerator(expr->target()) ||
|
4293
|
+
if (CallStubCompiler::HasCustomCallGenerator(*expr->target()) ||
|
4473
4294
|
expr->check_type() != RECEIVER_MAP_CHECK) {
|
4474
4295
|
// When the target has a custom call IC generator, use the IC,
|
4475
|
-
// because it is likely to generate better code.
|
4476
|
-
//
|
4296
|
+
// because it is likely to generate better code. Also use the IC
|
4297
|
+
// when a primitive receiver check is required.
|
4477
4298
|
HContext* context = new HContext;
|
4478
4299
|
AddInstruction(context);
|
4479
4300
|
call = PreProcessCall(new HCallNamed(context, name, argument_count));
|
@@ -4481,16 +4302,6 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|
4481
4302
|
AddCheckConstantFunction(expr, receiver, receiver_map, true);
|
4482
4303
|
|
4483
4304
|
if (TryInline(expr)) {
|
4484
|
-
if (current_block() != NULL) {
|
4485
|
-
HValue* return_value = Pop();
|
4486
|
-
// If we inlined a function in a test context then we need to emit
|
4487
|
-
// a simulate here to shadow the ones at the end of the
|
4488
|
-
// predecessor blocks. Those environments contain the return
|
4489
|
-
// value on top and do not correspond to any actual state of the
|
4490
|
-
// unoptimized code.
|
4491
|
-
if (ast_context()->IsEffect()) AddSimulate(expr->id());
|
4492
|
-
ast_context()->ReturnValue(return_value);
|
4493
|
-
}
|
4494
4305
|
return;
|
4495
4306
|
} else {
|
4496
4307
|
// Check for bailout, as the TryInline call in the if condition above
|
@@ -4521,14 +4332,17 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|
4521
4332
|
}
|
4522
4333
|
|
4523
4334
|
if (global_call) {
|
4335
|
+
bool known_global_function = false;
|
4524
4336
|
// If there is a global property cell for the name at compile time and
|
4525
4337
|
// access check is not enabled we assume that the function will not change
|
4526
4338
|
// and generate optimized code for calling the function.
|
4527
|
-
|
4528
|
-
|
4529
|
-
|
4530
|
-
|
4531
|
-
|
4339
|
+
LookupResult lookup;
|
4340
|
+
GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false);
|
4341
|
+
if (type == kUseCell &&
|
4342
|
+
!info()->global_object()->IsAccessCheckNeeded()) {
|
4343
|
+
Handle<GlobalObject> global(info()->global_object());
|
4344
|
+
known_global_function = expr->ComputeGlobalTarget(global, &lookup);
|
4345
|
+
}
|
4532
4346
|
if (known_global_function) {
|
4533
4347
|
// Push the global object instead of the global receiver because
|
4534
4348
|
// code generated by the full code generator expects it.
|
@@ -4553,16 +4367,6 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|
4553
4367
|
environment()->SetExpressionStackAt(receiver_index, global_receiver);
|
4554
4368
|
|
4555
4369
|
if (TryInline(expr)) {
|
4556
|
-
if (current_block() != NULL) {
|
4557
|
-
HValue* return_value = Pop();
|
4558
|
-
// If we inlined a function in a test context then we need to
|
4559
|
-
// emit a simulate here to shadow the ones at the end of the
|
4560
|
-
// predecessor blocks. Those environments contain the return
|
4561
|
-
// value on top and do not correspond to any actual state of the
|
4562
|
-
// unoptimized code.
|
4563
|
-
if (ast_context()->IsEffect()) AddSimulate(expr->id());
|
4564
|
-
ast_context()->ReturnValue(return_value);
|
4565
|
-
}
|
4566
4370
|
return;
|
4567
4371
|
}
|
4568
4372
|
// Check for bailout, as trying to inline might fail due to bailout
|
@@ -4642,7 +4446,7 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
|
|
4642
4446
|
BAILOUT("call to a JavaScript runtime function");
|
4643
4447
|
}
|
4644
4448
|
|
4645
|
-
Runtime::Function* function = expr->function();
|
4449
|
+
const Runtime::Function* function = expr->function();
|
4646
4450
|
ASSERT(function != NULL);
|
4647
4451
|
if (function->intrinsic_type == Runtime::INLINE) {
|
4648
4452
|
ASSERT(expr->name()->length() > 0);
|
@@ -4717,29 +4521,35 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
|
|
4717
4521
|
context->if_false(),
|
4718
4522
|
context->if_true());
|
4719
4523
|
} else if (ast_context()->IsValue()) {
|
4720
|
-
|
4721
|
-
|
4524
|
+
HBasicBlock* materialize_false = graph()->CreateBasicBlock();
|
4525
|
+
HBasicBlock* materialize_true = graph()->CreateBasicBlock();
|
4722
4526
|
VISIT_FOR_CONTROL(expr->expression(),
|
4723
|
-
|
4724
|
-
|
4725
|
-
|
4726
|
-
|
4727
|
-
|
4728
|
-
|
4729
|
-
|
4730
|
-
|
4731
|
-
|
4732
|
-
|
4733
|
-
|
4734
|
-
|
4735
|
-
|
4527
|
+
materialize_false,
|
4528
|
+
materialize_true);
|
4529
|
+
materialize_false->SetJoinId(expr->expression()->id());
|
4530
|
+
materialize_true->SetJoinId(expr->expression()->id());
|
4531
|
+
|
4532
|
+
set_current_block(materialize_false);
|
4533
|
+
Push(graph()->GetConstantFalse());
|
4534
|
+
set_current_block(materialize_true);
|
4535
|
+
Push(graph()->GetConstantTrue());
|
4536
|
+
|
4537
|
+
HBasicBlock* join =
|
4538
|
+
CreateJoin(materialize_false, materialize_true, expr->id());
|
4539
|
+
set_current_block(join);
|
4736
4540
|
ast_context()->ReturnValue(Pop());
|
4737
4541
|
} else {
|
4738
4542
|
ASSERT(ast_context()->IsEffect());
|
4739
|
-
|
4543
|
+
VisitForEffect(expr->expression());
|
4740
4544
|
}
|
4741
4545
|
|
4742
|
-
} else if (op == Token::
|
4546
|
+
} else if (op == Token::TYPEOF) {
|
4547
|
+
VisitForTypeOf(expr->expression());
|
4548
|
+
if (HasStackOverflow()) return;
|
4549
|
+
HValue* value = Pop();
|
4550
|
+
ast_context()->ReturnInstruction(new HTypeof(value), expr->id());
|
4551
|
+
|
4552
|
+
} else {
|
4743
4553
|
VISIT_FOR_VALUE(expr->expression());
|
4744
4554
|
HValue* value = Pop();
|
4745
4555
|
HInstruction* instr = NULL;
|
@@ -4748,19 +4558,16 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
|
|
4748
4558
|
instr = new HBitNot(value);
|
4749
4559
|
break;
|
4750
4560
|
case Token::SUB:
|
4751
|
-
instr = new HMul(graph_->GetConstantMinus1()
|
4561
|
+
instr = new HMul(value, graph_->GetConstantMinus1());
|
4562
|
+
break;
|
4563
|
+
case Token::ADD:
|
4564
|
+
instr = new HMul(value, graph_->GetConstant1());
|
4752
4565
|
break;
|
4753
4566
|
default:
|
4754
|
-
|
4567
|
+
BAILOUT("Value: unsupported unary operation");
|
4755
4568
|
break;
|
4756
4569
|
}
|
4757
4570
|
ast_context()->ReturnInstruction(instr, expr->id());
|
4758
|
-
} else if (op == Token::TYPEOF) {
|
4759
|
-
VISIT_FOR_VALUE(expr->expression());
|
4760
|
-
HValue* value = Pop();
|
4761
|
-
ast_context()->ReturnInstruction(new HTypeof(value), expr->id());
|
4762
|
-
} else {
|
4763
|
-
BAILOUT("Value: unsupported unary operation");
|
4764
4571
|
}
|
4765
4572
|
}
|
4766
4573
|
|
@@ -5034,28 +4841,23 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
|
|
5034
4841
|
VISIT_FOR_VALUE(expr->left());
|
5035
4842
|
ASSERT(current_block() != NULL);
|
5036
4843
|
|
5037
|
-
HValue* left = Top();
|
5038
|
-
HEnvironment* environment_copy = environment()->Copy();
|
5039
|
-
environment_copy->Pop();
|
5040
|
-
HSubgraph* right_subgraph;
|
5041
|
-
right_subgraph = CreateBranchSubgraph(environment_copy);
|
5042
|
-
ADD_TO_SUBGRAPH(right_subgraph, expr->right());
|
5043
|
-
|
5044
|
-
ASSERT(current_block() != NULL &&
|
5045
|
-
right_subgraph->exit_block() != NULL);
|
5046
4844
|
// We need an extra block to maintain edge-split form.
|
5047
4845
|
HBasicBlock* empty_block = graph()->CreateBasicBlock();
|
5048
|
-
HBasicBlock*
|
5049
|
-
|
4846
|
+
HBasicBlock* eval_right = graph()->CreateBasicBlock();
|
5050
4847
|
HTest* test = is_logical_and
|
5051
|
-
? new HTest(
|
5052
|
-
: new HTest(
|
4848
|
+
? new HTest(Top(), eval_right, empty_block)
|
4849
|
+
: new HTest(Top(), empty_block, eval_right);
|
5053
4850
|
current_block()->Finish(test);
|
5054
|
-
|
5055
|
-
|
5056
|
-
|
4851
|
+
|
4852
|
+
set_current_block(eval_right);
|
4853
|
+
Drop(1); // Value of the left subexpression.
|
4854
|
+
VISIT_FOR_VALUE(expr->right());
|
4855
|
+
|
4856
|
+
HBasicBlock* join_block =
|
4857
|
+
CreateJoin(empty_block, current_block(), expr->id());
|
5057
4858
|
set_current_block(join_block);
|
5058
4859
|
ast_context()->ReturnValue(Pop());
|
4860
|
+
|
5059
4861
|
} else {
|
5060
4862
|
ASSERT(ast_context()->IsEffect());
|
5061
4863
|
// In an effect context, we don't need the value of the left
|
@@ -5146,7 +4948,8 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
|
5146
4948
|
if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) &&
|
5147
4949
|
left_unary != NULL && left_unary->op() == Token::TYPEOF &&
|
5148
4950
|
right_literal != NULL && right_literal->handle()->IsString()) {
|
5149
|
-
|
4951
|
+
VisitForTypeOf(left_unary->expression());
|
4952
|
+
if (HasStackOverflow()) return;
|
5150
4953
|
HValue* left = Pop();
|
5151
4954
|
HInstruction* instr = new HTypeofIs(left,
|
5152
4955
|
Handle<String>::cast(right_literal->handle()));
|
@@ -5162,7 +4965,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
|
5162
4965
|
HValue* left = Pop();
|
5163
4966
|
Token::Value op = expr->op();
|
5164
4967
|
|
5165
|
-
TypeInfo
|
4968
|
+
TypeInfo type_info = oracle()->CompareType(expr);
|
5166
4969
|
HInstruction* instr = NULL;
|
5167
4970
|
if (op == Token::INSTANCEOF) {
|
5168
4971
|
// Check to see if the rhs of the instanceof is a global function not
|
@@ -5171,12 +4974,11 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
|
5171
4974
|
Handle<JSFunction> target = Handle<JSFunction>::null();
|
5172
4975
|
Variable* var = expr->right()->AsVariableProxy()->AsVariable();
|
5173
4976
|
bool global_function = (var != NULL) && var->is_global() && !var->is_this();
|
5174
|
-
CompilationInfo* info = graph()->info();
|
5175
4977
|
if (global_function &&
|
5176
|
-
info->has_global_object() &&
|
5177
|
-
!info->global_object()->IsAccessCheckNeeded()) {
|
4978
|
+
info()->has_global_object() &&
|
4979
|
+
!info()->global_object()->IsAccessCheckNeeded()) {
|
5178
4980
|
Handle<String> name = var->name();
|
5179
|
-
Handle<GlobalObject> global(info->global_object());
|
4981
|
+
Handle<GlobalObject> global(info()->global_object());
|
5180
4982
|
LookupResult lookup;
|
5181
4983
|
global->Lookup(*name, &lookup);
|
5182
4984
|
if (lookup.IsProperty() &&
|
@@ -5185,7 +4987,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
|
5185
4987
|
Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue()));
|
5186
4988
|
// If the function is in new space we assume it's more likely to
|
5187
4989
|
// change and thus prefer the general IC code.
|
5188
|
-
if (!
|
4990
|
+
if (!isolate()->heap()->InNewSpace(*candidate)) {
|
5189
4991
|
target = candidate;
|
5190
4992
|
}
|
5191
4993
|
}
|
@@ -5203,7 +5005,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
|
5203
5005
|
}
|
5204
5006
|
} else if (op == Token::IN) {
|
5205
5007
|
BAILOUT("Unsupported comparison: in");
|
5206
|
-
} else if (
|
5008
|
+
} else if (type_info.IsNonPrimitive()) {
|
5207
5009
|
switch (op) {
|
5208
5010
|
case Token::EQ:
|
5209
5011
|
case Token::EQ_STRICT: {
|
@@ -5220,7 +5022,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
|
5220
5022
|
}
|
5221
5023
|
} else {
|
5222
5024
|
HCompare* compare = new HCompare(left, right, op);
|
5223
|
-
Representation r = ToRepresentation(
|
5025
|
+
Representation r = ToRepresentation(type_info);
|
5224
5026
|
compare->SetInputRepresentation(r);
|
5225
5027
|
instr = compare;
|
5226
5028
|
}
|
@@ -5344,7 +5146,14 @@ void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
|
|
5344
5146
|
// Support for construct call checks.
|
5345
5147
|
void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
|
5346
5148
|
ASSERT(call->arguments()->length() == 0);
|
5347
|
-
|
5149
|
+
if (function_state()->outer() != NULL) {
|
5150
|
+
// We are generating graph for inlined function. Currently
|
5151
|
+
// constructor inlining is not supported and we can just return
|
5152
|
+
// false from %_IsConstructCall().
|
5153
|
+
ast_context()->ReturnValue(graph()->GetConstantFalse());
|
5154
|
+
} else {
|
5155
|
+
ast_context()->ReturnInstruction(new HIsConstructCall, call->id());
|
5156
|
+
}
|
5348
5157
|
}
|
5349
5158
|
|
5350
5159
|
|
@@ -5404,19 +5213,24 @@ void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
|
|
5404
5213
|
|
5405
5214
|
// Fast support for string.charAt(n) and string[n].
|
5406
5215
|
void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
|
5407
|
-
|
5216
|
+
ASSERT(call->arguments()->length() == 1);
|
5217
|
+
VISIT_FOR_VALUE(call->arguments()->at(0));
|
5218
|
+
HValue* char_code = Pop();
|
5219
|
+
HStringCharFromCode* result = new HStringCharFromCode(char_code);
|
5220
|
+
ast_context()->ReturnInstruction(result, call->id());
|
5408
5221
|
}
|
5409
5222
|
|
5410
5223
|
|
5411
5224
|
// Fast support for string.charAt(n) and string[n].
|
5412
5225
|
void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
|
5413
|
-
|
5414
|
-
|
5415
|
-
|
5416
|
-
|
5417
|
-
|
5418
|
-
|
5419
|
-
|
5226
|
+
ASSERT(call->arguments()->length() == 2);
|
5227
|
+
VISIT_FOR_VALUE(call->arguments()->at(0));
|
5228
|
+
VISIT_FOR_VALUE(call->arguments()->at(1));
|
5229
|
+
HValue* index = Pop();
|
5230
|
+
HValue* string = Pop();
|
5231
|
+
HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
|
5232
|
+
AddInstruction(char_code);
|
5233
|
+
HStringCharFromCode* result = new HStringCharFromCode(char_code);
|
5420
5234
|
ast_context()->ReturnInstruction(result, call->id());
|
5421
5235
|
}
|
5422
5236
|
|
@@ -5966,12 +5780,12 @@ void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
|
|
5966
5780
|
Tag tag(this, "intervals");
|
5967
5781
|
PrintStringProperty("name", name);
|
5968
5782
|
|
5969
|
-
const
|
5783
|
+
const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
|
5970
5784
|
for (int i = 0; i < fixed_d->length(); ++i) {
|
5971
5785
|
TraceLiveRange(fixed_d->at(i), "fixed");
|
5972
5786
|
}
|
5973
5787
|
|
5974
|
-
const
|
5788
|
+
const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
|
5975
5789
|
for (int i = 0; i < fixed->length(); ++i) {
|
5976
5790
|
TraceLiveRange(fixed->at(i), "fixed");
|
5977
5791
|
}
|
@@ -6042,6 +5856,11 @@ void HTracer::FlushToFile() {
|
|
6042
5856
|
}
|
6043
5857
|
|
6044
5858
|
|
5859
|
+
void HStatistics::Initialize(CompilationInfo* info) {
|
5860
|
+
source_size_ += info->shared_info()->SourceSize();
|
5861
|
+
}
|
5862
|
+
|
5863
|
+
|
6045
5864
|
void HStatistics::Print() {
|
6046
5865
|
PrintF("Timing results:\n");
|
6047
5866
|
int64_t sum = 0;
|
@@ -6059,9 +5878,15 @@ void HStatistics::Print() {
|
|
6059
5878
|
double size_percent = static_cast<double>(size) * 100 / total_size_;
|
6060
5879
|
PrintF(" %8u bytes / %4.1f %%\n", size, size_percent);
|
6061
5880
|
}
|
6062
|
-
|
6063
|
-
|
6064
|
-
|
5881
|
+
double source_size_in_kb = static_cast<double>(source_size_) / 1024;
|
5882
|
+
double normalized_time = source_size_in_kb > 0
|
5883
|
+
? (static_cast<double>(sum) / 1000) / source_size_in_kb
|
5884
|
+
: 0;
|
5885
|
+
double normalized_bytes = source_size_in_kb > 0
|
5886
|
+
? total_size_ / source_size_in_kb
|
5887
|
+
: 0;
|
5888
|
+
PrintF("%30s - %7.3f ms %7.3f bytes\n", "Sum",
|
5889
|
+
normalized_time, normalized_bytes);
|
6065
5890
|
PrintF("---------------------------------------------------------------\n");
|
6066
5891
|
PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n",
|
6067
5892
|
"Total",
|
@@ -6106,13 +5931,13 @@ void HPhase::Begin(const char* name,
|
|
6106
5931
|
if (allocator != NULL && chunk_ == NULL) {
|
6107
5932
|
chunk_ = allocator->chunk();
|
6108
5933
|
}
|
6109
|
-
if (
|
5934
|
+
if (FLAG_hydrogen_stats) start_ = OS::Ticks();
|
6110
5935
|
start_allocation_size_ = Zone::allocation_size_;
|
6111
5936
|
}
|
6112
5937
|
|
6113
5938
|
|
6114
5939
|
void HPhase::End() const {
|
6115
|
-
if (
|
5940
|
+
if (FLAG_hydrogen_stats) {
|
6116
5941
|
int64_t end = OS::Ticks();
|
6117
5942
|
unsigned size = Zone::allocation_size_ - start_allocation_size_;
|
6118
5943
|
HStatistics::Instance()->SaveTiming(name_, end - start_, size);
|