summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS4
-rw-r--r--ChangeLog69
-rw-r--r--SConstruct256
-rwxr-xr-xinclude/v8-debug.h32
-rw-r--r--include/v8-profiler.h165
-rw-r--r--include/v8-testing.h5
-rw-r--r--include/v8.h183
-rw-r--r--samples/shell.cc275
-rwxr-xr-xsrc/SConscript31
-rw-r--r--src/accessors.cc115
-rw-r--r--src/allocation-inl.h (renamed from test/cctest/test-mips.cc)33
-rw-r--r--src/allocation.cc82
-rw-r--r--src/allocation.h51
-rw-r--r--src/api.cc2755
-rw-r--r--src/api.h88
-rw-r--r--src/apiutils.h7
-rw-r--r--src/arguments.h10
-rw-r--r--src/arm/assembler-arm-inl.h13
-rw-r--r--src/arm/assembler-arm.cc150
-rw-r--r--src/arm/assembler-arm.h57
-rw-r--r--src/arm/builtins-arm.cc57
-rw-r--r--src/arm/code-stubs-arm.cc777
-rw-r--r--src/arm/code-stubs-arm.h59
-rw-r--r--src/arm/codegen-arm.cc236
-rw-r--r--src/arm/codegen-arm.h12
-rw-r--r--src/arm/constants-arm.h9
-rw-r--r--src/arm/cpu-arm.cc7
-rw-r--r--src/arm/debug-arm.cc10
-rw-r--r--src/arm/deoptimizer-arm.cc61
-rw-r--r--src/arm/disasm-arm.cc62
-rw-r--r--src/arm/full-codegen-arm.cc171
-rw-r--r--src/arm/ic-arm.cc148
-rw-r--r--src/arm/lithium-arm.cc132
-rw-r--r--src/arm/lithium-arm.h158
-rw-r--r--src/arm/lithium-codegen-arm.cc688
-rw-r--r--src/arm/lithium-codegen-arm.h17
-rw-r--r--src/arm/lithium-gap-resolver-arm.cc2
-rw-r--r--src/arm/macro-assembler-arm.cc434
-rw-r--r--src/arm/macro-assembler-arm.h76
-rw-r--r--src/arm/regexp-macro-assembler-arm.cc23
-rw-r--r--src/arm/regexp-macro-assembler-arm.h1
-rw-r--r--src/arm/simulator-arm.cc220
-rw-r--r--src/arm/simulator-arm.h47
-rw-r--r--src/arm/stub-cache-arm.cc873
-rw-r--r--src/arm/virtual-frame-arm.cc26
-rw-r--r--src/arm/virtual-frame-arm.h17
-rw-r--r--src/assembler.cc255
-rw-r--r--src/assembler.h146
-rw-r--r--src/ast-inl.h5
-rw-r--r--src/ast.cc43
-rw-r--r--src/ast.h141
-rw-r--r--src/atomicops.h2
-rw-r--r--src/atomicops_internals_mips_gcc.h169
-rw-r--r--src/bootstrapper.cc1016
-rw-r--r--src/bootstrapper.h121
-rw-r--r--src/builtins.cc563
-rw-r--r--src/builtins.h65
-rw-r--r--src/checks.cc4
-rw-r--r--src/code-stubs.cc40
-rw-r--r--src/code-stubs.h55
-rw-r--r--src/codegen-inl.h6
-rw-r--r--src/codegen.cc42
-rw-r--r--src/codegen.h18
-rw-r--r--src/compilation-cache.cc298
-rw-r--r--src/compilation-cache.h235
-rwxr-xr-xsrc/compiler.cc149
-rw-r--r--src/compiler.h19
-rw-r--r--src/contexts.cc37
-rw-r--r--src/contexts.h22
-rw-r--r--src/conversions.cc116
-rw-r--r--src/counters.cc23
-rw-r--r--src/counters.h44
-rw-r--r--src/cpu-profiler-inl.h6
-rw-r--r--src/cpu-profiler.cc194
-rw-r--r--src/cpu-profiler.h52
-rw-r--r--src/d8-debug.cc6
-rw-r--r--src/d8-debug.h13
-rw-r--r--src/d8-posix.cc2
-rw-r--r--src/d8.cc26
-rw-r--r--src/d8.gyp3
-rw-r--r--src/data-flow.h6
-rw-r--r--src/dateparser.h6
-rw-r--r--src/debug-agent.cc19
-rw-r--r--src/debug-agent.h20
-rw-r--r--src/debug.cc603
-rw-r--r--src/debug.h464
-rw-r--r--src/deoptimizer.cc137
-rw-r--r--src/deoptimizer.h68
-rw-r--r--src/disasm.h3
-rw-r--r--src/disassembler.cc19
-rw-r--r--src/execution.cc293
-rw-r--r--src/execution.h125
-rw-r--r--src/extensions/externalize-string-extension.cc4
-rw-r--r--src/extensions/gc-extension.cc2
-rw-r--r--src/factory.cc415
-rw-r--r--src/factory.h320
-rw-r--r--src/flag-definitions.h12
-rw-r--r--src/frame-element.cc5
-rw-r--r--src/frame-element.h24
-rw-r--r--src/frames-inl.h7
-rw-r--r--src/frames.cc98
-rw-r--r--src/frames.h59
-rw-r--r--src/full-codegen.cc17
-rw-r--r--src/full-codegen.h6
-rw-r--r--src/func-name-inferrer.cc13
-rw-r--r--src/func-name-inferrer.h2
-rw-r--r--src/gdb-jit.cc1
-rw-r--r--src/global-handles.cc174
-rw-r--r--src/global-handles.h138
-rw-r--r--src/globals.h4
-rw-r--r--src/handles-inl.h111
-rw-r--r--src/handles.cc348
-rw-r--r--src/handles.h88
-rw-r--r--src/hashmap.h6
-rw-r--r--src/heap-inl.h166
-rw-r--r--src/heap-profiler.cc135
-rw-r--r--src/heap-profiler.h55
-rw-r--r--src/heap.cc1252
-rw-r--r--src/heap.h1208
-rw-r--r--src/hydrogen-instructions.cc133
-rw-r--r--src/hydrogen-instructions.h252
-rw-r--r--src/hydrogen.cc1038
-rw-r--r--src/hydrogen.h103
-rw-r--r--src/ia32/assembler-ia32-inl.h17
-rw-r--r--src/ia32/assembler-ia32.cc179
-rw-r--r--src/ia32/assembler-ia32.h63
-rw-r--r--src/ia32/builtins-ia32.cc114
-rw-r--r--src/ia32/code-stubs-ia32.cc605
-rw-r--r--src/ia32/code-stubs-ia32.h47
-rw-r--r--src/ia32/codegen-ia32.cc343
-rw-r--r--src/ia32/codegen-ia32.h3
-rw-r--r--src/ia32/cpu-ia32.cc7
-rw-r--r--src/ia32/debug-ia32.cc13
-rw-r--r--src/ia32/deoptimizer-ia32.cc134
-rw-r--r--src/ia32/disasm-ia32.cc147
-rw-r--r--src/ia32/full-codegen-ia32.cc307
-rw-r--r--src/ia32/ic-ia32.cc155
-rw-r--r--src/ia32/lithium-codegen-ia32.cc657
-rw-r--r--src/ia32/lithium-codegen-ia32.h12
-rw-r--r--src/ia32/lithium-gap-resolver-ia32.cc2
-rw-r--r--src/ia32/lithium-ia32.cc134
-rw-r--r--src/ia32/lithium-ia32.h121
-rw-r--r--src/ia32/macro-assembler-ia32.cc180
-rw-r--r--src/ia32/macro-assembler-ia32.h16
-rw-r--r--src/ia32/regexp-macro-assembler-ia32.cc29
-rw-r--r--src/ia32/regexp-macro-assembler-ia32.h1
-rw-r--r--src/ia32/register-allocator-ia32.cc60
-rw-r--r--src/ia32/simulator-ia32.h8
-rw-r--r--src/ia32/stub-cache-ia32.cc774
-rw-r--r--src/ia32/virtual-frame-ia32.cc36
-rw-r--r--src/ia32/virtual-frame-ia32.h10
-rw-r--r--src/ic-inl.h5
-rw-r--r--src/ic.cc430
-rw-r--r--src/ic.h140
-rw-r--r--src/interpreter-irregexp.cc46
-rw-r--r--src/interpreter-irregexp.h3
-rw-r--r--src/isolate.cc895
-rw-r--r--src/isolate.h1308
-rw-r--r--src/jsregexp.cc183
-rw-r--r--src/jsregexp.h13
-rw-r--r--src/jump-target-heavy.cc13
-rw-r--r--src/jump-target-heavy.h6
-rw-r--r--src/jump-target-inl.h2
-rw-r--r--src/jump-target-light.cc6
-rw-r--r--src/lithium-allocator-inl.h2
-rw-r--r--src/lithium-allocator.cc70
-rw-r--r--src/lithium-allocator.h30
-rw-r--r--src/lithium.cc1
-rw-r--r--src/liveedit.cc230
-rw-r--r--src/liveedit.h9
-rw-r--r--src/liveobjectlist.h18
-rw-r--r--src/log-utils.cc157
-rw-r--r--src/log-utils.h69
-rw-r--r--src/log.cc539
-rw-r--r--src/log.h287
-rw-r--r--src/mark-compact.cc1015
-rw-r--r--src/mark-compact.h227
-rw-r--r--src/messages.cc30
-rw-r--r--src/messages.js29
-rw-r--r--src/mips/assembler-mips-inl.h190
-rw-r--r--src/mips/assembler-mips.cc1312
-rw-r--r--src/mips/assembler-mips.h705
-rw-r--r--src/mips/builtins-mips.cc143
-rw-r--r--src/mips/code-stubs-mips.cc752
-rw-r--r--src/mips/code-stubs-mips.h511
-rw-r--r--src/mips/codegen-mips-inl.h22
-rw-r--r--src/mips/codegen-mips.cc1568
-rw-r--r--src/mips/codegen-mips.h340
-rw-r--r--src/mips/constants-mips.cc64
-rw-r--r--src/mips/constants-mips.h278
-rw-r--r--src/mips/cpu-mips.cc23
-rw-r--r--src/mips/debug-mips.cc42
-rw-r--r--src/mips/deoptimizer-mips.cc91
-rw-r--r--src/mips/disasm-mips.cc422
-rw-r--r--src/mips/frames-mips.cc52
-rw-r--r--src/mips/frames-mips.h31
-rw-r--r--src/mips/full-codegen-mips.cc496
-rw-r--r--src/mips/ic-mips.cc126
-rw-r--r--src/mips/jump-target-mips.cc117
-rw-r--r--src/mips/lithium-codegen-mips.h65
-rw-r--r--src/mips/lithium-mips.h304
-rw-r--r--src/mips/macro-assembler-mips.cc2781
-rw-r--r--src/mips/macro-assembler-mips.h839
-rw-r--r--src/mips/regexp-macro-assembler-mips.cc478
-rw-r--r--src/mips/regexp-macro-assembler-mips.h250
-rw-r--r--src/mips/register-allocator-mips-inl.h3
-rw-r--r--src/mips/register-allocator-mips.h5
-rw-r--r--src/mips/simulator-mips.cc1230
-rw-r--r--src/mips/simulator-mips.h155
-rw-r--r--src/mips/stub-cache-mips.cc479
-rw-r--r--src/mips/virtual-frame-mips-inl.h (renamed from src/mips/fast-codegen-mips.cc)41
-rw-r--r--src/mips/virtual-frame-mips.cc286
-rw-r--r--src/mips/virtual-frame-mips.h606
-rw-r--r--src/mirror-debugger.js17
-rw-r--r--src/mksnapshot.cc4
-rw-r--r--src/objects-debug.cc32
-rw-r--r--src/objects-inl.h574
-rw-r--r--src/objects-printer.cc14
-rw-r--r--src/objects-visiting.cc2
-rw-r--r--src/objects-visiting.h30
-rw-r--r--src/objects.cc1343
-rw-r--r--src/objects.h309
-rw-r--r--src/parser.cc603
-rw-r--r--src/parser.h44
-rw-r--r--src/platform-cygwin.cc14
-rw-r--r--src/platform-freebsd.cc296
-rw-r--r--src/platform-linux.cc324
-rw-r--r--src/platform-macos.cc226
-rw-r--r--src/platform-nullos.cc12
-rw-r--r--src/platform-openbsd.cc29
-rw-r--r--src/platform-posix.cc8
-rw-r--r--src/platform-solaris.cc158
-rw-r--r--src/platform-tls-mac.h62
-rw-r--r--src/platform-tls-win32.h62
-rw-r--r--src/platform-tls.h50
-rw-r--r--src/platform-win32.cc252
-rw-r--r--src/platform.h69
-rw-r--r--src/preparse-data.cc2
-rw-r--r--src/preparser-api.cc10
-rw-r--r--src/preparser.cc2
-rw-r--r--src/prettyprinter.cc95
-rw-r--r--src/prettyprinter.h2
-rw-r--r--src/profile-generator.cc837
-rw-r--r--src/profile-generator.h213
-rw-r--r--src/property.cc6
-rw-r--r--src/property.h17
-rw-r--r--src/regexp-macro-assembler-irregexp.cc2
-rw-r--r--src/regexp-macro-assembler.cc47
-rw-r--r--src/regexp-macro-assembler.h17
-rw-r--r--src/regexp-stack.cc28
-rw-r--r--src/regexp-stack.h66
-rw-r--r--src/register-allocator-inl.h6
-rw-r--r--src/register-allocator.cc8
-rw-r--r--src/register-allocator.h20
-rw-r--r--src/rewriter.cc3
-rw-r--r--src/runtime-profiler.cc229
-rw-r--r--src/runtime-profiler.h147
-rw-r--r--src/runtime.cc3389
-rw-r--r--src/runtime.h83
-rw-r--r--src/safepoint-table.cc3
-rw-r--r--src/safepoint-table.h12
-rw-r--r--src/scanner-base.cc49
-rw-r--r--src/scanner-base.h33
-rwxr-xr-xsrc/scanner.cc8
-rw-r--r--src/scanner.h6
-rw-r--r--src/scopeinfo.cc27
-rw-r--r--src/scopeinfo.h41
-rw-r--r--src/scopes.cc98
-rw-r--r--src/scopes.h30
-rw-r--r--src/serialize.cc347
-rw-r--r--src/serialize.h77
-rw-r--r--src/small-pointer-list.h163
-rw-r--r--src/snapshot-common.cc2
-rw-r--r--src/snapshot.h4
-rw-r--r--src/spaces-inl.h55
-rw-r--r--src/spaces.cc632
-rw-r--r--src/spaces.h338
-rw-r--r--src/string-search.cc7
-rw-r--r--src/string-search.h41
-rw-r--r--src/string-stream.cc56
-rw-r--r--src/stub-cache.cc521
-rw-r--r--src/stub-cache.h304
-rw-r--r--src/token.cc6
-rw-r--r--src/token.h6
-rw-r--r--src/top.cc608
-rw-r--r--src/top.h608
-rw-r--r--src/type-info.cc124
-rw-r--r--src/type-info.h11
-rw-r--r--src/unicode.cc2
-rw-r--r--src/unicode.h2
-rw-r--r--src/utils.h3
-rw-r--r--src/v8-counters.cc29
-rw-r--r--src/v8-counters.h44
-rw-r--r--src/v8.cc145
-rw-r--r--src/v8.h5
-rw-r--r--src/v8globals.h30
-rw-r--r--src/v8memory.h (renamed from src/memory.h)0
-rw-r--r--src/v8natives.js67
-rw-r--r--src/v8threads.cc241
-rw-r--r--src/v8threads.h77
-rw-r--r--src/variables.h2
-rw-r--r--src/version.cc31
-rw-r--r--src/version.h4
-rw-r--r--src/virtual-frame-light-inl.h9
-rw-r--r--src/vm-state-inl.h38
-rw-r--r--src/vm-state.h12
-rw-r--r--src/win32-headers.h1
-rw-r--r--src/x64/assembler-x64-inl.h15
-rw-r--r--src/x64/assembler-x64.cc77
-rw-r--r--src/x64/assembler-x64.h73
-rw-r--r--src/x64/builtins-x64.cc56
-rw-r--r--src/x64/code-stubs-x64.cc735
-rw-r--r--src/x64/code-stubs-x64.h44
-rw-r--r--src/x64/codegen-x64.cc235
-rw-r--r--src/x64/codegen-x64.h3
-rw-r--r--src/x64/cpu-x64.cc2
-rw-r--r--src/x64/debug-x64.cc12
-rw-r--r--src/x64/deoptimizer-x64.cc56
-rw-r--r--src/x64/disasm-x64.cc53
-rw-r--r--src/x64/full-codegen-x64.cc479
-rw-r--r--src/x64/ic-x64.cc129
-rw-r--r--src/x64/lithium-codegen-x64.cc610
-rw-r--r--src/x64/lithium-codegen-x64.h32
-rw-r--r--src/x64/lithium-x64.cc120
-rw-r--r--src/x64/lithium-x64.h142
-rw-r--r--src/x64/macro-assembler-x64.cc608
-rw-r--r--src/x64/macro-assembler-x64.h172
-rw-r--r--src/x64/regexp-macro-assembler-x64.cc55
-rw-r--r--src/x64/regexp-macro-assembler-x64.h10
-rw-r--r--src/x64/register-allocator-x64-inl.h6
-rw-r--r--src/x64/register-allocator-x64.cc20
-rw-r--r--src/x64/simulator-x64.h8
-rw-r--r--src/x64/stub-cache-x64.cc633
-rw-r--r--src/x64/virtual-frame-x64.cc30
-rw-r--r--src/x64/virtual-frame-x64.h12
-rw-r--r--src/zone-inl.h48
-rw-r--r--src/zone.cc83
-rw-r--r--src/zone.h70
-rw-r--r--test/benchmarks/testcfg.py100
-rw-r--r--test/cctest/SConscript9
-rw-r--r--test/cctest/cctest.h5
-rw-r--r--test/cctest/cctest.status17
-rw-r--r--test/cctest/test-accessors.cc6
-rw-r--r--test/cctest/test-alloc.cc71
-rw-r--r--test/cctest/test-api.cc1136
-rw-r--r--test/cctest/test-assembler-arm.cc56
-rw-r--r--test/cctest/test-assembler-ia32.cc63
-rw-r--r--test/cctest/test-assembler-mips.cc1138
-rw-r--r--test/cctest/test-assembler-x64.cc13
-rw-r--r--test/cctest/test-ast.cc1
-rw-r--r--test/cctest/test-circular-queue.cc13
-rw-r--r--test/cctest/test-compiler.cc46
-rw-r--r--test/cctest/test-cpu-profiler.cc145
-rw-r--r--test/cctest/test-dataflow.cc1
-rw-r--r--test/cctest/test-debug.cc212
-rw-r--r--test/cctest/test-decls.cc2
-rw-r--r--test/cctest/test-deoptimization.cc49
-rw-r--r--test/cctest/test-disasm-arm.cc11
-rw-r--r--test/cctest/test-disasm-ia32.cc28
-rw-r--r--test/cctest/test-func-name-inference.cc14
-rw-r--r--test/cctest/test-heap-profiler.cc386
-rw-r--r--test/cctest/test-heap.cc384
-rw-r--r--test/cctest/test-liveedit.cc1
-rw-r--r--test/cctest/test-log-stack-tracer.cc38
-rw-r--r--test/cctest/test-log.cc222
-rwxr-xr-xtest/cctest/test-macro-assembler-x64.cc277
-rw-r--r--test/cctest/test-mark-compact.cc216
-rwxr-xr-xtest/cctest/test-parsing.cc29
-rw-r--r--test/cctest/test-platform-linux.cc1
-rw-r--r--test/cctest/test-platform-tls.cc66
-rw-r--r--test/cctest/test-platform-win32.cc1
-rw-r--r--test/cctest/test-profile-generator.cc2
-rw-r--r--test/cctest/test-regexp.cc94
-rw-r--r--test/cctest/test-reloc-info.cc29
-rw-r--r--test/cctest/test-serialize.cc87
-rw-r--r--test/cctest/test-sockets.cc11
-rw-r--r--test/cctest/test-spaces.cc76
-rw-r--r--test/cctest/test-strings.cc40
-rw-r--r--test/cctest/test-thread-termination.cc11
-rw-r--r--test/cctest/test-threads.cc8
-rw-r--r--test/cctest/test-utils.cc2
-rw-r--r--test/cctest/testcfg.py10
-rw-r--r--test/es5conform/es5conform.status13
-rw-r--r--test/es5conform/testcfg.py2
-rw-r--r--test/message/testcfg.py2
-rw-r--r--test/mjsunit/accessors-on-global-object.js6
-rw-r--r--test/mjsunit/bitops-info.js8
-rw-r--r--test/mjsunit/compiler/array-length.js4
-rw-r--r--test/mjsunit/compiler/pic.js2
-rw-r--r--test/mjsunit/compiler/regress-loadfield.js65
-rw-r--r--test/mjsunit/math-sqrt.js6
-rw-r--r--test/mjsunit/mjsunit.js67
-rw-r--r--test/mjsunit/mul-exhaustive.js140
-rw-r--r--test/mjsunit/negate-zero.js2
-rw-r--r--test/mjsunit/object-freeze.js18
-rw-r--r--test/mjsunit/object-prevent-extensions.js59
-rw-r--r--test/mjsunit/object-seal.js17
-rw-r--r--test/mjsunit/regress/regress-1233.js47
-rw-r--r--test/mjsunit/regress/regress-1236.js34
-rw-r--r--test/mjsunit/regress/regress-1237.js36
-rw-r--r--test/mjsunit/regress/regress-1240.js39
-rw-r--r--test/mjsunit/regress/regress-1257.js58
-rw-r--r--test/mjsunit/regress/regress-1278.js69
-rw-r--r--test/mjsunit/regress/regress-create-exception.js1
-rw-r--r--test/mjsunit/regress/regress-lazy-deopt-reloc.js52
-rw-r--r--test/mjsunit/sin-cos.js25
-rw-r--r--test/mjsunit/smi-negative-zero.js4
-rw-r--r--test/mjsunit/str-to-num.js2
-rw-r--r--test/mjsunit/strict-mode.js178
-rw-r--r--test/mjsunit/testcfg.py29
-rw-r--r--test/mjsunit/tools/tickprocessor-test-func-info.log6
-rw-r--r--test/mjsunit/tools/tickprocessor-test.log26
-rw-r--r--test/mozilla/mozilla.status2
-rw-r--r--test/mozilla/testcfg.py2
-rw-r--r--test/sputnik/testcfg.py2
-rw-r--r--test/test262/README16
-rw-r--r--test/test262/harness-adapt.js80
-rw-r--r--test/test262/test262.status1506
-rw-r--r--test/test262/testcfg.py123
-rwxr-xr-xtools/freebsd-tick-processor10
-rw-r--r--tools/gyp/v8.gyp41
-rwxr-xr-xtools/linux-tick-processor8
-rwxr-xr-xtools/test.py41
-rw-r--r--tools/tickprocessor.js27
-rw-r--r--tools/v8.xcodeproj/project.pbxproj24
-rw-r--r--tools/visual_studio/v8_base.vcproj14
-rw-r--r--tools/visual_studio/v8_base_arm.vcproj6
-rw-r--r--tools/visual_studio/v8_base_x64.vcproj6
428 files changed, 48145 insertions, 24600 deletions
diff --git a/AUTHORS b/AUTHORS
index 92b69cb6..843d1d2a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -24,12 +24,14 @@ Jay Freeman <saurik@saurik.com>
Joel Stanley <joel.stan@gmail.com>
John Jozwiak <jjozwiak@codeaurora.org>
Kun Zhang <zhangk@codeaurora.org>
-Matt Hanselman <mjhanselman@gmail.com>
Martyn Capewell <martyn.capewell@arm.com>
+Matt Hanselman <mjhanselman@gmail.com>
+Maxim Mossienko <maxim.mossienko@gmail.com>
Michael Smith <mike@w3.org>
Mike Gilbert <floppymaster@gmail.com>
Paolo Giarrusso <p.giarrusso@gmail.com>
Patrick Gansterer <paroga@paroga.com>
+Peter Varga <pvarga@inf.u-szeged.hu>
Rafal Krypa <rafal@krypa.net>
Rene Rebe <rene@exactcode.de>
Rodolph Perfetta <rodolph.perfetta@arm.com>
diff --git a/ChangeLog b/ChangeLog
index 44935caf..b5b44233 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,72 @@
+2011-03-30: Version 3.2.6
+
+ Fixed xcode build warning in shell.cc (out of order initialization).
+
+ Fixed null-pointer dereference in the compiler when running without
+ SSE3 support (Chromium issue 77654).
+
+ Fixed x64 compilation error due to some dead code. (Issue 1286)
+
+ Introduced scons target to build the preparser stand-alone example.
+
+ Made FreeBSD build and pass all tests.
+
+
+2011-03-28: Version 3.2.5
+
+ Fixed build with Irregexp interpreter (issue 1266).
+
+ Added Crankshaft support for external arrays.
+
+ Fixed two potential crash bugs.
+
+
+2011-03-23: Version 3.2.4
+
+ Added isolates which allows several V8 instances in the same process.
+ This is controlled through the new Isolate class in the API.
+
+ Implemented more of EcmaScript 5 strict mode.
+
+ Reduced the time it takes to make detailed heap snapshot.
+
+ Added a number of commands to the ARM simulator and enhanced the ARM
+ disassembler.
+
+
+2011-03-17: Version 3.2.3
+
+ Fixed a number of crash bugs.
+
+ Fixed Array::New(length) to return an array with a length (issue 1256).
+
+ Fixed FreeBSD build.
+
+ Changed __defineGetter__ to not throw (matching the behavior of Safari).
+
+ Implemented more of EcmaScript 5 strict mode.
+
+ Improved Crankshaft performance on all platforms.
+
+
+2011-03-14: Version 3.2.2
+
+ Fixed a number of crash and correctness bugs.
+
+ Improved Crankshaft performance on all platforms.
+
+ Fixed Crankshaft on Solaris/Illumos.
+
+
+2011-03-10: Version 3.2.1
+
+ Fixed a number of crash bugs.
+
+ Improved Crankshaft for x64 and ARM.
+
+ Implemented more of EcmaScript 5 strict mode.
+
+
2011-03-07: Version 3.2.0
Fixed a number of crash bugs.
diff --git a/SConstruct b/SConstruct
index 84707e98..2287c800 100644
--- a/SConstruct
+++ b/SConstruct
@@ -128,6 +128,9 @@ LIBRARY_FLAGS = {
'inspector:on': {
'CPPDEFINES': ['INSPECTOR'],
},
+ 'fasttls:on': {
+ 'CPPDEFINES': ['V8_FAST_TLS'],
+ },
'liveobjectlist:on': {
'CPPDEFINES': ['ENABLE_DEBUGGER_SUPPORT', 'INSPECTOR',
'LIVE_OBJECT_LIST', 'OBJECT_PRINT'],
@@ -174,6 +177,7 @@ LIBRARY_FLAGS = {
'CPPPATH' : ['/usr/local/include'],
'LIBPATH' : ['/usr/local/lib'],
'CCFLAGS': ['-ansi'],
+ 'LIBS': ['execinfo']
},
'os:openbsd': {
'CPPPATH' : ['/usr/local/include'],
@@ -220,14 +224,37 @@ LIBRARY_FLAGS = {
},
'arch:mips': {
'CPPDEFINES': ['V8_TARGET_ARCH_MIPS'],
+ 'mips_arch_variant:mips32r2': {
+ 'CPPDEFINES': ['_MIPS_ARCH_MIPS32R2']
+ },
'simulator:none': {
- 'CCFLAGS': ['-EL', '-mips32r2', '-Wa,-mips32r2', '-fno-inline'],
- 'LDFLAGS': ['-EL']
+ 'CCFLAGS': ['-EL'],
+ 'LINKFLAGS': ['-EL'],
+ 'mips_arch_variant:mips32r2': {
+ 'CCFLAGS': ['-mips32r2', '-Wa,-mips32r2']
+ },
+ 'mips_arch_variant:mips32r1': {
+ 'CCFLAGS': ['-mips32', '-Wa,-mips32']
+ },
+ 'library:static': {
+ 'LINKFLAGS': ['-static', '-static-libgcc']
+ },
+ 'mipsabi:softfloat': {
+ 'CCFLAGS': ['-msoft-float'],
+ 'LINKFLAGS': ['-msoft-float']
+ },
+ 'mipsabi:hardfloat': {
+ 'CCFLAGS': ['-mhard-float'],
+ 'LINKFLAGS': ['-mhard-float']
+ }
}
},
'simulator:mips': {
'CCFLAGS': ['-m32'],
'LINKFLAGS': ['-m32'],
+ 'mipsabi:softfloat': {
+ 'CPPDEFINES': ['__mips_soft_float=1'],
+ }
},
'arch:x64': {
'CPPDEFINES': ['V8_TARGET_ARCH_X64'],
@@ -341,6 +368,9 @@ V8_EXTRA_FLAGS = {
},
'arch:mips': {
'CPPDEFINES': ['V8_TARGET_ARCH_MIPS'],
+ 'mips_arch_variant:mips32r2': {
+ 'CPPDEFINES': ['_MIPS_ARCH_MIPS32R2']
+ },
},
'disassembler:on': {
'CPPDEFINES': ['ENABLE_DISASSEMBLER']
@@ -474,17 +504,17 @@ SAMPLE_FLAGS = {
'LIBS': ['pthread'],
},
'os:freebsd': {
- 'LIBPATH' : ['/usr/local/lib'],
- 'LIBS': ['execinfo', 'pthread']
+ 'LIBPATH' : ['/usr/local/lib'],
+ 'LIBS': ['execinfo', 'pthread']
},
'os:solaris': {
- 'LIBPATH' : ['/usr/local/lib'],
- 'LIBS': ['m', 'pthread', 'socket', 'nsl', 'rt'],
- 'LINKFLAGS': ['-mt']
+ 'LIBPATH' : ['/usr/local/lib'],
+ 'LIBS': ['m', 'pthread', 'socket', 'nsl', 'rt'],
+ 'LINKFLAGS': ['-mt']
},
'os:openbsd': {
- 'LIBPATH' : ['/usr/local/lib'],
- 'LIBS': ['execinfo', 'pthread']
+ 'LIBPATH' : ['/usr/local/lib'],
+ 'LIBS': ['execinfo', 'pthread']
},
'os:win32': {
'LIBS': ['winmm', 'ws2_32']
@@ -577,11 +607,155 @@ SAMPLE_FLAGS = {
}
},
'arch:ia32': {
- 'CPPDEFINES': ['V8_TARGET_ARCH_IA32'],
+ 'CPPDEFINES': ['V8_TARGET_ARCH_IA32', 'WIN32'],
+ 'LINKFLAGS': ['/MACHINE:X86']
+ },
+ 'arch:x64': {
+ 'CPPDEFINES': ['V8_TARGET_ARCH_X64', 'WIN32'],
+ 'LINKFLAGS': ['/MACHINE:X64', '/STACK:2091752']
+ },
+ 'mode:debug': {
+ 'CCFLAGS': ['/Od'],
+ 'LINKFLAGS': ['/DEBUG'],
+ 'CPPDEFINES': ['DEBUG'],
+ 'msvcrt:static': {
+ 'CCFLAGS': ['/MTd']
+ },
+ 'msvcrt:shared': {
+ 'CCFLAGS': ['/MDd']
+ }
+ }
+ }
+}
+
+
+PREPARSER_FLAGS = {
+ 'all': {
+ 'CPPPATH': [join(abspath('.'), 'include'), join(abspath('.'), 'src')]
+ },
+ 'gcc': {
+ 'all': {
+ 'LIBPATH': ['.'],
+ 'CCFLAGS': ['-fno-rtti', '-fno-exceptions']
+ },
+ 'os:win32': {
+ 'LIBS': ['winmm', 'ws2_32']
+ },
+ 'os:android': {
+ 'CPPDEFINES': ['ANDROID', '__ARM_ARCH_5__', '__ARM_ARCH_5T__',
+ '__ARM_ARCH_5E__', '__ARM_ARCH_5TE__'],
+ 'CCFLAGS': ANDROID_FLAGS,
+ 'CPPPATH': ANDROID_INCLUDES,
+ 'LIBPATH': [ANDROID_TOP + '/out/target/product/generic/obj/lib',
+ ANDROID_TOP + '/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/lib/gcc/arm-eabi/4.4.0/interwork'],
+ 'LINKFLAGS': ANDROID_LINKFLAGS,
+ 'LIBS': ['log', 'c', 'stdc++', 'm', 'gcc'],
+ 'mode:release': {
+ 'CPPDEFINES': ['SK_RELEASE', 'NDEBUG']
+ }
+ },
+ 'arch:arm': {
+ 'LINKFLAGS': ARM_LINK_FLAGS
+ },
+ 'arch:ia32': {
+ 'CCFLAGS': ['-m32'],
+ 'LINKFLAGS': ['-m32']
+ },
+ 'arch:x64': {
+ 'CCFLAGS': ['-m64'],
+ 'LINKFLAGS': ['-m64']
+ },
+ 'arch:mips': {
+ 'CPPDEFINES': ['V8_TARGET_ARCH_MIPS'],
+ 'mips_arch_variant:mips32r2': {
+ 'CPPDEFINES': ['_MIPS_ARCH_MIPS32R2']
+ },
+ 'simulator:none': {
+ 'CCFLAGS': ['-EL'],
+ 'LINKFLAGS': ['-EL'],
+ 'mips_arch_variant:mips32r2': {
+ 'CCFLAGS': ['-mips32r2', '-Wa,-mips32r2']
+ },
+ 'mips_arch_variant:mips32r1': {
+ 'CCFLAGS': ['-mips32', '-Wa,-mips32']
+ },
+ 'library:static': {
+ 'LINKFLAGS': ['-static', '-static-libgcc']
+ },
+ 'mipsabi:softfloat': {
+ 'CCFLAGS': ['-msoft-float'],
+ 'LINKFLAGS': ['-msoft-float']
+ },
+ 'mipsabi:hardfloat': {
+ 'CCFLAGS': ['-mhard-float'],
+ 'LINKFLAGS': ['-mhard-float']
+ }
+ }
+ },
+ 'simulator:arm': {
+ 'CCFLAGS': ['-m32'],
+ 'LINKFLAGS': ['-m32']
+ },
+ 'simulator:mips': {
+ 'CCFLAGS': ['-m32'],
+ 'LINKFLAGS': ['-m32'],
+ 'mipsabi:softfloat': {
+ 'CPPDEFINES': ['__mips_soft_float=1'],
+ }
+ },
+ 'mode:release': {
+ 'CCFLAGS': ['-O2']
+ },
+ 'mode:debug': {
+ 'CCFLAGS': ['-g', '-O0'],
+ 'CPPDEFINES': ['DEBUG']
+ },
+ },
+ 'msvc': {
+ 'all': {
+ 'LIBS': ['winmm', 'ws2_32']
+ },
+ 'verbose:off': {
+ 'CCFLAGS': ['/nologo'],
+ 'LINKFLAGS': ['/NOLOGO']
+ },
+ 'verbose:on': {
+ 'LINKFLAGS': ['/VERBOSE']
+ },
+ 'library:shared': {
+ 'CPPDEFINES': ['USING_V8_SHARED']
+ },
+ 'prof:on': {
+ 'LINKFLAGS': ['/MAP']
+ },
+ 'mode:release': {
+ 'CCFLAGS': ['/O2'],
+ 'LINKFLAGS': ['/OPT:REF', '/OPT:ICF'],
+ 'msvcrt:static': {
+ 'CCFLAGS': ['/MT']
+ },
+ 'msvcrt:shared': {
+ 'CCFLAGS': ['/MD']
+ },
+ 'msvcltcg:on': {
+ 'CCFLAGS': ['/GL'],
+ 'pgo:off': {
+ 'LINKFLAGS': ['/LTCG'],
+ },
+ },
+ 'pgo:instrument': {
+ 'LINKFLAGS': ['/LTCG:PGI']
+ },
+ 'pgo:optimize': {
+ 'LINKFLAGS': ['/LTCG:PGO']
+ }
+ },
+ 'arch:ia32': {
+ 'CPPDEFINES': ['V8_TARGET_ARCH_IA32', 'WIN32'],
'LINKFLAGS': ['/MACHINE:X86']
},
'arch:x64': {
- 'CPPDEFINES': ['V8_TARGET_ARCH_X64'],
+ 'CPPDEFINES': ['V8_TARGET_ARCH_X64', 'WIN32'],
'LINKFLAGS': ['/MACHINE:X64', '/STACK:2091752']
},
'mode:debug': {
@@ -784,6 +958,12 @@ SIMPLE_OPTIONS = {
'default': 'off',
'help': 'enable the disassembler to inspect generated code'
},
+ 'fasttls': {
+ 'values': ['on', 'off'],
+ 'default': 'on',
+ 'help': 'enable fast thread local storage support '
+ '(if available on the current architecture/platform)'
+ },
'sourcesignatures': {
'values': ['MD5', 'timestamp'],
'default': 'MD5',
@@ -808,6 +988,16 @@ SIMPLE_OPTIONS = {
'values': ['off', 'instrument', 'optimize'],
'default': 'off',
'help': 'select profile guided optimization variant',
+ },
+ 'mipsabi': {
+ 'values': ['hardfloat', 'softfloat', 'none'],
+ 'default': 'hardfloat',
+ 'help': 'generate calling conventiont according to selected mips ABI'
+ },
+ 'mips_arch_variant': {
+ 'values': ['mips32r2', 'mips32r1'],
+ 'default': 'mips32r2',
+ 'help': 'mips variant'
}
}
@@ -926,6 +1116,7 @@ class BuildContext(object):
self.options = options
self.env_overrides = env_overrides
self.samples = samples
+ self.preparser_targets = []
self.use_snapshot = (options['snapshot'] != 'off')
self.build_snapshot = (options['snapshot'] == 'on')
self.flags = None
@@ -1004,11 +1195,12 @@ def PostprocessOptions(options, os):
if 'msvcltcg' in ARGUMENTS:
print "Warning: forcing msvcltcg on as it is required for pgo (%s)" % options['pgo']
options['msvcltcg'] = 'on'
- if options['arch'] == 'mips':
- if ('regexp' in ARGUMENTS) and options['regexp'] == 'native':
- # Print a warning if native regexp is specified for mips
- print "Warning: forcing regexp to interpreted for mips"
- options['regexp'] = 'interpreted'
+ if (options['simulator'] == 'mips' and options['mipsabi'] != 'softfloat'):
+ # Print a warning if soft-float ABI is not selected for mips simulator
+ print "Warning: forcing soft-float mips ABI when running on simulator"
+ options['mipsabi'] = 'softfloat'
+ if (options['mipsabi'] != 'none') and (options['arch'] != 'mips') and (options['simulator'] != 'mips'):
+ options['mipsabi'] = 'none'
if options['liveobjectlist'] == 'on':
if (options['debuggersupport'] != 'on') or (options['mode'] == 'release'):
# Print a warning that liveobjectlist will implicitly enable the debugger
@@ -1055,6 +1247,7 @@ def BuildSpecific(env, mode, env_overrides):
dtoa_flags = context.AddRelevantFlags(library_flags, DTOA_EXTRA_FLAGS)
cctest_flags = context.AddRelevantFlags(v8_flags, CCTEST_EXTRA_FLAGS)
sample_flags = context.AddRelevantFlags(user_environ, SAMPLE_FLAGS)
+ preparser_flags = context.AddRelevantFlags(user_environ, PREPARSER_FLAGS)
d8_flags = context.AddRelevantFlags(library_flags, D8_FLAGS)
context.flags = {
@@ -1063,13 +1256,15 @@ def BuildSpecific(env, mode, env_overrides):
'dtoa': dtoa_flags,
'cctest': cctest_flags,
'sample': sample_flags,
- 'd8': d8_flags
+ 'd8': d8_flags,
+ 'preparser': preparser_flags
}
# Generate library base name.
target_id = mode
suffix = SUFFIXES[target_id]
library_name = 'v8' + suffix
+ preparser_library_name = 'v8preparser' + suffix
version = GetVersion()
if context.options['soname'] == 'on':
# When building shared object with SONAME version the library name.
@@ -1083,7 +1278,7 @@ def BuildSpecific(env, mode, env_overrides):
env['SONAME'] = soname
# Build the object files by invoking SCons recursively.
- (object_files, shell_files, mksnapshot) = env.SConscript(
+ (object_files, shell_files, mksnapshot, preparser_files) = env.SConscript(
join('src', 'SConscript'),
build_dir=join('obj', target_id),
exports='context',
@@ -1098,13 +1293,20 @@ def BuildSpecific(env, mode, env_overrides):
context.ApplyEnvOverrides(env)
if context.options['library'] == 'static':
library = env.StaticLibrary(library_name, object_files)
+ preparser_library = env.StaticLibrary(preparser_library_name,
+ preparser_files)
else:
# There seems to be a glitch in the way scons decides where to put
# PDB files when compiling using MSVC so we specify it manually.
# This should not affect any other platforms.
pdb_name = library_name + '.dll.pdb'
library = env.SharedLibrary(library_name, object_files, PDB=pdb_name)
+ preparser_pdb_name = preparser_library_name + '.dll.pdb';
+ preparser_library = env.SharedLibrary(preparser_library_name,
+ preparser_files,
+ PDB=preparser_pdb_name)
context.library_targets.append(library)
+ context.library_targets.append(preparser_library)
d8_env = Environment()
d8_env.Replace(**context.flags['d8'])
@@ -1138,6 +1340,21 @@ def BuildSpecific(env, mode, env_overrides):
)
context.cctest_targets.append(cctest_program)
+ preparser_env = env.Copy()
+ preparser_env.Replace(**context.flags['preparser'])
+ preparser_env.Prepend(LIBS=[preparser_library_name])
+ context.ApplyEnvOverrides(preparser_env)
+ preparser_object = preparser_env.SConscript(
+ join('preparser', 'SConscript'),
+ build_dir=join('obj', 'preparser', target_id),
+ exports='context',
+ duplicate=False
+ )
+ preparser_name = join('obj', 'preparser', target_id, 'preparser' + suffix)
+ preparser_program = preparser_env.Program(preparser_name, preparser_object);
+ preparser_env.Depends(preparser_program, preparser_library)
+ context.preparser_targets.append(preparser_program)
+
return context
@@ -1154,6 +1371,7 @@ def Build():
mksnapshots = []
cctests = []
samples = []
+ preparsers = []
d8s = []
modes = SplitList(env['mode'])
for mode in modes:
@@ -1162,6 +1380,7 @@ def Build():
mksnapshots += context.mksnapshot_targets
cctests += context.cctest_targets
samples += context.sample_targets
+ preparsers += context.preparser_targets
d8s += context.d8_targets
env.Alias('library', libraries)
@@ -1169,6 +1388,7 @@ def Build():
env.Alias('cctests', cctests)
env.Alias('sample', samples)
env.Alias('d8', d8s)
+ env.Alias('preparser', preparsers)
if env['sample']:
env.Default('sample')
diff --git a/include/v8-debug.h b/include/v8-debug.h
index f17b8485..0bdff846 100755
--- a/include/v8-debug.h
+++ b/include/v8-debug.h
@@ -227,7 +227,7 @@ class EXPORT Debug {
* Debug message callback function.
*
* \param message the debug message handler message object
-
+ *
* A MessageHandler does not take possession of the message data,
* and must not rely on the data persisting after the handler returns.
*/
@@ -253,25 +253,35 @@ class EXPORT Debug {
static bool SetDebugEventListener(v8::Handle<v8::Object> that,
Handle<Value> data = Handle<Value>());
- // Schedule a debugger break to happen when JavaScript code is run.
- static void DebugBreak();
+ // Schedule a debugger break to happen when JavaScript code is run
+ // in the given isolate. If no isolate is provided the default
+ // isolate is used.
+ static void DebugBreak(Isolate* isolate = NULL);
- // Remove scheduled debugger break if it has not happened yet.
- static void CancelDebugBreak();
+ // Remove scheduled debugger break in given isolate if it has not
+ // happened yet. If no isolate is provided the default isolate is
+ // used.
+ static void CancelDebugBreak(Isolate* isolate = NULL);
- // Break execution of JavaScript (this method can be invoked from a
- // non-VM thread) for further client command execution on a VM
- // thread. Client data is then passed in EventDetails to
- // EventCallback at the moment when the VM actually stops.
- static void DebugBreakForCommand(ClientData* data = NULL);
+ // Break execution of JavaScript in the given isolate (this method
+ // can be invoked from a non-VM thread) for further client command
+ // execution on a VM thread. Client data is then passed in
+ // EventDetails to EventCallback at the moment when the VM actually
+ // stops. If no isolate is provided the default isolate is used.
+ static void DebugBreakForCommand(ClientData* data = NULL,
+ Isolate* isolate = NULL);
// Message based interface. The message protocol is JSON. NOTE the message
// handler thread is not supported any more parameter must be false.
static void SetMessageHandler(MessageHandler handler,
bool message_handler_thread = false);
static void SetMessageHandler2(MessageHandler2 handler);
+
+ // If no isolate is provided the default isolate is
+ // used.
static void SendCommand(const uint16_t* command, int length,
- ClientData* client_data = NULL);
+ ClientData* client_data = NULL,
+ Isolate* isolate = NULL);
// Dispatch interface.
static void SetHostDispatchHandler(HostDispatchHandler handler,
diff --git a/include/v8-profiler.h b/include/v8-profiler.h
index 675a2298..db56e268 100644
--- a/include/v8-profiler.h
+++ b/include/v8-profiler.h
@@ -131,6 +131,16 @@ class V8EXPORT CpuProfile {
/** Returns the root node of the top down call tree. */
const CpuProfileNode* GetTopDownRoot() const;
+
+ /**
+ * Deletes the profile and removes it from CpuProfiler's list.
+ * All pointers to nodes previously returned become invalid.
+ * Profiles with the same uid but obtained using different
+ * security token are not deleted, but become inaccessible
+ * using FindProfile method. It is embedder's responsibility
+ * to call Delete on these profiles.
+ */
+ void Delete();
};
@@ -181,6 +191,13 @@ class V8EXPORT CpuProfiler {
static const CpuProfile* StopProfiling(
Handle<String> title,
Handle<Value> security_token = Handle<Value>());
+
+ /**
+ * Deletes all existing profiles, also cancelling all profiling
+ * activity. All previously returned pointers to profiles and their
+ * contents become invalid after this call.
+ */
+ static void DeleteAllProfiles();
};
@@ -223,36 +240,21 @@ class V8EXPORT HeapGraphEdge {
};
-class V8EXPORT HeapGraphPath {
- public:
- /** Returns the number of edges in the path. */
- int GetEdgesCount() const;
-
- /** Returns an edge from the path. */
- const HeapGraphEdge* GetEdge(int index) const;
-
- /** Returns origin node. */
- const HeapGraphNode* GetFromNode() const;
-
- /** Returns destination node. */
- const HeapGraphNode* GetToNode() const;
-};
-
-
/**
* HeapGraphNode represents a node in a heap graph.
*/
class V8EXPORT HeapGraphNode {
public:
enum Type {
- kHidden = 0, // Hidden node, may be filtered when shown to user.
- kArray = 1, // An array of elements.
- kString = 2, // A string.
- kObject = 3, // A JS object (except for arrays and strings).
- kCode = 4, // Compiled code.
- kClosure = 5, // Function closure.
- kRegExp = 6, // RegExp.
- kHeapNumber = 7 // Number stored in the heap.
+ kHidden = 0, // Hidden node, may be filtered when shown to user.
+ kArray = 1, // An array of elements.
+ kString = 2, // A string.
+ kObject = 3, // A JS object (except for arrays and strings).
+ kCode = 4, // Compiled code.
+ kClosure = 5, // Function closure.
+ kRegExp = 6, // RegExp.
+ kHeapNumber = 7, // Number stored in the heap.
+ kNative = 8 // Native object (not from V8 heap).
};
/** Returns node type (see HeapGraphNode::Type). */
@@ -307,12 +309,6 @@ class V8EXPORT HeapGraphNode {
/** Returns a retainer by index. */
const HeapGraphEdge* GetRetainer(int index) const;
- /** Returns the number of simple retaining paths from the root to the node. */
- int GetRetainingPathsCount() const;
-
- /** Returns a retaining path by index. */
- const HeapGraphPath* GetRetainingPath(int index) const;
-
/**
* Returns a dominator node. This is the node that participates in every
* path from the snapshot root to the current node.
@@ -321,16 +317,6 @@ class V8EXPORT HeapGraphNode {
};
-class V8EXPORT HeapSnapshotsDiff {
- public:
- /** Returns the root node for added nodes. */
- const HeapGraphNode* GetAdditionsRoot() const;
-
- /** Returns the root node for deleted nodes. */
- const HeapGraphNode* GetDeletionsRoot() const;
-};
-
-
/**
* HeapSnapshots record the state of the JS heap at some moment.
*/
@@ -361,10 +347,11 @@ class V8EXPORT HeapSnapshot {
const HeapGraphNode* GetNodeById(uint64_t id) const;
/**
- * Returns a diff between this snapshot and another one. Only snapshots
- * of the same type can be compared.
+ * Deletes the snapshot and removes it from HeapProfiler's list.
+ * All pointers to nodes, edges and paths previously returned become
+ * invalid.
*/
- const HeapSnapshotsDiff* CompareWith(const HeapSnapshot* snapshot) const;
+ void Delete();
/**
* Prepare a serialized representation of the snapshot. The result
@@ -392,11 +379,22 @@ class V8EXPORT HeapSnapshot {
};
+class RetainedObjectInfo;
+
/**
* Interface for controlling heap profiling.
*/
class V8EXPORT HeapProfiler {
public:
+ /**
+ * Callback function invoked for obtaining RetainedObjectInfo for
+ * the given JavaScript wrapper object. It is prohibited to enter V8
+ * while the callback is running: only getters on the handle and
+ * GetPointerFromInternalField on the objects are allowed.
+ */
+ typedef RetainedObjectInfo* (*WrapperInfoCallback)
+ (uint16_t class_id, Handle<Value> wrapper);
+
/** Returns the number of snapshots taken. */
static int GetSnapshotsCount();
@@ -414,6 +412,87 @@ class V8EXPORT HeapProfiler {
Handle<String> title,
HeapSnapshot::Type type = HeapSnapshot::kFull,
ActivityControl* control = NULL);
+
+ /**
+ * Deletes all snapshots taken. All previously returned pointers to
+ * snapshots and their contents become invalid after this call.
+ */
+ static void DeleteAllSnapshots();
+
+ /** Binds a callback to embedder's class ID. */
+ static void DefineWrapperClass(
+ uint16_t class_id,
+ WrapperInfoCallback callback);
+
+ /**
+ * Default value of persistent handle class ID. Must not be used to
+ * define a class. Can be used to reset a class of a persistent
+ * handle.
+ */
+ static const uint16_t kPersistentHandleNoClassId = 0;
+};
+
+
+/**
+ * Interface for providing information about embedder's objects
+ * held by global handles. This information is reported in two ways:
+ *
+ * 1. When calling AddObjectGroup, an embedder may pass
+ * RetainedObjectInfo instance describing the group. To collect
+ * this information while taking a heap snapshot, V8 calls GC
+ * prologue and epilogue callbacks.
+ *
+ * 2. When a heap snapshot is collected, V8 additionally
+ * requests RetainedObjectInfos for persistent handles that
+ * were not previously reported via AddObjectGroup.
+ *
+ * Thus, if an embedder wants to provide information about native
+ * objects for heap snapshots, he can do it in a GC prologue
+ * handler, and / or by assigning wrapper class ids in the following way:
+ *
+ * 1. Bind a callback to class id by calling DefineWrapperClass.
+ * 2. Call SetWrapperClassId on certain persistent handles.
+ *
+ * V8 takes ownership of RetainedObjectInfo instances passed to it and
+ * keeps them alive only during snapshot collection. Afterwards, they
+ * are freed by calling the Dispose class function.
+ */
+class V8EXPORT RetainedObjectInfo { // NOLINT
+ public:
+ /** Called by V8 when it no longer needs an instance. */
+ virtual void Dispose() = 0;
+
+ /** Returns whether two instances are equivalent. */
+ virtual bool IsEquivalent(RetainedObjectInfo* other) = 0;
+
+ /**
+ * Returns hash value for the instance. Equivalent instances
+ * must have the same hash value.
+ */
+ virtual intptr_t GetHash() = 0;
+
+ /**
+ * Returns human-readable label. It must be a NUL-terminated UTF-8
+ * encoded string. V8 copies its contents during a call to GetLabel.
+ */
+ virtual const char* GetLabel() = 0;
+
+ /**
+ * Returns element count in case if a global handle retains
+ * a subgraph by holding one of its nodes.
+ */
+ virtual intptr_t GetElementCount() { return -1; }
+
+ /** Returns embedder's object size in bytes. */
+ virtual intptr_t GetSizeInBytes() { return -1; }
+
+ protected:
+ RetainedObjectInfo() {}
+ virtual ~RetainedObjectInfo() {}
+
+ private:
+ RetainedObjectInfo(const RetainedObjectInfo&);
+ RetainedObjectInfo& operator=(const RetainedObjectInfo&);
};
diff --git a/include/v8-testing.h b/include/v8-testing.h
index 4db30a44..245f74d8 100644
--- a/include/v8-testing.h
+++ b/include/v8-testing.h
@@ -87,6 +87,11 @@ class V8EXPORT Testing {
* should be between 0 and one less than the result from GetStressRuns()
*/
static void PrepareStressRun(int run);
+
+ /**
+ * Force deoptimization of all functions.
+ */
+ static void DeoptimizeAll();
};
diff --git a/include/v8.h b/include/v8.h
index 83a57442..62d1085c 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -110,7 +110,8 @@ namespace internal {
class Arguments;
class Object;
class Heap;
-class Top;
+class HeapObject;
+class Isolate;
}
@@ -396,6 +397,12 @@ template <class T> class Persistent : public Handle<T> {
*/
inline bool IsWeak() const;
+ /**
+ * Assigns a wrapper class ID to the handle. See RetainedObjectInfo
+ * interface description in v8-profiler.h for details.
+ */
+ inline void SetWrapperClassId(uint16_t class_id);
+
private:
friend class ImplementationUtilities;
friend class ObjectTemplate;
@@ -437,6 +444,8 @@ class V8EXPORT HandleScope {
* Creates a new handle with the given value.
*/
static internal::Object** CreateHandle(internal::Object* value);
+ // Faster version, uses HeapObject to obtain the current Isolate.
+ static internal::Object** CreateHandle(internal::HeapObject* value);
private:
// Make it impossible to create heap-allocated or illegal handle
@@ -453,7 +462,6 @@ class V8EXPORT HandleScope {
internal::Object** next;
internal::Object** limit;
int level;
-
inline void Initialize() {
next = limit = NULL;
level = 0;
@@ -462,6 +470,7 @@ class V8EXPORT HandleScope {
void Leave();
+ internal::Isolate* isolate_;
internal::Object** prev_next_;
internal::Object** prev_limit_;
@@ -1435,7 +1444,8 @@ enum ExternalArrayType {
kExternalUnsignedShortArray,
kExternalIntArray,
kExternalUnsignedIntArray,
- kExternalFloatArray
+ kExternalFloatArray,
+ kExternalPixelArray
};
/**
@@ -1699,7 +1709,12 @@ class Array : public Object {
*/
V8EXPORT Local<Object> CloneElementAt(uint32_t index);
+ /**
+ * Creates a JavaScript array with the given length. If the length
+ * is negative the returned array will have length 0.
+ */
V8EXPORT static Local<Array> New(int length = 0);
+
static inline Array* Cast(Value* obj);
private:
V8EXPORT Array();
@@ -2533,6 +2548,92 @@ class V8EXPORT HeapStatistics {
};
+class RetainedObjectInfo;
+
+/**
+ * Isolate represents an isolated instance of the V8 engine. V8
+ * isolates have completely separate states. Objects from one isolate
+ * must not be used in other isolates. When V8 is initialized a
+ * default isolate is implicitly created and entered. The embedder
+ * can create additional isolates and use them in parallel in multiple
+ * threads. An isolate can be entered by at most one thread at any
+ * given time. The Locker/Unlocker API can be used to synchronize.
+ */
+class V8EXPORT Isolate {
+ public:
+ /**
+ * Stack-allocated class which sets the isolate for all operations
+ * executed within a local scope.
+ */
+ class V8EXPORT Scope {
+ public:
+ explicit Scope(Isolate* isolate) : isolate_(isolate) {
+ isolate->Enter();
+ }
+
+ ~Scope() { isolate_->Exit(); }
+
+ private:
+ Isolate* const isolate_;
+
+ // Prevent copying of Scope objects.
+ Scope(const Scope&);
+ Scope& operator=(const Scope&);
+ };
+
+ /**
+ * Creates a new isolate. Does not change the currently entered
+ * isolate.
+ *
+ * When an isolate is no longer used its resources should be freed
+ * by calling Dispose(). Using the delete operator is not allowed.
+ */
+ static Isolate* New();
+
+ /**
+ * Returns the entered isolate for the current thread or NULL in
+ * case there is no current isolate.
+ */
+ static Isolate* GetCurrent();
+
+ /**
+ * Methods below this point require holding a lock (using Locker) in
+ * a multi-threaded environment.
+ */
+
+ /**
+ * Sets this isolate as the entered one for the current thread.
+ * Saves the previously entered one (if any), so that it can be
+ * restored when exiting. Re-entering an isolate is allowed.
+ */
+ void Enter();
+
+ /**
+ * Exits this isolate by restoring the previously entered one in the
+ * current thread. The isolate may still stay the same, if it was
+ * entered more than once.
+ *
+ * Requires: this == Isolate::GetCurrent().
+ */
+ void Exit();
+
+ /**
+ * Disposes the isolate. The isolate must not be entered by any
+ * thread to be disposable.
+ */
+ void Dispose();
+
+ private:
+
+ Isolate();
+ Isolate(const Isolate&);
+ ~Isolate();
+ Isolate& operator=(const Isolate&);
+ void* operator new(size_t size);
+ void operator delete(void*, size_t);
+};
+
+
/**
* Container class for static utility functions.
*/
@@ -2702,8 +2803,22 @@ class V8EXPORT V8 {
* intended to be used in the before-garbage-collection callback
* function, for instance to simulate DOM tree connections among JS
* wrapper objects.
+ * See v8-profiler.h for RetainedObjectInfo interface description.
+ */
+ static void AddObjectGroup(Persistent<Value>* objects,
+ size_t length,
+ RetainedObjectInfo* info = NULL);
+
+ /**
+ * Allows the host application to declare implicit references between
+ * the objects: if |parent| is alive, all |children| are alive too.
+ * After each garbage collection, all implicit references
+ * are removed. It is intended to be used in the before-garbage-collection
+ * callback function.
*/
- static void AddObjectGroup(Persistent<Value>* objects, size_t length);
+ static void AddImplicitReferences(Persistent<Object> parent,
+ Persistent<Value>* children,
+ size_t length);
/**
* Initializes from snapshot if possible. Otherwise, attempts to
@@ -2844,12 +2959,16 @@ class V8EXPORT V8 {
static void TerminateExecution(int thread_id);
/**
- * Forcefully terminate the current thread of JavaScript execution.
+ * Forcefully terminate the current thread of JavaScript execution
+ * in the given isolate. If no isolate is provided, the default
+ * isolate is used.
*
* This method can be used by any thread even if that thread has not
* acquired the V8 lock with a Locker object.
+ *
+ * \param isolate The isolate in which to terminate the current JS execution.
*/
- static void TerminateExecution();
+ static void TerminateExecution(Isolate* isolate = NULL);
/**
* Is V8 terminating JavaScript execution.
@@ -2912,6 +3031,8 @@ class V8EXPORT V8 {
static void ClearWeak(internal::Object** global_handle);
static bool IsGlobalNearDeath(internal::Object** global_handle);
static bool IsGlobalWeak(internal::Object** global_handle);
+ static void SetWrapperClassId(internal::Object** global_handle,
+ uint16_t class_id);
template <class T> friend class Handle;
template <class T> friend class Local;
@@ -3025,7 +3146,7 @@ class V8EXPORT TryCatch {
bool capture_message_ : 1;
bool rethrow_ : 1;
- friend class v8::internal::Top;
+ friend class v8::internal::Isolate;
};
@@ -3188,15 +3309,26 @@ class V8EXPORT Context {
/**
* Multiple threads in V8 are allowed, but only one thread at a time
- * is allowed to use V8. The definition of 'using V8' includes
- * accessing handles or holding onto object pointers obtained from V8
- * handles. It is up to the user of V8 to ensure (perhaps with
- * locking) that this constraint is not violated.
+ * is allowed to use any given V8 isolate. See Isolate class
+ * comments. The definition of 'using V8 isolate' includes
+ * accessing handles or holding onto object pointers obtained
+ * from V8 handles while in the particular V8 isolate. It is up
+ * to the user of V8 to ensure (perhaps with locking) that this
+ * constraint is not violated.
+ *
+ * More then one thread and multiple V8 isolates can be used
+ * without any locking if each isolate is created and accessed
+ * by a single thread only. For example, one thread can use
+ * multiple isolates or multiple threads can each create and run
+ * their own isolate.
*
- * If you wish to start using V8 in a thread you can do this by constructing
- * a v8::Locker object. After the code using V8 has completed for the
- * current thread you can call the destructor. This can be combined
- * with C++ scope-based construction as follows:
+ * If you wish to start using V8 isolate in more then one thread
+ * you can do this by constructing a v8::Locker object to guard
+ * access to the isolate. After the code using V8 has completed
+ * for the current thread you can call the destructor. This can
+ * be combined with C++ scope-based construction as follows
+ * (assumes the default isolate that is used if not specified as
+ * a parameter for the Locker):
*
* \code
* ...
@@ -3438,7 +3570,7 @@ class Internals {
// These values match non-compiler-dependent values defined within
// the implementation of v8.
static const int kHeapObjectMapOffset = 0;
- static const int kMapInstanceTypeOffset = kApiPointerSize + kApiIntSize;
+ static const int kMapInstanceTypeOffset = 1 * kApiPointerSize + kApiIntSize;
static const int kStringResourceOffset =
InternalConstants<kApiPointerSize>::kStringResourceOffset;
@@ -3495,6 +3627,14 @@ class Internals {
uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag;
return *reinterpret_cast<T*>(addr);
}
+
+ static inline bool CanCastToHeapObject(void* o) { return false; }
+ static inline bool CanCastToHeapObject(Context* o) { return true; }
+ static inline bool CanCastToHeapObject(String* o) { return true; }
+ static inline bool CanCastToHeapObject(Object* o) { return true; }
+ static inline bool CanCastToHeapObject(Message* o) { return true; }
+ static inline bool CanCastToHeapObject(StackTrace* o) { return true; }
+ static inline bool CanCastToHeapObject(StackFrame* o) { return true; }
};
} // namespace internal
@@ -3511,7 +3651,12 @@ Local<T>::Local() : Handle<T>() { }
template <class T>
Local<T> Local<T>::New(Handle<T> that) {
if (that.IsEmpty()) return Local<T>();
- internal::Object** p = reinterpret_cast<internal::Object**>(*that);
+ T* that_ptr = *that;
+ internal::Object** p = reinterpret_cast<internal::Object**>(that_ptr);
+ if (internal::Internals::CanCastToHeapObject(that_ptr)) {
+ return Local<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(
+ reinterpret_cast<internal::HeapObject*>(*p))));
+ }
return Local<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(*p)));
}
@@ -3560,6 +3705,10 @@ void Persistent<T>::ClearWeak() {
V8::ClearWeak(reinterpret_cast<internal::Object**>(**this));
}
+template <class T>
+void Persistent<T>::SetWrapperClassId(uint16_t class_id) {
+ V8::SetWrapperClassId(reinterpret_cast<internal::Object**>(**this), class_id);
+}
Arguments::Arguments(internal::Object** implicit_args,
internal::Object** values, int length,
diff --git a/samples/shell.cc b/samples/shell.cc
index 64f78f02..0710d464 100644
--- a/samples/shell.cc
+++ b/samples/shell.cc
@@ -33,7 +33,28 @@
#include <stdio.h>
#include <stdlib.h>
+// When building with V8 in a shared library we cannot use functions which
+// is not explicitly a part of the public V8 API. This extensive use of
+// #ifndef USING_V8_SHARED/#endif is a hack until we can resolve whether to
+// still use the shell sample for testing or change to use the developer
+// shell d8 TODO(1272).
+#ifndef USING_V8_SHARED
+#include "../src/v8.h"
+#endif // USING_V8_SHARED
+#if !defined(_WIN32) && !defined(_WIN64)
+#include <unistd.h> // NOLINT
+#endif
+
+static void ExitShell(int exit_code) {
+ // Use _exit instead of exit to avoid races between isolate
+ // threads and static destructors.
+ fflush(stdout);
+ fflush(stderr);
+ _exit(exit_code);
+}
+
+v8::Persistent<v8::Context> CreateShellContext();
void RunShell(v8::Handle<v8::Context> context);
bool ExecuteString(v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
@@ -48,58 +69,200 @@ v8::Handle<v8::String> ReadFile(const char* name);
void ReportException(v8::TryCatch* handler);
+static bool last_run = true;
+
+class SourceGroup {
+ public:
+ SourceGroup() :
+#ifndef USING_V8_SHARED
+ next_semaphore_(v8::internal::OS::CreateSemaphore(0)),
+ done_semaphore_(v8::internal::OS::CreateSemaphore(0)),
+ thread_(NULL),
+#endif // USING_V8_SHARED
+ argv_(NULL),
+ begin_offset_(0),
+ end_offset_(0) { }
+
+ void Begin(char** argv, int offset) {
+ argv_ = const_cast<const char**>(argv);
+ begin_offset_ = offset;
+ }
+
+ void End(int offset) { end_offset_ = offset; }
+
+ void Execute() {
+ for (int i = begin_offset_; i < end_offset_; ++i) {
+ const char* arg = argv_[i];
+ if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
+ // Execute argument given to -e option directly.
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::String> file_name = v8::String::New("unnamed");
+ v8::Handle<v8::String> source = v8::String::New(argv_[i + 1]);
+ if (!ExecuteString(source, file_name, false, true)) {
+ ExitShell(1);
+ return;
+ }
+ ++i;
+ } else if (arg[0] == '-') {
+ // Ignore other options. They have been parsed already.
+ } else {
+ // Use all other arguments as names of files to load and run.
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::String> file_name = v8::String::New(arg);
+ v8::Handle<v8::String> source = ReadFile(arg);
+ if (source.IsEmpty()) {
+ printf("Error reading '%s'\n", arg);
+ }
+ if (!ExecuteString(source, file_name, false, true)) {
+ ExitShell(1);
+ return;
+ }
+ }
+ }
+ }
+
+#ifndef USING_V8_SHARED
+ void StartExecuteInThread() {
+ if (thread_ == NULL) {
+ thread_ = new IsolateThread(this);
+ thread_->Start();
+ }
+ next_semaphore_->Signal();
+ }
+
+ void WaitForThread() {
+ if (thread_ == NULL) return;
+ if (last_run) {
+ thread_->Join();
+ thread_ = NULL;
+ } else {
+ done_semaphore_->Wait();
+ }
+ }
+#endif // USING_V8_SHARED
+
+ private:
+#ifndef USING_V8_SHARED
+ static v8::internal::Thread::Options GetThreadOptions() {
+ v8::internal::Thread::Options options;
+ options.name = "IsolateThread";
+ // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
+ // which is not enough to parse the big literal expressions used in tests.
+ // The stack size should be at least StackGuard::kLimitSize + some
+ // OS-specific padding for thread startup code.
+ options.stack_size = 2 << 20; // 2 Mb seems to be enough
+ return options;
+ }
+
+ class IsolateThread : public v8::internal::Thread {
+ public:
+ explicit IsolateThread(SourceGroup* group)
+ : v8::internal::Thread(NULL, GetThreadOptions()), group_(group) {}
+
+ virtual void Run() {
+ group_->ExecuteInThread();
+ }
+
+ private:
+ SourceGroup* group_;
+ };
+
+ void ExecuteInThread() {
+ v8::Isolate* isolate = v8::Isolate::New();
+ do {
+ if (next_semaphore_ != NULL) next_semaphore_->Wait();
+ {
+ v8::Isolate::Scope iscope(isolate);
+ v8::HandleScope scope;
+ v8::Persistent<v8::Context> context = CreateShellContext();
+ {
+ v8::Context::Scope cscope(context);
+ Execute();
+ }
+ context.Dispose();
+ }
+ if (done_semaphore_ != NULL) done_semaphore_->Signal();
+ } while (!last_run);
+ isolate->Dispose();
+ }
+
+ v8::internal::Semaphore* next_semaphore_;
+ v8::internal::Semaphore* done_semaphore_;
+ v8::internal::Thread* thread_;
+#endif // USING_V8_SHARED
+
+ const char** argv_;
+ int begin_offset_;
+ int end_offset_;
+};
+
+
+static SourceGroup* isolate_sources = NULL;
+
+
int RunMain(int argc, char* argv[]) {
+ v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
v8::HandleScope handle_scope;
- // Create a template for the global object.
- v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
- // Bind the global 'print' function to the C++ Print callback.
- global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
- // Bind the global 'read' function to the C++ Read callback.
- global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
- // Bind the global 'load' function to the C++ Load callback.
- global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
- // Bind the 'quit' function
- global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
- // Bind the 'version' function
- global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
- // Create a new execution environment containing the built-in
- // functions
- v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
+ v8::Persistent<v8::Context> context = CreateShellContext();
+ // Enter the newly created execution environment.
+ context->Enter();
+ if (context.IsEmpty()) {
+ printf("Error creating context\n");
+ return 1;
+ }
+
bool run_shell = (argc == 1);
+ int num_isolates = 1;
for (int i = 1; i < argc; i++) {
- // Enter the execution environment before evaluating any code.
- v8::Context::Scope context_scope(context);
- const char* str = argv[i];
- if (strcmp(str, "--shell") == 0) {
- run_shell = true;
- } else if (strcmp(str, "-f") == 0) {
- // Ignore any -f flags for compatibility with the other stand-
- // alone JavaScript engines.
- continue;
- } else if (strncmp(str, "--", 2) == 0) {
- printf("Warning: unknown flag %s.\nTry --help for options\n", str);
- } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
- // Execute argument given to -e option directly
- v8::HandleScope handle_scope;
- v8::Handle<v8::String> file_name = v8::String::New("unnamed");
- v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
- if (!ExecuteString(source, file_name, false, true))
- return 1;
- i++;
- } else {
- // Use all other arguments as names of files to load and run.
- v8::HandleScope handle_scope;
- v8::Handle<v8::String> file_name = v8::String::New(str);
- v8::Handle<v8::String> source = ReadFile(str);
- if (source.IsEmpty()) {
- printf("Error reading '%s'\n", str);
- return 1;
+ if (strcmp(argv[i], "--isolate") == 0) {
+#ifndef USING_V8_SHARED
+ ++num_isolates;
+#else // USING_V8_SHARED
+ printf("Error: --isolate not supported when linked with shared "
+ "library\n");
+ ExitShell(1);
+#endif // USING_V8_SHARED
+ }
+ }
+ if (isolate_sources == NULL) {
+ isolate_sources = new SourceGroup[num_isolates];
+ SourceGroup* current = isolate_sources;
+ current->Begin(argv, 1);
+ for (int i = 1; i < argc; i++) {
+ const char* str = argv[i];
+ if (strcmp(str, "--isolate") == 0) {
+ current->End(i);
+ current++;
+ current->Begin(argv, i + 1);
+ } else if (strcmp(str, "--shell") == 0) {
+ run_shell = true;
+ } else if (strcmp(str, "-f") == 0) {
+ // Ignore any -f flags for compatibility with the other stand-
+ // alone JavaScript engines.
+ continue;
+ } else if (strncmp(str, "--", 2) == 0) {
+ printf("Warning: unknown flag %s.\nTry --help for options\n", str);
}
- if (!ExecuteString(source, file_name, false, true))
- return 1;
}
+ current->End(argc);
+ }
+#ifndef USING_V8_SHARED
+ for (int i = 1; i < num_isolates; ++i) {
+ isolate_sources[i].StartExecuteInThread();
}
+#endif // USING_V8_SHARED
+ isolate_sources[0].Execute();
if (run_shell) RunShell(context);
+#ifndef USING_V8_SHARED
+ for (int i = 1; i < num_isolates; ++i) {
+ isolate_sources[i].WaitForThread();
+ }
+#endif // USING_V8_SHARED
+ if (last_run) {
+ delete[] isolate_sources;
+ isolate_sources = NULL;
+ }
+ context->Exit();
context.Dispose();
return 0;
}
@@ -137,8 +300,11 @@ int main(int argc, char* argv[]) {
printf("============ Stress %d/%d ============\n",
i + 1, stress_runs);
v8::Testing::PrepareStressRun(i);
+ last_run = (i == stress_runs - 1);
result = RunMain(argc, argv);
}
+ printf("======== Full Deoptimization =======\n");
+ v8::Testing::DeoptimizeAll();
} else {
result = RunMain(argc, argv);
}
@@ -153,6 +319,25 @@ const char* ToCString(const v8::String::Utf8Value& value) {
}
+// Creates a new execution environment containing the built-in
+// functions.
+v8::Persistent<v8::Context> CreateShellContext() {
+ // Create a template for the global object.
+ v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+ // Bind the global 'print' function to the C++ Print callback.
+ global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
+ // Bind the global 'read' function to the C++ Read callback.
+ global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
+ // Bind the global 'load' function to the C++ Load callback.
+ global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
+ // Bind the 'quit' function
+ global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
+ // Bind the 'version' function
+ global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
+ return v8::Context::New(NULL, global);
+}
+
+
// The callback that is invoked by v8 whenever the JavaScript 'print'
// function is called. Prints its arguments on stdout separated by
// spaces and ending with a newline.
@@ -222,7 +407,7 @@ v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
// If not arguments are given args[0] will yield undefined which
// converts to the integer value 0.
int exit_code = args[0]->Int32Value();
- exit(exit_code);
+ ExitShell(exit_code);
return v8::Undefined();
}
diff --git a/src/SConscript b/src/SConscript
index 34ca91ca..3b9968ee 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -84,6 +84,7 @@ SOURCES = {
ic.cc
inspector.cc
interpreter-irregexp.cc
+ isolate.cc
jsregexp.cc
jump-target.cc
lithium-allocator.cc
@@ -162,18 +163,23 @@ SOURCES = {
arm/assembler-arm.cc
"""),
'arch:mips': Split("""
+ jump-target-light.cc
+ virtual-frame-light.cc
mips/assembler-mips.cc
mips/builtins-mips.cc
+ mips/code-stubs-mips.cc
mips/codegen-mips.cc
mips/constants-mips.cc
mips/cpu-mips.cc
mips/debug-mips.cc
+ mips/deoptimizer-mips.cc
mips/disasm-mips.cc
- mips/full-codegen-mips.cc
mips/frames-mips.cc
+ mips/full-codegen-mips.cc
mips/ic-mips.cc
mips/jump-target-mips.cc
mips/macro-assembler-mips.cc
+ mips/regexp-macro-assembler-mips.cc
mips/register-allocator-mips.cc
mips/stub-cache-mips.cc
mips/virtual-frame-mips.cc
@@ -244,6 +250,20 @@ SOURCES = {
}
+PREPARSER_SOURCES = {
+ 'all': Split("""
+ allocation.cc
+ hashmap.cc
+ preparse-data.cc
+ preparser.cc
+ preparser-api.cc
+ scanner-base.cc
+ token.cc
+ unicode.cc
+ """)
+}
+
+
D8_FILES = {
'all': [
'd8.cc', 'd8-debug.cc'
@@ -329,6 +349,9 @@ def ConfigureObjectFiles():
source_objs = context.ConfigureObject(env, source_files)
non_snapshot_files = [source_objs]
+ preparser_source_files = context.GetRelevantSources(PREPARSER_SOURCES)
+ preparser_objs = context.ConfigureObject(env, preparser_source_files)
+
# Create snapshot if necessary. For cross compilation you should either
# do without snapshots and take the performance hit or you should build a
# host VM with the simulator=arm and snapshot=on options and then take the
@@ -349,8 +372,8 @@ def ConfigureObjectFiles():
else:
snapshot_obj = empty_snapshot_obj
library_objs = [non_snapshot_files, libraries_obj, snapshot_obj]
- return (library_objs, d8_objs, [mksnapshot])
+ return (library_objs, d8_objs, [mksnapshot], preparser_objs)
-(library_objs, d8_objs, mksnapshot) = ConfigureObjectFiles()
-Return('library_objs d8_objs mksnapshot')
+(library_objs, d8_objs, mksnapshot, preparser_objs) = ConfigureObjectFiles()
+Return('library_objs d8_objs mksnapshot preparser_objs')
diff --git a/src/accessors.cc b/src/accessors.cc
index 18264254..e33b4d79 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -34,7 +34,6 @@
#include "factory.h"
#include "safepoint-table.h"
#include "scopeinfo.h"
-#include "top.h"
namespace v8 {
namespace internal {
@@ -43,8 +42,9 @@ namespace internal {
template <class C>
static C* FindInPrototypeChain(Object* obj, bool* found_it) {
ASSERT(!*found_it);
+ Heap* heap = HEAP;
while (!Is<C>(obj)) {
- if (obj == Heap::null_value()) return NULL;
+ if (obj == heap->null_value()) return NULL;
obj = obj->GetPrototype();
}
*found_it = true;
@@ -90,24 +90,25 @@ MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
Object* Accessors::FlattenNumber(Object* value) {
if (value->IsNumber() || !value->IsJSValue()) return value;
JSValue* wrapper = JSValue::cast(value);
- ASSERT(
- Top::context()->global_context()->number_function()->has_initial_map());
- Map* number_map =
- Top::context()->global_context()->number_function()->initial_map();
+ ASSERT(Isolate::Current()->context()->global_context()->number_function()->
+ has_initial_map());
+ Map* number_map = Isolate::Current()->context()->global_context()->
+ number_function()->initial_map();
if (wrapper->map() == number_map) return wrapper->value();
return value;
}
MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
+ Isolate* isolate = object->GetIsolate();
value = FlattenNumber(value);
// Need to call methods that may trigger GC.
- HandleScope scope;
+ HandleScope scope(isolate);
// Protect raw pointers.
- Handle<JSObject> object_handle(object);
- Handle<Object> value_handle(value);
+ Handle<JSObject> object_handle(object, isolate);
+ Handle<Object> value_handle(value, isolate);
bool has_exception;
Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
@@ -126,12 +127,13 @@ MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
// This means one of the object's prototypes is a JSArray and
// the object does not have a 'length' property.
// Calling SetProperty causes an infinite loop.
- return object->SetLocalPropertyIgnoreAttributes(Heap::length_symbol(),
- value, NONE);
+ return object->SetLocalPropertyIgnoreAttributes(
+ isolate->heap()->length_symbol(), value, NONE);
}
}
- return Top::Throw(*Factory::NewRangeError("invalid_array_length",
- HandleVector<Object>(NULL, 0)));
+ return isolate->Throw(
+ *isolate->factory()->NewRangeError("invalid_array_length",
+ HandleVector<Object>(NULL, 0)));
}
@@ -314,15 +316,18 @@ const AccessorDescriptor Accessors::ScriptCompilationType = {
MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
- HandleScope scope;
- Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
+ JSValue* wrapper = JSValue::cast(object);
+ Isolate* isolate = wrapper->GetIsolate();
+ HandleScope scope(isolate);
+ Handle<Script> script(Script::cast(wrapper->value()), isolate);
InitScriptLineEnds(script);
ASSERT(script->line_ends()->IsFixedArray());
Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
// We do not want anyone to modify this array from JS.
- ASSERT(*line_ends == Heap::empty_fixed_array() ||
- line_ends->map() == Heap::fixed_cow_array_map());
- Handle<JSArray> js_array = Factory::NewJSArrayWithElements(line_ends);
+ ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
+ line_ends->map() == isolate->heap()->fixed_cow_array_map());
+ Handle<JSArray> js_array =
+ isolate->factory()->NewJSArrayWithElements(line_ends);
return *js_array;
}
@@ -368,7 +373,7 @@ MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
return *GetScriptWrapper(eval_from_script);
}
}
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
@@ -391,7 +396,7 @@ MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
// If this is not a script compiled through eval there is no eval position.
int compilation_type = Smi::cast(script->compilation_type())->value();
if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
// Get the function from where eval was called and find the source position
@@ -443,9 +448,10 @@ const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
+ Heap* heap = Isolate::Current()->heap();
bool found_it = false;
JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return Heap::undefined_value();
+ if (!found_it) return heap->undefined_value();
while (!function->should_have_prototype()) {
found_it = false;
function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
@@ -456,7 +462,7 @@ MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
if (!function->has_prototype()) {
Object* prototype;
- { MaybeObject* maybe_prototype = Heap::AllocateFunctionPrototype(function);
+ { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
}
Object* result;
@@ -471,12 +477,13 @@ MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
Object* value,
void*) {
+ Heap* heap = object->GetHeap();
bool found_it = false;
JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return Heap::undefined_value();
+ if (!found_it) return heap->undefined_value();
if (!function->should_have_prototype()) {
// Since we hit this accessor, object will have no prototype property.
- return object->SetLocalPropertyIgnoreAttributes(Heap::prototype_symbol(),
+ return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
value,
NONE);
}
@@ -545,7 +552,7 @@ const AccessorDescriptor Accessors::FunctionLength = {
MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
bool found_it = false;
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return Heap::undefined_value();
+ if (!found_it) return HEAP->undefined_value();
return holder->shared()->name();
}
@@ -604,13 +611,13 @@ class SlotRef BASE_EMBEDDED {
if (Smi::IsValid(value)) {
return Handle<Object>(Smi::FromInt(value));
} else {
- return Factory::NewNumberFromInt(value);
+ return Isolate::Current()->factory()->NewNumberFromInt(value);
}
}
case DOUBLE: {
double value = Memory::double_at(addr_);
- return Factory::NewNumber(value);
+ return Isolate::Current()->factory()->NewNumber(value);
}
case LITERAL:
@@ -732,12 +739,13 @@ static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
JavaScriptFrame* frame,
Handle<JSFunction> inlined_function,
int inlined_frame_index) {
+ Factory* factory = Isolate::Current()->factory();
int args_count = inlined_function->shared()->formal_parameter_count();
ScopedVector<SlotRef> args_slots(args_count);
ComputeSlotMappingForArguments(frame, inlined_frame_index, &args_slots);
Handle<JSObject> arguments =
- Factory::NewArgumentsObject(inlined_function, args_count);
- Handle<FixedArray> array = Factory::NewFixedArray(args_count);
+ factory->NewArgumentsObject(inlined_function, args_count);
+ Handle<FixedArray> array = factory->NewFixedArray(args_count);
for (int i = 0; i < args_count; ++i) {
Handle<Object> value = args_slots[i].GetValue();
array->set(i, *value);
@@ -750,11 +758,12 @@ static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
- HandleScope scope;
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
bool found_it = false;
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return Heap::undefined_value();
- Handle<JSFunction> function(holder);
+ if (!found_it) return isolate->heap()->undefined_value();
+ Handle<JSFunction> function(holder, isolate);
// Find the top invocation of the function by traversing frames.
List<JSFunction*> functions(2);
@@ -776,9 +785,9 @@ MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
if (!frame->is_optimized()) {
// If there is an arguments variable in the stack, we return that.
Handle<SerializedScopeInfo> info(function->shared()->scope_info());
- int index = info->StackSlotIndex(Heap::arguments_symbol());
+ int index = info->StackSlotIndex(isolate->heap()->arguments_symbol());
if (index >= 0) {
- Handle<Object> arguments(frame->GetExpression(index));
+ Handle<Object> arguments(frame->GetExpression(index), isolate);
if (!arguments->IsArgumentsMarker()) return *arguments;
}
}
@@ -791,10 +800,10 @@ MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
// Get the number of arguments and construct an arguments object
// mirror for the right frame.
- const int length = frame->GetProvidedParametersCount();
- Handle<JSObject> arguments = Factory::NewArgumentsObject(function,
- length);
- Handle<FixedArray> array = Factory::NewFixedArray(length);
+ const int length = frame->ComputeParametersCount();
+ Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
+ function, length);
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
// Copy the parameters to the arguments object.
ASSERT(array->length() == length);
@@ -808,7 +817,7 @@ MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
}
// No frame corresponding to the given function found. Return null.
- return Heap::null_value();
+ return isolate->heap()->null_value();
}
@@ -824,13 +833,27 @@ const AccessorDescriptor Accessors::FunctionArguments = {
//
+static MaybeObject* CheckNonStrictCallerOrThrow(
+ Isolate* isolate,
+ JSFunction* caller) {
+ DisableAssertNoAllocation enable_allocation;
+ if (caller->shared()->strict_mode()) {
+ return isolate->Throw(
+ *isolate->factory()->NewTypeError("strict_caller",
+ HandleVector<Object>(NULL, 0)));
+ }
+ return caller;
+}
+
+
MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
- HandleScope scope;
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
AssertNoAllocation no_alloc;
bool found_it = false;
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
- if (!found_it) return Heap::undefined_value();
- Handle<JSFunction> function(holder);
+ if (!found_it) return isolate->heap()->undefined_value();
+ Handle<JSFunction> function(holder, isolate);
List<JSFunction*> functions(2);
for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
@@ -843,18 +866,18 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
// frames, e.g. frames for scripts not functions.
if (i > 0) {
ASSERT(!functions[i - 1]->shared()->is_toplevel());
- return functions[i - 1];
+ return CheckNonStrictCallerOrThrow(isolate, functions[i - 1]);
} else {
for (it.Advance(); !it.done(); it.Advance()) {
frame = it.frame();
functions.Rewind(0);
frame->GetFunctions(&functions);
if (!functions.last()->shared()->is_toplevel()) {
- return functions.last();
+ return CheckNonStrictCallerOrThrow(isolate, functions.last());
}
ASSERT(functions.length() == 1);
}
- if (it.done()) return Heap::null_value();
+ if (it.done()) return isolate->heap()->null_value();
break;
}
}
@@ -863,7 +886,7 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
}
// No frame corresponding to the given function found. Return null.
- return Heap::null_value();
+ return isolate->heap()->null_value();
}
diff --git a/test/cctest/test-mips.cc b/src/allocation-inl.h
index efd4cc97..04a3fe66 100644
--- a/test/cctest/test-mips.cc
+++ b/src/allocation-inl.h
@@ -25,28 +25,25 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifndef V8_ALLOCATION_INL_H_
+#define V8_ALLOCATION_INL_H_
-#include "v8.h"
-#include "execution.h"
+#include "allocation.h"
-#include "cctest.h"
+namespace v8 {
+namespace internal {
-using ::v8::Local;
-using ::v8::String;
-using ::v8::Script;
-namespace i = ::v8::internal;
-
-TEST(MIPSFunctionCalls) {
- // Disable compilation of natives.
- i::FLAG_disable_native_files = true;
- i::FLAG_full_compiler = false;
+void* PreallocatedStorage::New(size_t size) {
+ return Isolate::Current()->PreallocatedStorageNew(size);
+}
- v8::HandleScope scope;
- LocalContext env; // from cctest.h
- const char* c_source = "function foo() { return 0x1234; }; foo();";
- Local<String> source = ::v8::String::New(c_source);
- Local<Script> script = ::v8::Script::Compile(source);
- CHECK_EQ(0x1234, script->Run()->Int32Value());
+void PreallocatedStorage::Delete(void* p) {
+ return Isolate::Current()->PreallocatedStorageDelete(p);
}
+
+
+} } // namespace v8::internal
+
+#endif // V8_ALLOCATION_INL_H_
diff --git a/src/allocation.cc b/src/allocation.cc
index d74c37cd..119b087c 100644
--- a/src/allocation.cc
+++ b/src/allocation.cc
@@ -25,8 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <stdlib.h>
-
#include "../include/v8stdint.h"
#include "globals.h"
#include "checks.h"
@@ -37,7 +35,6 @@ namespace v8 {
namespace internal {
void* Malloced::New(size_t size) {
- ASSERT(NativeAllocationChecker::allocation_allowed());
void* result = malloc(size);
if (result == NULL) {
v8::internal::FatalProcessOutOfMemory("Malloced operator new");
@@ -103,85 +100,6 @@ char* StrNDup(const char* str, int n) {
}
-int NativeAllocationChecker::allocation_disallowed_ = 0;
-
-
-PreallocatedStorage PreallocatedStorage::in_use_list_(0);
-PreallocatedStorage PreallocatedStorage::free_list_(0);
-bool PreallocatedStorage::preallocated_ = false;
-
-
-void PreallocatedStorage::Init(size_t size) {
- ASSERT(free_list_.next_ == &free_list_);
- ASSERT(free_list_.previous_ == &free_list_);
- PreallocatedStorage* free_chunk =
- reinterpret_cast<PreallocatedStorage*>(new char[size]);
- free_list_.next_ = free_list_.previous_ = free_chunk;
- free_chunk->next_ = free_chunk->previous_ = &free_list_;
- free_chunk->size_ = size - sizeof(PreallocatedStorage);
- preallocated_ = true;
-}
-
-
-void* PreallocatedStorage::New(size_t size) {
- if (!preallocated_) {
- return FreeStoreAllocationPolicy::New(size);
- }
- ASSERT(free_list_.next_ != &free_list_);
- ASSERT(free_list_.previous_ != &free_list_);
-
- size = (size + kPointerSize - 1) & ~(kPointerSize - 1);
- // Search for exact fit.
- for (PreallocatedStorage* storage = free_list_.next_;
- storage != &free_list_;
- storage = storage->next_) {
- if (storage->size_ == size) {
- storage->Unlink();
- storage->LinkTo(&in_use_list_);
- return reinterpret_cast<void*>(storage + 1);
- }
- }
- // Search for first fit.
- for (PreallocatedStorage* storage = free_list_.next_;
- storage != &free_list_;
- storage = storage->next_) {
- if (storage->size_ >= size + sizeof(PreallocatedStorage)) {
- storage->Unlink();
- storage->LinkTo(&in_use_list_);
- PreallocatedStorage* left_over =
- reinterpret_cast<PreallocatedStorage*>(
- reinterpret_cast<char*>(storage + 1) + size);
- left_over->size_ = storage->size_ - size - sizeof(PreallocatedStorage);
- ASSERT(size + left_over->size_ + sizeof(PreallocatedStorage) ==
- storage->size_);
- storage->size_ = size;
- left_over->LinkTo(&free_list_);
- return reinterpret_cast<void*>(storage + 1);
- }
- }
- // Allocation failure.
- ASSERT(false);
- return NULL;
-}
-
-
-// We don't attempt to coalesce.
-void PreallocatedStorage::Delete(void* p) {
- if (p == NULL) {
- return;
- }
- if (!preallocated_) {
- FreeStoreAllocationPolicy::Delete(p);
- return;
- }
- PreallocatedStorage* storage = reinterpret_cast<PreallocatedStorage*>(p) - 1;
- ASSERT(storage->next_->previous_ == storage);
- ASSERT(storage->previous_->next_ == storage);
- storage->Unlink();
- storage->LinkTo(&free_list_);
-}
-
-
void PreallocatedStorage::LinkTo(PreallocatedStorage* other) {
next_ = other->next_;
other->next_->previous_ = this;
diff --git a/src/allocation.h b/src/allocation.h
index 394366ea..75aba35d 100644
--- a/src/allocation.h
+++ b/src/allocation.h
@@ -39,38 +39,6 @@ namespace internal {
// processing.
void FatalProcessOutOfMemory(const char* message);
-// A class that controls whether allocation is allowed. This is for
-// the C++ heap only!
-class NativeAllocationChecker {
- public:
- typedef enum { ALLOW, DISALLOW } NativeAllocationAllowed;
- explicit inline NativeAllocationChecker(NativeAllocationAllowed allowed)
- : allowed_(allowed) {
-#ifdef DEBUG
- if (allowed == DISALLOW) {
- allocation_disallowed_++;
- }
-#endif
- }
- ~NativeAllocationChecker() {
-#ifdef DEBUG
- if (allowed_ == DISALLOW) {
- allocation_disallowed_--;
- }
-#endif
- ASSERT(allocation_disallowed_ >= 0);
- }
- static inline bool allocation_allowed() {
- return allocation_disallowed_ == 0;
- }
- private:
- // This static counter ensures that NativeAllocationCheckers can be nested.
- static int allocation_disallowed_;
- // This flag applies to this particular instance.
- NativeAllocationAllowed allowed_;
-};
-
-
// Superclass for classes managed with new & delete.
class Malloced {
public:
@@ -114,7 +82,6 @@ class AllStatic {
template <typename T>
static T* NewArray(int size) {
- ASSERT(NativeAllocationChecker::allocation_allowed());
T* result = new T[size];
if (result == NULL) Malloced::FatalProcessOutOfMemory();
return result;
@@ -146,27 +113,27 @@ class FreeStoreAllocationPolicy {
// Allocation policy for allocating in preallocated space.
// Used as an allocation policy for ScopeInfo when generating
// stack traces.
-class PreallocatedStorage : public AllStatic {
+class PreallocatedStorage {
public:
explicit PreallocatedStorage(size_t size);
size_t size() { return size_; }
- static void* New(size_t size);
- static void Delete(void* p);
- // Preallocate a set number of bytes.
- static void Init(size_t size);
+ // TODO(isolates): Get rid of these-- we'll have to change the allocator
+ // interface to include a pointer to an isolate to do this
+ // efficiently.
+ static inline void* New(size_t size);
+ static inline void Delete(void* p);
private:
size_t size_;
PreallocatedStorage* previous_;
PreallocatedStorage* next_;
- static bool preallocated_;
-
- static PreallocatedStorage in_use_list_;
- static PreallocatedStorage free_list_;
void LinkTo(PreallocatedStorage* other);
void Unlink();
+
+ friend class Isolate;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(PreallocatedStorage);
};
diff --git a/src/api.cc b/src/api.cc
index 555af843..0d5e4f06 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -44,7 +44,6 @@
#include "runtime-profiler.h"
#include "serialize.h"
#include "snapshot.h"
-#include "top.h"
#include "v8threads.h"
#include "version.h"
#include "vm-state-inl.h"
@@ -52,81 +51,84 @@
#include "../include/v8-profiler.h"
#include "../include/v8-testing.h"
-#define LOG_API(expr) LOG(ApiEntryCall(expr))
+#define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr))
+// TODO(isolates): avoid repeated TLS reads in function prologues.
#ifdef ENABLE_VMSTATE_TRACKING
-#define ENTER_V8 ASSERT(i::V8::IsRunning()); i::VMState __state__(i::OTHER)
-#define LEAVE_V8 i::VMState __state__(i::EXTERNAL)
+#define ENTER_V8(isolate) \
+ ASSERT((isolate)->IsInitialized()); \
+ i::VMState __state__((isolate), i::OTHER)
+#define LEAVE_V8(isolate) \
+ i::VMState __state__((isolate), i::EXTERNAL)
#else
-#define ENTER_V8 ((void) 0)
-#define LEAVE_V8 ((void) 0)
+#define ENTER_V8(isolate) ((void) 0)
+#define LEAVE_V8(isolate) ((void) 0)
#endif
namespace v8 {
-#define ON_BAILOUT(location, code) \
- if (IsDeadCheck(location) || v8::V8::IsExecutionTerminating()) { \
+#define ON_BAILOUT(isolate, location, code) \
+ if (IsDeadCheck(isolate, location) || \
+ IsExecutionTerminatingCheck(isolate)) { \
code; \
UNREACHABLE(); \
}
-#define EXCEPTION_PREAMBLE() \
- thread_local.IncrementCallDepth(); \
- ASSERT(!i::Top::external_caught_exception()); \
+#define EXCEPTION_PREAMBLE(isolate) \
+ (isolate)->handle_scope_implementer()->IncrementCallDepth(); \
+ ASSERT(!(isolate)->external_caught_exception()); \
bool has_pending_exception = false
-#define EXCEPTION_BAILOUT_CHECK(value) \
+#define EXCEPTION_BAILOUT_CHECK(isolate, value) \
do { \
- thread_local.DecrementCallDepth(); \
+ i::HandleScopeImplementer* handle_scope_implementer = \
+ (isolate)->handle_scope_implementer(); \
+ handle_scope_implementer->DecrementCallDepth(); \
if (has_pending_exception) { \
- if (thread_local.CallDepthIsZero() && i::Top::is_out_of_memory()) { \
- if (!thread_local.ignore_out_of_memory()) \
+ if (handle_scope_implementer->CallDepthIsZero() && \
+ (isolate)->is_out_of_memory()) { \
+ if (!handle_scope_implementer->ignore_out_of_memory()) \
i::V8::FatalProcessOutOfMemory(NULL); \
} \
- bool call_depth_is_zero = thread_local.CallDepthIsZero(); \
- i::Top::OptionalRescheduleException(call_depth_is_zero); \
+ bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero(); \
+ (isolate)->OptionalRescheduleException(call_depth_is_zero); \
return value; \
} \
} while (false)
+// TODO(isolates): Add a parameter to this macro for an isolate.
#define API_ENTRY_CHECK(msg) \
do { \
if (v8::Locker::IsActive()) { \
- ApiCheck(i::ThreadManager::IsLockedByCurrentThread(), \
+ ApiCheck(i::Isolate::Current()->thread_manager()-> \
+ IsLockedByCurrentThread(), \
msg, \
"Entering the V8 API without proper locking in place"); \
} \
} while (false)
-// --- D a t a t h a t i s s p e c i f i c t o a t h r e a d ---
-
-
-static i::HandleScopeImplementer thread_local;
-
-
// --- E x c e p t i o n B e h a v i o r ---
-static FatalErrorCallback exception_behavior = NULL;
-
static void DefaultFatalErrorHandler(const char* location,
const char* message) {
#ifdef ENABLE_VMSTATE_TRACKING
- i::VMState __state__(i::OTHER);
+ i::VMState __state__(i::Isolate::Current(), i::OTHER);
#endif
API_Fatal(location, message);
}
-static FatalErrorCallback& GetFatalErrorHandler() {
- if (exception_behavior == NULL) {
- exception_behavior = DefaultFatalErrorHandler;
+static FatalErrorCallback GetFatalErrorHandler() {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (isolate->exception_behavior() == NULL) {
+ isolate->set_exception_behavior(DefaultFatalErrorHandler);
}
- return exception_behavior;
+ return isolate->exception_behavior();
}
@@ -189,11 +191,12 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) {
heap_stats.os_error = &os_error;
int end_marker;
heap_stats.end_marker = &end_marker;
- i::Heap::RecordStats(&heap_stats, take_snapshot);
+ i::Isolate* isolate = i::Isolate::Current();
+ isolate->heap()->RecordStats(&heap_stats, take_snapshot);
i::V8::SetFatalError();
FatalErrorCallback callback = GetFatalErrorHandler();
{
- LEAVE_V8;
+ LEAVE_V8(isolate);
callback(location, "Allocation failed - process out of memory");
}
// If the callback returns, we stop execution.
@@ -201,11 +204,6 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) {
}
-void V8::SetFatalErrorHandler(FatalErrorCallback that) {
- exception_behavior = that;
-}
-
-
bool Utils::ReportApiFailure(const char* location, const char* message) {
FatalErrorCallback callback = GetFatalErrorHandler();
callback(location, message);
@@ -252,12 +250,22 @@ static bool ReportEmptyHandle(const char* location) {
* advantage over ON_BAILOUT that it actually initializes the VM if this has not
* yet been done.
*/
-static inline bool IsDeadCheck(const char* location) {
- return !i::V8::IsRunning()
+static inline bool IsDeadCheck(i::Isolate* isolate, const char* location) {
+ return !isolate->IsInitialized()
&& i::V8::IsDead() ? ReportV8Dead(location) : false;
}
+static inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) {
+ if (!isolate->IsInitialized()) return false;
+ if (isolate->has_scheduled_exception()) {
+ return isolate->scheduled_exception() ==
+ isolate->heap()->termination_exception();
+ }
+ return false;
+}
+
+
static inline bool EmptyCheck(const char* location, v8::Handle<v8::Data> obj) {
return obj.IsEmpty() ? ReportEmptyHandle(location) : false;
}
@@ -270,23 +278,42 @@ static inline bool EmptyCheck(const char* location, const v8::Data* obj) {
// --- S t a t i c s ---
-static i::StringInputBuffer write_input_buffer;
+static bool InitializeHelper() {
+ if (i::Snapshot::Initialize()) return true;
+ return i::V8::Initialize(NULL);
+}
-static inline bool EnsureInitialized(const char* location) {
- if (i::V8::IsRunning()) {
- return true;
- }
- if (IsDeadCheck(location)) {
- return false;
+static inline bool EnsureInitializedForIsolate(i::Isolate* isolate,
+ const char* location) {
+ if (IsDeadCheck(isolate, location)) return false;
+ if (isolate != NULL) {
+ if (isolate->IsInitialized()) return true;
}
- return ApiCheck(v8::V8::Initialize(), location, "Error initializing V8");
+ return ApiCheck(InitializeHelper(), location, "Error initializing V8");
}
+// Some initializing API functions are called early and may be
+// called on a thread different from static initializer thread.
+// If Isolate API is used, Isolate::Enter() will initialize TLS so
+// Isolate::Current() works. If it's a legacy case, then the thread
+// may not have TLS initialized yet. However, in initializing APIs it
+// may be too early to call EnsureInitialized() - some pre-init
+// parameters still have to be configured.
+static inline i::Isolate* EnterIsolateIfNeeded() {
+ i::Isolate* isolate = i::Isolate::UncheckedCurrent();
+ if (isolate != NULL)
+ return isolate;
-ImplementationUtilities::HandleScopeData*
- ImplementationUtilities::CurrentHandleScope() {
- return &i::HandleScope::current_;
+ i::Isolate::EnterDefaultIsolate();
+ isolate = i::Isolate::Current();
+ return isolate;
+}
+
+
+void V8::SetFatalErrorHandler(FatalErrorCallback that) {
+ i::Isolate* isolate = EnterIsolateIfNeeded();
+ isolate->set_exception_behavior(that);
}
@@ -298,30 +325,6 @@ void ImplementationUtilities::ZapHandleRange(i::Object** begin,
#endif
-v8::Handle<v8::Primitive> ImplementationUtilities::Undefined() {
- if (!EnsureInitialized("v8::Undefined()")) return v8::Handle<v8::Primitive>();
- return v8::Handle<Primitive>(ToApi<Primitive>(i::Factory::undefined_value()));
-}
-
-
-v8::Handle<v8::Primitive> ImplementationUtilities::Null() {
- if (!EnsureInitialized("v8::Null()")) return v8::Handle<v8::Primitive>();
- return v8::Handle<Primitive>(ToApi<Primitive>(i::Factory::null_value()));
-}
-
-
-v8::Handle<v8::Boolean> ImplementationUtilities::True() {
- if (!EnsureInitialized("v8::True()")) return v8::Handle<v8::Boolean>();
- return v8::Handle<v8::Boolean>(ToApi<Boolean>(i::Factory::true_value()));
-}
-
-
-v8::Handle<v8::Boolean> ImplementationUtilities::False() {
- if (!EnsureInitialized("v8::False()")) return v8::Handle<v8::Boolean>();
- return v8::Handle<v8::Boolean>(ToApi<Boolean>(i::Factory::false_value()));
-}
-
-
void V8::SetFlagsFromString(const char* str, int length) {
i::FlagList::SetFlagsFromString(str, length);
}
@@ -333,14 +336,17 @@ void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
v8::Handle<Value> ThrowException(v8::Handle<v8::Value> value) {
- if (IsDeadCheck("v8::ThrowException()")) return v8::Handle<Value>();
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::ThrowException()")) {
+ return v8::Handle<Value>();
+ }
+ ENTER_V8(isolate);
// If we're passed an empty handle, we throw an undefined exception
// to deal more gracefully with out of memory situations.
if (value.IsEmpty()) {
- i::Top::ScheduleThrow(i::Heap::undefined_value());
+ isolate->ScheduleThrow(isolate->heap()->undefined_value());
} else {
- i::Top::ScheduleThrow(*Utils::OpenHandle(*value));
+ isolate->ScheduleThrow(*Utils::OpenHandle(*value));
}
return v8::Undefined();
}
@@ -354,8 +360,8 @@ RegisteredExtension::RegisteredExtension(Extension* extension)
void RegisteredExtension::Register(RegisteredExtension* that) {
- that->next_ = RegisteredExtension::first_extension_;
- RegisteredExtension::first_extension_ = that;
+ that->next_ = first_extension_;
+ first_extension_ = that;
}
@@ -377,26 +383,42 @@ Extension::Extension(const char* name,
v8::Handle<Primitive> Undefined() {
- LOG_API("Undefined");
- return ImplementationUtilities::Undefined();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!EnsureInitializedForIsolate(isolate, "v8::Undefined()")) {
+ return v8::Handle<v8::Primitive>();
+ }
+ return v8::Handle<Primitive>(ToApi<Primitive>(
+ isolate->factory()->undefined_value()));
}
v8::Handle<Primitive> Null() {
- LOG_API("Null");
- return ImplementationUtilities::Null();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!EnsureInitializedForIsolate(isolate, "v8::Null()")) {
+ return v8::Handle<v8::Primitive>();
+ }
+ return v8::Handle<Primitive>(
+ ToApi<Primitive>(isolate->factory()->null_value()));
}
v8::Handle<Boolean> True() {
- LOG_API("True");
- return ImplementationUtilities::True();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!EnsureInitializedForIsolate(isolate, "v8::True()")) {
+ return v8::Handle<Boolean>();
+ }
+ return v8::Handle<Boolean>(
+ ToApi<Boolean>(isolate->factory()->true_value()));
}
v8::Handle<Boolean> False() {
- LOG_API("False");
- return ImplementationUtilities::False();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!EnsureInitializedForIsolate(isolate, "v8::False()")) {
+ return v8::Handle<Boolean>();
+ }
+ return v8::Handle<Boolean>(
+ ToApi<Boolean>(isolate->factory()->false_value()));
}
@@ -408,74 +430,89 @@ ResourceConstraints::ResourceConstraints()
bool SetResourceConstraints(ResourceConstraints* constraints) {
+ i::Isolate* isolate = EnterIsolateIfNeeded();
+
int young_space_size = constraints->max_young_space_size();
int old_gen_size = constraints->max_old_space_size();
int max_executable_size = constraints->max_executable_size();
if (young_space_size != 0 || old_gen_size != 0 || max_executable_size != 0) {
- bool result = i::Heap::ConfigureHeap(young_space_size / 2,
- old_gen_size,
- max_executable_size);
+ // After initialization it's too late to change Heap constraints.
+ ASSERT(!isolate->IsInitialized());
+ bool result = isolate->heap()->ConfigureHeap(young_space_size / 2,
+ old_gen_size,
+ max_executable_size);
if (!result) return false;
}
if (constraints->stack_limit() != NULL) {
uintptr_t limit = reinterpret_cast<uintptr_t>(constraints->stack_limit());
- i::StackGuard::SetStackLimit(limit);
+ isolate->stack_guard()->SetStackLimit(limit);
}
return true;
}
i::Object** V8::GlobalizeReference(i::Object** obj) {
- if (IsDeadCheck("V8::Persistent::New")) return NULL;
- LOG_API("Persistent::New");
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "V8::Persistent::New")) return NULL;
+ LOG_API(isolate, "Persistent::New");
i::Handle<i::Object> result =
- i::GlobalHandles::Create(*obj);
+ isolate->global_handles()->Create(*obj);
return result.location();
}
void V8::MakeWeak(i::Object** object, void* parameters,
WeakReferenceCallback callback) {
- LOG_API("MakeWeak");
- i::GlobalHandles::MakeWeak(object, parameters, callback);
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "MakeWeak");
+ isolate->global_handles()->MakeWeak(object, parameters,
+ callback);
}
void V8::ClearWeak(i::Object** obj) {
- LOG_API("ClearWeak");
- i::GlobalHandles::ClearWeakness(obj);
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "ClearWeak");
+ isolate->global_handles()->ClearWeakness(obj);
}
bool V8::IsGlobalNearDeath(i::Object** obj) {
- LOG_API("IsGlobalNearDeath");
- if (!i::V8::IsRunning()) return false;
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "IsGlobalNearDeath");
+ if (!isolate->IsInitialized()) return false;
return i::GlobalHandles::IsNearDeath(obj);
}
bool V8::IsGlobalWeak(i::Object** obj) {
- LOG_API("IsGlobalWeak");
- if (!i::V8::IsRunning()) return false;
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "IsGlobalWeak");
+ if (!isolate->IsInitialized()) return false;
return i::GlobalHandles::IsWeak(obj);
}
void V8::DisposeGlobal(i::Object** obj) {
- LOG_API("DisposeGlobal");
- if (!i::V8::IsRunning()) return;
- i::GlobalHandles::Destroy(obj);
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "DisposeGlobal");
+ if (!isolate->IsInitialized()) return;
+ isolate->global_handles()->Destroy(obj);
}
// --- H a n d l e s ---
-HandleScope::HandleScope()
- : prev_next_(i::HandleScope::current_.next),
- prev_limit_(i::HandleScope::current_.limit),
- is_closed_(false) {
+HandleScope::HandleScope() {
API_ENTRY_CHECK("HandleScope::HandleScope");
- i::HandleScope::current_.level++;
+ i::Isolate* isolate = i::Isolate::Current();
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate->handle_scope_data();
+ isolate_ = isolate;
+ prev_next_ = current->next;
+ prev_limit_ = current->limit;
+ is_closed_ = false;
+ current->level++;
}
@@ -487,12 +524,15 @@ HandleScope::~HandleScope() {
void HandleScope::Leave() {
- i::HandleScope::current_.level--;
- ASSERT(i::HandleScope::current_.level >= 0);
- i::HandleScope::current_.next = prev_next_;
- if (i::HandleScope::current_.limit != prev_limit_) {
- i::HandleScope::current_.limit = prev_limit_;
- i::HandleScope::DeleteExtensions();
+ ASSERT(isolate_ == i::Isolate::Current());
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate_->handle_scope_data();
+ current->level--;
+ ASSERT(current->level >= 0);
+ current->next = prev_next_;
+ if (current->limit != prev_limit_) {
+ current->limit = prev_limit_;
+ i::HandleScope::DeleteExtensions(isolate_);
}
#ifdef DEBUG
@@ -502,45 +542,63 @@ void HandleScope::Leave() {
int HandleScope::NumberOfHandles() {
+ EnsureInitializedForIsolate(
+ i::Isolate::Current(), "HandleScope::NumberOfHandles");
return i::HandleScope::NumberOfHandles();
}
-i::Object** v8::HandleScope::CreateHandle(i::Object* value) {
- return i::HandleScope::CreateHandle(value);
+i::Object** HandleScope::CreateHandle(i::Object* value) {
+ return i::HandleScope::CreateHandle(value, i::Isolate::Current());
+}
+
+
+i::Object** HandleScope::CreateHandle(i::HeapObject* value) {
+ ASSERT(value->IsHeapObject());
+ return reinterpret_cast<i::Object**>(
+ i::HandleScope::CreateHandle(value, value->GetIsolate()));
}
void Context::Enter() {
- if (IsDeadCheck("v8::Context::Enter()")) return;
- ENTER_V8;
+ // TODO(isolates): Context should have a pointer to isolate.
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::Enter()")) return;
+ ENTER_V8(isolate);
+
i::Handle<i::Context> env = Utils::OpenHandle(this);
- thread_local.EnterContext(env);
+ isolate->handle_scope_implementer()->EnterContext(env);
- thread_local.SaveContext(i::Top::context());
- i::Top::set_context(*env);
+ isolate->handle_scope_implementer()->SaveContext(isolate->context());
+ isolate->set_context(*env);
}
void Context::Exit() {
- if (!i::V8::IsRunning()) return;
- if (!ApiCheck(thread_local.LeaveLastContext(),
+ // TODO(isolates): Context should have a pointer to isolate.
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!isolate->IsInitialized()) return;
+
+ if (!ApiCheck(isolate->handle_scope_implementer()->LeaveLastContext(),
"v8::Context::Exit()",
"Cannot exit non-entered context")) {
return;
}
// Content of 'last_context' could be NULL.
- i::Context* last_context = thread_local.RestoreContext();
- i::Top::set_context(last_context);
+ i::Context* last_context =
+ isolate->handle_scope_implementer()->RestoreContext();
+ isolate->set_context(last_context);
}
void Context::SetData(v8::Handle<String> data) {
- if (IsDeadCheck("v8::Context::SetData()")) return;
- ENTER_V8;
+ // TODO(isolates): Context should have a pointer to isolate.
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::SetData()")) return;
+ ENTER_V8(isolate);
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::Context> env = Utils::OpenHandle(this);
i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
ASSERT(env->IsGlobalContext());
@@ -552,11 +610,15 @@ void Context::SetData(v8::Handle<String> data) {
v8::Local<v8::Value> Context::GetData() {
- if (IsDeadCheck("v8::Context::GetData()")) return v8::Local<Value>();
- ENTER_V8;
+ // TODO(isolates): Context should have a pointer to isolate.
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::GetData()")) {
+ return v8::Local<Value>();
+ }
+ ENTER_V8(isolate);
i::Object* raw_result = NULL;
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::Context> env = Utils::OpenHandle(this);
ASSERT(env->IsGlobalContext());
if (env->IsGlobalContext()) {
@@ -576,7 +638,7 @@ i::Object** v8::HandleScope::RawClose(i::Object** value) {
"Local scope has already been closed")) {
return 0;
}
- LOG_API("CloseHandleScope");
+ LOG_API(isolate_, "CloseHandleScope");
// Read the result before popping the handle block.
i::Object* result = NULL;
@@ -605,10 +667,11 @@ i::Object** v8::HandleScope::RawClose(i::Object** value) {
// NeanderObject constructor. When you add one to the site calling the
// constructor you should check that you ensured the VM was not dead first.
NeanderObject::NeanderObject(int size) {
- EnsureInitialized("v8::Nowhere");
- ENTER_V8;
- value_ = i::Factory::NewNeanderObject();
- i::Handle<i::FixedArray> elements = i::Factory::NewFixedArray(size);
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Nowhere");
+ ENTER_V8(isolate);
+ value_ = isolate->factory()->NewNeanderObject();
+ i::Handle<i::FixedArray> elements = isolate->factory()->NewFixedArray(size);
value_->set_elements(*elements);
}
@@ -644,7 +707,7 @@ void NeanderArray::add(i::Handle<i::Object> value) {
int length = this->length();
int size = obj_.size();
if (length == size - 1) {
- i::Handle<i::FixedArray> new_elms = i::Factory::NewFixedArray(2 * size);
+ i::Handle<i::FixedArray> new_elms = FACTORY->NewFixedArray(2 * size);
for (int i = 0; i < length; i++)
new_elms->set(i + 1, get(i));
obj_.value()->set_elements(*new_elms);
@@ -670,9 +733,10 @@ static void InitializeTemplate(i::Handle<i::TemplateInfo> that, int type) {
void Template::Set(v8::Handle<String> name, v8::Handle<Data> value,
v8::PropertyAttribute attribute) {
- if (IsDeadCheck("v8::Template::Set()")) return;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Template::Set()")) return;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::Object> list(Utils::OpenHandle(this)->property_list());
if (list->IsUndefined()) {
list = NeanderArray().value();
@@ -694,10 +758,11 @@ static void InitializeFunctionTemplate(
Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate() {
- if (IsDeadCheck("v8::FunctionTemplate::PrototypeTemplate()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::FunctionTemplate::PrototypeTemplate()")) {
return Local<ObjectTemplate>();
}
- ENTER_V8;
+ ENTER_V8(isolate);
i::Handle<i::Object> result(Utils::OpenHandle(this)->prototype_template());
if (result->IsUndefined()) {
result = Utils::OpenHandle(*ObjectTemplate::New());
@@ -708,28 +773,27 @@ Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate() {
void FunctionTemplate::Inherit(v8::Handle<FunctionTemplate> value) {
- if (IsDeadCheck("v8::FunctionTemplate::Inherit()")) return;
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::FunctionTemplate::Inherit()")) return;
+ ENTER_V8(isolate);
Utils::OpenHandle(this)->set_parent_template(*Utils::OpenHandle(*value));
}
-// To distinguish the function templates, so that we can find them in the
-// function cache of the global context.
-static int next_serial_number = 0;
-
-
Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
v8::Handle<Value> data, v8::Handle<Signature> signature) {
- EnsureInitialized("v8::FunctionTemplate::New()");
- LOG_API("FunctionTemplate::New");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::FunctionTemplate::New()");
+ LOG_API(isolate, "FunctionTemplate::New");
+ ENTER_V8(isolate);
i::Handle<i::Struct> struct_obj =
- i::Factory::NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE);
+ isolate->factory()->NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE);
i::Handle<i::FunctionTemplateInfo> obj =
i::Handle<i::FunctionTemplateInfo>::cast(struct_obj);
InitializeFunctionTemplate(obj);
- obj->set_serial_number(i::Smi::FromInt(next_serial_number++));
+ int next_serial_number = isolate->next_serial_number();
+ isolate->set_next_serial_number(next_serial_number + 1);
+ obj->set_serial_number(i::Smi::FromInt(next_serial_number));
if (callback != 0) {
if (data.IsEmpty()) data = v8::Undefined();
Utils::ToLocal(obj)->SetCallHandler(callback, data);
@@ -745,16 +809,17 @@ Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
Local<Signature> Signature::New(Handle<FunctionTemplate> receiver,
int argc, Handle<FunctionTemplate> argv[]) {
- EnsureInitialized("v8::Signature::New()");
- LOG_API("Signature::New");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Signature::New()");
+ LOG_API(isolate, "Signature::New");
+ ENTER_V8(isolate);
i::Handle<i::Struct> struct_obj =
- i::Factory::NewStruct(i::SIGNATURE_INFO_TYPE);
+ isolate->factory()->NewStruct(i::SIGNATURE_INFO_TYPE);
i::Handle<i::SignatureInfo> obj =
i::Handle<i::SignatureInfo>::cast(struct_obj);
if (!receiver.IsEmpty()) obj->set_receiver(*Utils::OpenHandle(*receiver));
if (argc > 0) {
- i::Handle<i::FixedArray> args = i::Factory::NewFixedArray(argc);
+ i::Handle<i::FixedArray> args = isolate->factory()->NewFixedArray(argc);
for (int i = 0; i < argc; i++) {
if (!argv[i].IsEmpty())
args->set(i, *Utils::OpenHandle(*argv[i]));
@@ -772,14 +837,15 @@ Local<TypeSwitch> TypeSwitch::New(Handle<FunctionTemplate> type) {
Local<TypeSwitch> TypeSwitch::New(int argc, Handle<FunctionTemplate> types[]) {
- EnsureInitialized("v8::TypeSwitch::New()");
- LOG_API("TypeSwitch::New");
- ENTER_V8;
- i::Handle<i::FixedArray> vector = i::Factory::NewFixedArray(argc);
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::TypeSwitch::New()");
+ LOG_API(isolate, "TypeSwitch::New");
+ ENTER_V8(isolate);
+ i::Handle<i::FixedArray> vector = isolate->factory()->NewFixedArray(argc);
for (int i = 0; i < argc; i++)
vector->set(i, *Utils::OpenHandle(*types[i]));
i::Handle<i::Struct> struct_obj =
- i::Factory::NewStruct(i::TYPE_SWITCH_INFO_TYPE);
+ isolate->factory()->NewStruct(i::TYPE_SWITCH_INFO_TYPE);
i::Handle<i::TypeSwitchInfo> obj =
i::Handle<i::TypeSwitchInfo>::cast(struct_obj);
obj->set_types(*vector);
@@ -788,7 +854,8 @@ Local<TypeSwitch> TypeSwitch::New(int argc, Handle<FunctionTemplate> types[]) {
int TypeSwitch::match(v8::Handle<Value> value) {
- LOG_API("TypeSwitch::match");
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "TypeSwitch::match");
i::Handle<i::Object> obj = Utils::OpenHandle(*value);
i::Handle<i::TypeSwitchInfo> info = Utils::OpenHandle(this);
i::FixedArray* types = i::FixedArray::cast(info->types());
@@ -808,11 +875,12 @@ int TypeSwitch::match(v8::Handle<Value> value) {
void FunctionTemplate::SetCallHandler(InvocationCallback callback,
v8::Handle<Value> data) {
- if (IsDeadCheck("v8::FunctionTemplate::SetCallHandler()")) return;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetCallHandler()")) return;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::Struct> struct_obj =
- i::Factory::NewStruct(i::CALL_HANDLER_INFO_TYPE);
+ isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE);
i::Handle<i::CallHandlerInfo> obj =
i::Handle<i::CallHandlerInfo>::cast(struct_obj);
SET_FIELD_WRAPPED(obj, set_callback, callback);
@@ -829,7 +897,7 @@ static i::Handle<i::AccessorInfo> MakeAccessorInfo(
v8::Handle<Value> data,
v8::AccessControl settings,
v8::PropertyAttribute attributes) {
- i::Handle<i::AccessorInfo> obj = i::Factory::NewAccessorInfo();
+ i::Handle<i::AccessorInfo> obj = FACTORY->NewAccessorInfo();
ASSERT(getter != NULL);
SET_FIELD_WRAPPED(obj, set_getter, getter);
SET_FIELD_WRAPPED(obj, set_setter, setter);
@@ -851,11 +919,13 @@ void FunctionTemplate::AddInstancePropertyAccessor(
v8::Handle<Value> data,
v8::AccessControl settings,
v8::PropertyAttribute attributes) {
- if (IsDeadCheck("v8::FunctionTemplate::AddInstancePropertyAccessor()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate,
+ "v8::FunctionTemplate::AddInstancePropertyAccessor()")) {
return;
}
- ENTER_V8;
- HandleScope scope;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(name,
getter, setter, data,
@@ -871,10 +941,11 @@ void FunctionTemplate::AddInstancePropertyAccessor(
Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() {
- if (IsDeadCheck("v8::FunctionTemplate::InstanceTemplate()")
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::FunctionTemplate::InstanceTemplate()")
|| EmptyCheck("v8::FunctionTemplate::InstanceTemplate()", this))
return Local<ObjectTemplate>();
- ENTER_V8;
+ ENTER_V8(isolate);
if (Utils::OpenHandle(this)->instance_template()->IsUndefined()) {
Local<ObjectTemplate> templ =
ObjectTemplate::New(v8::Handle<FunctionTemplate>(this));
@@ -887,15 +958,19 @@ Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() {
void FunctionTemplate::SetClassName(Handle<String> name) {
- if (IsDeadCheck("v8::FunctionTemplate::SetClassName()")) return;
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetClassName()")) return;
+ ENTER_V8(isolate);
Utils::OpenHandle(this)->set_class_name(*Utils::OpenHandle(*name));
}
void FunctionTemplate::SetHiddenPrototype(bool value) {
- if (IsDeadCheck("v8::FunctionTemplate::SetHiddenPrototype()")) return;
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetHiddenPrototype()")) {
+ return;
+ }
+ ENTER_V8(isolate);
Utils::OpenHandle(this)->set_hidden_prototype(value);
}
@@ -907,13 +982,15 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
Handle<Value> data) {
- if (IsDeadCheck("v8::FunctionTemplate::SetNamedInstancePropertyHandler()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate,
+ "v8::FunctionTemplate::SetNamedInstancePropertyHandler()")) {
return;
}
- ENTER_V8;
- HandleScope scope;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::Struct> struct_obj =
- i::Factory::NewStruct(i::INTERCEPTOR_INFO_TYPE);
+ isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE);
i::Handle<i::InterceptorInfo> obj =
i::Handle<i::InterceptorInfo>::cast(struct_obj);
@@ -936,14 +1013,15 @@ void FunctionTemplate::SetIndexedInstancePropertyHandler(
IndexedPropertyDeleter remover,
IndexedPropertyEnumerator enumerator,
Handle<Value> data) {
- if (IsDeadCheck(
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate,
"v8::FunctionTemplate::SetIndexedInstancePropertyHandler()")) {
return;
}
- ENTER_V8;
- HandleScope scope;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::Struct> struct_obj =
- i::Factory::NewStruct(i::INTERCEPTOR_INFO_TYPE);
+ isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE);
i::Handle<i::InterceptorInfo> obj =
i::Handle<i::InterceptorInfo>::cast(struct_obj);
@@ -962,13 +1040,15 @@ void FunctionTemplate::SetIndexedInstancePropertyHandler(
void FunctionTemplate::SetInstanceCallAsFunctionHandler(
InvocationCallback callback,
Handle<Value> data) {
- if (IsDeadCheck("v8::FunctionTemplate::SetInstanceCallAsFunctionHandler()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate,
+ "v8::FunctionTemplate::SetInstanceCallAsFunctionHandler()")) {
return;
}
- ENTER_V8;
- HandleScope scope;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::Struct> struct_obj =
- i::Factory::NewStruct(i::CALL_HANDLER_INFO_TYPE);
+ isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE);
i::Handle<i::CallHandlerInfo> obj =
i::Handle<i::CallHandlerInfo>::cast(struct_obj);
SET_FIELD_WRAPPED(obj, set_callback, callback);
@@ -988,12 +1068,15 @@ Local<ObjectTemplate> ObjectTemplate::New() {
Local<ObjectTemplate> ObjectTemplate::New(
v8::Handle<FunctionTemplate> constructor) {
- if (IsDeadCheck("v8::ObjectTemplate::New()")) return Local<ObjectTemplate>();
- EnsureInitialized("v8::ObjectTemplate::New()");
- LOG_API("ObjectTemplate::New");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::New()")) {
+ return Local<ObjectTemplate>();
+ }
+ EnsureInitializedForIsolate(isolate, "v8::ObjectTemplate::New()");
+ LOG_API(isolate, "ObjectTemplate::New");
+ ENTER_V8(isolate);
i::Handle<i::Struct> struct_obj =
- i::Factory::NewStruct(i::OBJECT_TEMPLATE_INFO_TYPE);
+ isolate->factory()->NewStruct(i::OBJECT_TEMPLATE_INFO_TYPE);
i::Handle<i::ObjectTemplateInfo> obj =
i::Handle<i::ObjectTemplateInfo>::cast(struct_obj);
InitializeTemplate(obj, Consts::OBJECT_TEMPLATE);
@@ -1022,9 +1105,10 @@ void ObjectTemplate::SetAccessor(v8::Handle<String> name,
v8::Handle<Value> data,
AccessControl settings,
PropertyAttribute attribute) {
- if (IsDeadCheck("v8::ObjectTemplate::SetAccessor()")) return;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
@@ -1044,9 +1128,12 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
Handle<Value> data) {
- if (IsDeadCheck("v8::ObjectTemplate::SetNamedPropertyHandler()")) return;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetNamedPropertyHandler()")) {
+ return;
+ }
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
@@ -1061,9 +1148,10 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
void ObjectTemplate::MarkAsUndetectable() {
- if (IsDeadCheck("v8::ObjectTemplate::MarkAsUndetectable()")) return;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::MarkAsUndetectable()")) return;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
@@ -1077,13 +1165,16 @@ void ObjectTemplate::SetAccessCheckCallbacks(
IndexedSecurityCallback indexed_callback,
Handle<Value> data,
bool turned_on_by_default) {
- if (IsDeadCheck("v8::ObjectTemplate::SetAccessCheckCallbacks()")) return;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessCheckCallbacks()")) {
+ return;
+ }
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
EnsureConstructor(this);
i::Handle<i::Struct> struct_info =
- i::Factory::NewStruct(i::ACCESS_CHECK_INFO_TYPE);
+ isolate->factory()->NewStruct(i::ACCESS_CHECK_INFO_TYPE);
i::Handle<i::AccessCheckInfo> info =
i::Handle<i::AccessCheckInfo>::cast(struct_info);
@@ -1108,9 +1199,12 @@ void ObjectTemplate::SetIndexedPropertyHandler(
IndexedPropertyDeleter remover,
IndexedPropertyEnumerator enumerator,
Handle<Value> data) {
- if (IsDeadCheck("v8::ObjectTemplate::SetIndexedPropertyHandler()")) return;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetIndexedPropertyHandler()")) {
+ return;
+ }
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
@@ -1126,9 +1220,13 @@ void ObjectTemplate::SetIndexedPropertyHandler(
void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback,
Handle<Value> data) {
- if (IsDeadCheck("v8::ObjectTemplate::SetCallAsFunctionHandler()")) return;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate,
+ "v8::ObjectTemplate::SetCallAsFunctionHandler()")) {
+ return;
+ }
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
@@ -1138,7 +1236,8 @@ void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback,
int ObjectTemplate::InternalFieldCount() {
- if (IsDeadCheck("v8::ObjectTemplate::InternalFieldCount()")) {
+ if (IsDeadCheck(Utils::OpenHandle(this)->GetIsolate(),
+ "v8::ObjectTemplate::InternalFieldCount()")) {
return 0;
}
return i::Smi::cast(Utils::OpenHandle(this)->internal_field_count())->value();
@@ -1146,13 +1245,16 @@ int ObjectTemplate::InternalFieldCount() {
void ObjectTemplate::SetInternalFieldCount(int value) {
- if (IsDeadCheck("v8::ObjectTemplate::SetInternalFieldCount()")) return;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetInternalFieldCount()")) {
+ return;
+ }
if (!ApiCheck(i::Smi::IsValid(value),
"v8::ObjectTemplate::SetInternalFieldCount()",
"Invalid internal field count")) {
return;
}
- ENTER_V8;
+ ENTER_V8(isolate);
if (value > 0) {
// The internal field count is set by the constructor function's
// construct code, so we ensure that there is a constructor
@@ -1214,9 +1316,10 @@ Local<Script> Script::New(v8::Handle<String> source,
v8::ScriptOrigin* origin,
v8::ScriptData* pre_data,
v8::Handle<String> script_data) {
- ON_BAILOUT("v8::Script::New()", return Local<Script>());
- LOG_API("Script::New");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>());
+ LOG_API(isolate, "Script::New");
+ ENTER_V8(isolate);
i::Handle<i::String> str = Utils::OpenHandle(*source);
i::Handle<i::Object> name_obj;
int line_offset = 0;
@@ -1232,7 +1335,7 @@ Local<Script> Script::New(v8::Handle<String> source,
column_offset = static_cast<int>(origin->ResourceColumnOffset()->Value());
}
}
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::ScriptDataImpl* pre_data_impl = static_cast<i::ScriptDataImpl*>(pre_data);
// We assert that the pre-data is sane, even though we can actually
// handle it if it turns out not to be in release mode.
@@ -1251,7 +1354,7 @@ Local<Script> Script::New(v8::Handle<String> source,
Utils::OpenHandle(*script_data),
i::NOT_NATIVES_CODE);
has_pending_exception = result.is_null();
- EXCEPTION_BAILOUT_CHECK(Local<Script>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
return Local<Script>(ToApi<Script>(result));
}
@@ -1267,9 +1370,10 @@ Local<Script> Script::Compile(v8::Handle<String> source,
v8::ScriptOrigin* origin,
v8::ScriptData* pre_data,
v8::Handle<String> script_data) {
- ON_BAILOUT("v8::Script::Compile()", return Local<Script>());
- LOG_API("Script::Compile");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>());
+ LOG_API(isolate, "Script::Compile");
+ ENTER_V8(isolate);
Local<Script> generic = New(source, origin, pre_data, script_data);
if (generic.IsEmpty())
return generic;
@@ -1277,8 +1381,9 @@ Local<Script> Script::Compile(v8::Handle<String> source,
i::Handle<i::SharedFunctionInfo> function =
i::Handle<i::SharedFunctionInfo>(i::SharedFunctionInfo::cast(*obj));
i::Handle<i::JSFunction> result =
- i::Factory::NewFunctionFromSharedFunctionInfo(function,
- i::Top::global_context());
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ function,
+ isolate->global_context());
return Local<Script>(ToApi<Script>(result));
}
@@ -1292,30 +1397,32 @@ Local<Script> Script::Compile(v8::Handle<String> source,
Local<Value> Script::Run() {
- ON_BAILOUT("v8::Script::Run()", return Local<Value>());
- LOG_API("Script::Run");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>());
+ LOG_API(isolate, "Script::Run");
+ ENTER_V8(isolate);
i::Object* raw_result = NULL;
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::JSFunction> fun;
if (obj->IsSharedFunctionInfo()) {
i::Handle<i::SharedFunctionInfo>
- function_info(i::SharedFunctionInfo::cast(*obj));
- fun = i::Factory::NewFunctionFromSharedFunctionInfo(
- function_info, i::Top::global_context());
+ function_info(i::SharedFunctionInfo::cast(*obj), isolate);
+ fun = isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ function_info, isolate->global_context());
} else {
- fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj));
+ fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
}
- EXCEPTION_PREAMBLE();
- i::Handle<i::Object> receiver(i::Top::context()->global_proxy());
+ EXCEPTION_PREAMBLE(isolate);
+ i::Handle<i::Object> receiver(
+ isolate->context()->global_proxy(), isolate);
i::Handle<i::Object> result =
i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<Value>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
raw_result = *result;
}
- i::Handle<i::Object> result(raw_result);
+ i::Handle<i::Object> result(raw_result, isolate);
return Utils::ToLocal(result);
}
@@ -1335,11 +1442,12 @@ static i::Handle<i::SharedFunctionInfo> OpenScript(Script* script) {
Local<Value> Script::Id() {
- ON_BAILOUT("v8::Script::Id()", return Local<Value>());
- LOG_API("Script::Id");
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::Id()", return Local<Value>());
+ LOG_API(isolate, "Script::Id");
i::Object* raw_id = NULL;
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::SharedFunctionInfo> function_info = OpenScript(this);
i::Handle<i::Script> script(i::Script::cast(function_info->script()));
i::Handle<i::Object> id(script->id());
@@ -1351,10 +1459,11 @@ Local<Value> Script::Id() {
void Script::SetData(v8::Handle<String> data) {
- ON_BAILOUT("v8::Script::SetData()", return);
- LOG_API("Script::SetData");
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::SetData()", return);
+ LOG_API(isolate, "Script::SetData");
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::SharedFunctionInfo> function_info = OpenScript(this);
i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
i::Handle<i::Script> script(i::Script::cast(function_info->script()));
@@ -1367,25 +1476,26 @@ void Script::SetData(v8::Handle<String> data) {
v8::TryCatch::TryCatch()
- : next_(i::Top::try_catch_handler_address()),
- exception_(i::Heap::the_hole_value()),
+ : next_(i::Isolate::Current()->try_catch_handler_address()),
+ exception_(HEAP->the_hole_value()),
message_(i::Smi::FromInt(0)),
is_verbose_(false),
can_continue_(true),
capture_message_(true),
rethrow_(false) {
- i::Top::RegisterTryCatchHandler(this);
+ i::Isolate::Current()->RegisterTryCatchHandler(this);
}
v8::TryCatch::~TryCatch() {
+ i::Isolate* isolate = i::Isolate::Current();
if (rethrow_) {
v8::HandleScope scope;
v8::Local<v8::Value> exc = v8::Local<v8::Value>::New(Exception());
- i::Top::UnregisterTryCatchHandler(this);
+ isolate->UnregisterTryCatchHandler(this);
v8::ThrowException(exc);
} else {
- i::Top::UnregisterTryCatchHandler(this);
+ isolate->UnregisterTryCatchHandler(this);
}
}
@@ -1424,7 +1534,7 @@ v8::Local<Value> v8::TryCatch::StackTrace() const {
if (!raw_obj->IsJSObject()) return v8::Local<Value>();
v8::HandleScope scope;
i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj));
- i::Handle<i::String> name = i::Factory::LookupAsciiSymbol("stack");
+ i::Handle<i::String> name = FACTORY->LookupAsciiSymbol("stack");
if (!obj->HasProperty(*name))
return v8::Local<Value>();
return scope.Close(v8::Utils::ToLocal(i::GetProperty(obj, name)));
@@ -1445,7 +1555,7 @@ v8::Local<v8::Message> v8::TryCatch::Message() const {
void v8::TryCatch::Reset() {
- exception_ = i::Heap::the_hole_value();
+ exception_ = HEAP->the_hole_value();
message_ = i::Smi::FromInt(0);
}
@@ -1464,8 +1574,9 @@ void v8::TryCatch::SetCaptureMessage(bool value) {
Local<String> Message::Get() const {
- ON_BAILOUT("v8::Message::Get()", return Local<String>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Message::Get()", return Local<String>());
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::String> raw_result = i::MessageHandler::GetMessage(obj);
@@ -1475,10 +1586,11 @@ Local<String> Message::Get() const {
v8::Handle<Value> Message::GetScriptResourceName() const {
- if (IsDeadCheck("v8::Message::GetScriptResourceName()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Message::GetScriptResourceName()")) {
return Local<String>();
}
- ENTER_V8;
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
@@ -1491,10 +1603,11 @@ v8::Handle<Value> Message::GetScriptResourceName() const {
v8::Handle<Value> Message::GetScriptData() const {
- if (IsDeadCheck("v8::Message::GetScriptResourceData()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Message::GetScriptResourceData()")) {
return Local<Value>();
}
- ENTER_V8;
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
@@ -1507,10 +1620,11 @@ v8::Handle<Value> Message::GetScriptData() const {
v8::Handle<v8::StackTrace> Message::GetStackTrace() const {
- if (IsDeadCheck("v8::Message::GetStackTrace()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Message::GetStackTrace()")) {
return Local<v8::StackTrace>();
}
- ENTER_V8;
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
@@ -1527,9 +1641,10 @@ static i::Handle<i::Object> CallV8HeapFunction(const char* name,
int argc,
i::Object** argv[],
bool* has_pending_exception) {
- i::Handle<i::String> fmt_str = i::Factory::LookupAsciiSymbol(name);
+ i::Isolate* isolate = i::Isolate::Current();
+ i::Handle<i::String> fmt_str = isolate->factory()->LookupAsciiSymbol(name);
i::Object* object_fun =
- i::Top::builtins()->GetPropertyNoExceptionThrown(*fmt_str);
+ isolate->js_builtins_object()->GetPropertyNoExceptionThrown(*fmt_str);
i::Handle<i::JSFunction> fun =
i::Handle<i::JSFunction>(i::JSFunction::cast(object_fun));
i::Handle<i::Object> value =
@@ -1543,7 +1658,7 @@ static i::Handle<i::Object> CallV8HeapFunction(const char* name,
bool* has_pending_exception) {
i::Object** argv[1] = { data.location() };
return CallV8HeapFunction(name,
- i::Top::builtins(),
+ i::Isolate::Current()->js_builtins_object(),
1,
argv,
has_pending_exception);
@@ -1551,23 +1666,25 @@ static i::Handle<i::Object> CallV8HeapFunction(const char* name,
int Message::GetLineNumber() const {
- ON_BAILOUT("v8::Message::GetLineNumber()", return kNoLineNumberInfo);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Message::GetLineNumber()", return kNoLineNumberInfo);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = CallV8HeapFunction("GetLineNumber",
Utils::OpenHandle(this),
&has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(0);
+ EXCEPTION_BAILOUT_CHECK(isolate, 0);
return static_cast<int>(result->Number());
}
int Message::GetStartPosition() const {
- if (IsDeadCheck("v8::Message::GetStartPosition()")) return 0;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Message::GetStartPosition()")) return 0;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
return message->start_position();
@@ -1575,9 +1692,10 @@ int Message::GetStartPosition() const {
int Message::GetEndPosition() const {
- if (IsDeadCheck("v8::Message::GetEndPosition()")) return 0;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Message::GetEndPosition()")) return 0;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
return message->end_position();
@@ -1585,31 +1703,35 @@ int Message::GetEndPosition() const {
int Message::GetStartColumn() const {
- if (IsDeadCheck("v8::Message::GetStartColumn()")) return kNoColumnInfo;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Message::GetStartColumn()")) {
+ return kNoColumnInfo;
+ }
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
"GetPositionInLine",
data_obj,
&has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(0);
+ EXCEPTION_BAILOUT_CHECK(isolate, 0);
return static_cast<int>(start_col_obj->Number());
}
int Message::GetEndColumn() const {
- if (IsDeadCheck("v8::Message::GetEndColumn()")) return kNoColumnInfo;
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Message::GetEndColumn()")) return kNoColumnInfo;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
"GetPositionInLine",
data_obj,
&has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(0);
+ EXCEPTION_BAILOUT_CHECK(isolate, 0);
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(data_obj);
int start = message->start_position();
@@ -1619,14 +1741,15 @@ int Message::GetEndColumn() const {
Local<String> Message::GetSourceLine() const {
- ON_BAILOUT("v8::Message::GetSourceLine()", return Local<String>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Message::GetSourceLine()", return Local<String>());
+ ENTER_V8(isolate);
HandleScope scope;
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = CallV8HeapFunction("GetSourceLine",
Utils::OpenHandle(this),
&has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<v8::String>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::String>());
if (result->IsString()) {
return scope.Close(Utils::ToLocal(i::Handle<i::String>::cast(result)));
} else {
@@ -1636,17 +1759,21 @@ Local<String> Message::GetSourceLine() const {
void Message::PrintCurrentStackTrace(FILE* out) {
- if (IsDeadCheck("v8::Message::PrintCurrentStackTrace()")) return;
- ENTER_V8;
- i::Top::PrintCurrentStackTrace(out);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Message::PrintCurrentStackTrace()")) return;
+ ENTER_V8(isolate);
+ isolate->PrintCurrentStackTrace(out);
}
// --- S t a c k T r a c e ---
Local<StackFrame> StackTrace::GetFrame(uint32_t index) const {
- if (IsDeadCheck("v8::StackTrace::GetFrame()")) return Local<StackFrame>();
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackTrace::GetFrame()")) {
+ return Local<StackFrame>();
+ }
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::JSArray> self = Utils::OpenHandle(this);
i::Object* raw_object = self->GetElementNoExceptionThrown(index);
@@ -1656,25 +1783,30 @@ Local<StackFrame> StackTrace::GetFrame(uint32_t index) const {
int StackTrace::GetFrameCount() const {
- if (IsDeadCheck("v8::StackTrace::GetFrameCount()")) return -1;
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackTrace::GetFrameCount()")) return -1;
+ ENTER_V8(isolate);
return i::Smi::cast(Utils::OpenHandle(this)->length())->value();
}
Local<Array> StackTrace::AsArray() {
- if (IsDeadCheck("v8::StackTrace::AsArray()")) Local<Array>();
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackTrace::AsArray()")) Local<Array>();
+ ENTER_V8(isolate);
return Utils::ToLocal(Utils::OpenHandle(this));
}
Local<StackTrace> StackTrace::CurrentStackTrace(int frame_limit,
StackTraceOptions options) {
- if (IsDeadCheck("v8::StackTrace::CurrentStackTrace()")) Local<StackTrace>();
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::StackTrace::CurrentStackTrace()")) {
+ Local<StackTrace>();
+ }
+ ENTER_V8(isolate);
i::Handle<i::JSArray> stackTrace =
- i::Top::CaptureCurrentStackTrace(frame_limit, options);
+ isolate->CaptureCurrentStackTrace(frame_limit, options);
return Utils::StackTraceToLocal(stackTrace);
}
@@ -1682,11 +1814,12 @@ Local<StackTrace> StackTrace::CurrentStackTrace(int frame_limit,
// --- S t a c k F r a m e ---
int StackFrame::GetLineNumber() const {
- if (IsDeadCheck("v8::StackFrame::GetLineNumber()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackFrame::GetLineNumber()")) {
return Message::kNoLineNumberInfo;
}
- ENTER_V8;
- i::HandleScope scope;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> line = GetProperty(self, "lineNumber");
if (!line->IsSmi()) {
@@ -1697,11 +1830,12 @@ int StackFrame::GetLineNumber() const {
int StackFrame::GetColumn() const {
- if (IsDeadCheck("v8::StackFrame::GetColumn()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackFrame::GetColumn()")) {
return Message::kNoColumnInfo;
}
- ENTER_V8;
- i::HandleScope scope;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> column = GetProperty(self, "column");
if (!column->IsSmi()) {
@@ -1712,8 +1846,11 @@ int StackFrame::GetColumn() const {
Local<String> StackFrame::GetScriptName() const {
- if (IsDeadCheck("v8::StackFrame::GetScriptName()")) return Local<String>();
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackFrame::GetScriptName()")) {
+ return Local<String>();
+ }
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> name = GetProperty(self, "scriptName");
@@ -1725,10 +1862,11 @@ Local<String> StackFrame::GetScriptName() const {
Local<String> StackFrame::GetScriptNameOrSourceURL() const {
- if (IsDeadCheck("v8::StackFrame::GetScriptNameOrSourceURL()")) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackFrame::GetScriptNameOrSourceURL()")) {
return Local<String>();
}
- ENTER_V8;
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> name = GetProperty(self, "scriptNameOrSourceURL");
@@ -1740,8 +1878,11 @@ Local<String> StackFrame::GetScriptNameOrSourceURL() const {
Local<String> StackFrame::GetFunctionName() const {
- if (IsDeadCheck("v8::StackFrame::GetFunctionName()")) return Local<String>();
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackFrame::GetFunctionName()")) {
+ return Local<String>();
+ }
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> name = GetProperty(self, "functionName");
@@ -1753,9 +1894,10 @@ Local<String> StackFrame::GetFunctionName() const {
bool StackFrame::IsEval() const {
- if (IsDeadCheck("v8::StackFrame::IsEval()")) return false;
- ENTER_V8;
- i::HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackFrame::IsEval()")) return false;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> is_eval = GetProperty(self, "isEval");
return is_eval->IsTrue();
@@ -1763,9 +1905,10 @@ bool StackFrame::IsEval() const {
bool StackFrame::IsConstructor() const {
- if (IsDeadCheck("v8::StackFrame::IsConstructor()")) return false;
- ENTER_V8;
- i::HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::StackFrame::IsConstructor()")) return false;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> is_constructor = GetProperty(self, "isConstructor");
return is_constructor->IsTrue();
@@ -1775,37 +1918,41 @@ bool StackFrame::IsConstructor() const {
// --- D a t a ---
bool Value::IsUndefined() const {
- if (IsDeadCheck("v8::Value::IsUndefined()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsUndefined()")) {
+ return false;
+ }
return Utils::OpenHandle(this)->IsUndefined();
}
bool Value::IsNull() const {
- if (IsDeadCheck("v8::Value::IsNull()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsNull()")) return false;
return Utils::OpenHandle(this)->IsNull();
}
bool Value::IsTrue() const {
- if (IsDeadCheck("v8::Value::IsTrue()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsTrue()")) return false;
return Utils::OpenHandle(this)->IsTrue();
}
bool Value::IsFalse() const {
- if (IsDeadCheck("v8::Value::IsFalse()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsFalse()")) return false;
return Utils::OpenHandle(this)->IsFalse();
}
bool Value::IsFunction() const {
- if (IsDeadCheck("v8::Value::IsFunction()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsFunction()")) {
+ return false;
+ }
return Utils::OpenHandle(this)->IsJSFunction();
}
bool Value::FullIsString() const {
- if (IsDeadCheck("v8::Value::IsString()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsString()")) return false;
bool result = Utils::OpenHandle(this)->IsString();
ASSERT_EQ(result, QuickIsString());
return result;
@@ -1813,37 +1960,41 @@ bool Value::FullIsString() const {
bool Value::IsArray() const {
- if (IsDeadCheck("v8::Value::IsArray()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsArray()")) return false;
return Utils::OpenHandle(this)->IsJSArray();
}
bool Value::IsObject() const {
- if (IsDeadCheck("v8::Value::IsObject()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsObject()")) return false;
return Utils::OpenHandle(this)->IsJSObject();
}
bool Value::IsNumber() const {
- if (IsDeadCheck("v8::Value::IsNumber()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsNumber()")) return false;
return Utils::OpenHandle(this)->IsNumber();
}
bool Value::IsBoolean() const {
- if (IsDeadCheck("v8::Value::IsBoolean()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsBoolean()")) {
+ return false;
+ }
return Utils::OpenHandle(this)->IsBoolean();
}
bool Value::IsExternal() const {
- if (IsDeadCheck("v8::Value::IsExternal()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsExternal()")) {
+ return false;
+ }
return Utils::OpenHandle(this)->IsProxy();
}
bool Value::IsInt32() const {
- if (IsDeadCheck("v8::Value::IsInt32()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsInt32()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsSmi()) return true;
if (obj->IsNumber()) {
@@ -1855,7 +2006,7 @@ bool Value::IsInt32() const {
bool Value::IsUint32() const {
- if (IsDeadCheck("v8::Value::IsUint32()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsUint32()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsSmi()) return i::Smi::cast(*obj)->value() >= 0;
if (obj->IsNumber()) {
@@ -1867,78 +2018,91 @@ bool Value::IsUint32() const {
bool Value::IsDate() const {
- if (IsDeadCheck("v8::Value::IsDate()")) return false;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::IsDate()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
- return obj->HasSpecificClassOf(i::Heap::Date_symbol());
+ return obj->HasSpecificClassOf(isolate->heap()->Date_symbol());
}
bool Value::IsRegExp() const {
- if (IsDeadCheck("v8::Value::IsRegExp()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsRegExp()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
return obj->IsJSRegExp();
}
Local<String> Value::ToString() const {
- if (IsDeadCheck("v8::Value::ToString()")) return Local<String>();
- LOG_API("ToString");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> str;
if (obj->IsString()) {
str = obj;
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::ToString()")) {
+ return Local<String>();
+ }
+ LOG_API(isolate, "ToString");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
str = i::Execution::ToString(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<String>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<String>());
}
return Local<String>(ToApi<String>(str));
}
Local<String> Value::ToDetailString() const {
- if (IsDeadCheck("v8::Value::ToDetailString()")) return Local<String>();
- LOG_API("ToDetailString");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> str;
if (obj->IsString()) {
str = obj;
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::ToDetailString()")) {
+ return Local<String>();
+ }
+ LOG_API(isolate, "ToDetailString");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
str = i::Execution::ToDetailString(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<String>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<String>());
}
return Local<String>(ToApi<String>(str));
}
Local<v8::Object> Value::ToObject() const {
- if (IsDeadCheck("v8::Value::ToObject()")) return Local<v8::Object>();
- LOG_API("ToObject");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> val;
if (obj->IsJSObject()) {
val = obj;
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::ToObject()")) {
+ return Local<v8::Object>();
+ }
+ LOG_API(isolate, "ToObject");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
val = i::Execution::ToObject(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<v8::Object>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
}
return Local<v8::Object>(ToApi<Object>(val));
}
Local<Boolean> Value::ToBoolean() const {
- if (IsDeadCheck("v8::Value::ToBoolean()")) return Local<Boolean>();
- LOG_API("ToBoolean");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsBoolean()) {
return Local<Boolean>(ToApi<Boolean>(obj));
} else {
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::ToBoolean()")) {
+ return Local<Boolean>();
+ }
+ LOG_API(isolate, "ToBoolean");
+ ENTER_V8(isolate);
i::Handle<i::Object> val = i::Execution::ToBoolean(obj);
return Local<Boolean>(ToApi<Boolean>(val));
}
@@ -1946,41 +2110,45 @@ Local<Boolean> Value::ToBoolean() const {
Local<Number> Value::ToNumber() const {
- if (IsDeadCheck("v8::Value::ToNumber()")) return Local<Number>();
- LOG_API("ToNumber");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> num;
if (obj->IsNumber()) {
num = obj;
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::ToNumber()")) {
+ return Local<Number>();
+ }
+ LOG_API(isolate, "ToNumber");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
num = i::Execution::ToNumber(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<Number>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Number>());
}
return Local<Number>(ToApi<Number>(num));
}
Local<Integer> Value::ToInteger() const {
- if (IsDeadCheck("v8::Value::ToInteger()")) return Local<Integer>();
- LOG_API("ToInteger");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> num;
if (obj->IsSmi()) {
num = obj;
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::ToInteger()")) return Local<Integer>();
+ LOG_API(isolate, "ToInteger");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
num = i::Execution::ToInteger(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<Integer>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Integer>());
}
return Local<Integer>(ToApi<Integer>(num));
}
void External::CheckCast(v8::Value* that) {
- if (IsDeadCheck("v8::External::Cast()")) return;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::External::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->IsProxy(),
"v8::External::Cast()",
@@ -1989,7 +2157,7 @@ void External::CheckCast(v8::Value* that) {
void v8::Object::CheckCast(Value* that) {
- if (IsDeadCheck("v8::Object::Cast()")) return;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Object::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->IsJSObject(),
"v8::Object::Cast()",
@@ -1998,7 +2166,7 @@ void v8::Object::CheckCast(Value* that) {
void v8::Function::CheckCast(Value* that) {
- if (IsDeadCheck("v8::Function::Cast()")) return;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Function::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->IsJSFunction(),
"v8::Function::Cast()",
@@ -2007,7 +2175,7 @@ void v8::Function::CheckCast(Value* that) {
void v8::String::CheckCast(v8::Value* that) {
- if (IsDeadCheck("v8::String::Cast()")) return;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::String::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->IsString(),
"v8::String::Cast()",
@@ -2016,7 +2184,7 @@ void v8::String::CheckCast(v8::Value* that) {
void v8::Number::CheckCast(v8::Value* that) {
- if (IsDeadCheck("v8::Number::Cast()")) return;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Number::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->IsNumber(),
"v8::Number::Cast()",
@@ -2025,7 +2193,7 @@ void v8::Number::CheckCast(v8::Value* that) {
void v8::Integer::CheckCast(v8::Value* that) {
- if (IsDeadCheck("v8::Integer::Cast()")) return;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Integer::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->IsNumber(),
"v8::Integer::Cast()",
@@ -2034,7 +2202,7 @@ void v8::Integer::CheckCast(v8::Value* that) {
void v8::Array::CheckCast(Value* that) {
- if (IsDeadCheck("v8::Array::Cast()")) return;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Array::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->IsJSArray(),
"v8::Array::Cast()",
@@ -2043,16 +2211,17 @@ void v8::Array::CheckCast(Value* that) {
void v8::Date::CheckCast(v8::Value* that) {
- if (IsDeadCheck("v8::Date::Cast()")) return;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Date::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
- ApiCheck(obj->HasSpecificClassOf(i::Heap::Date_symbol()),
+ ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Date_symbol()),
"v8::Date::Cast()",
"Could not convert to date");
}
void v8::RegExp::CheckCast(v8::Value* that) {
- if (IsDeadCheck("v8::RegExp::Cast()")) return;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::RegExp::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->IsJSRegExp(),
"v8::RegExp::Cast()",
@@ -2061,13 +2230,14 @@ void v8::RegExp::CheckCast(v8::Value* that) {
bool Value::BooleanValue() const {
- if (IsDeadCheck("v8::Value::BooleanValue()")) return false;
- LOG_API("BooleanValue");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsBoolean()) {
return obj->IsTrue();
} else {
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::BooleanValue()")) return false;
+ LOG_API(isolate, "BooleanValue");
+ ENTER_V8(isolate);
i::Handle<i::Object> value = i::Execution::ToBoolean(obj);
return value->IsTrue();
}
@@ -2075,34 +2245,38 @@ bool Value::BooleanValue() const {
double Value::NumberValue() const {
- if (IsDeadCheck("v8::Value::NumberValue()")) return i::OS::nan_value();
- LOG_API("NumberValue");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> num;
if (obj->IsNumber()) {
num = obj;
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::NumberValue()")) {
+ return i::OS::nan_value();
+ }
+ LOG_API(isolate, "NumberValue");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
num = i::Execution::ToNumber(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(i::OS::nan_value());
+ EXCEPTION_BAILOUT_CHECK(isolate, i::OS::nan_value());
}
return num->Number();
}
int64_t Value::IntegerValue() const {
- if (IsDeadCheck("v8::Value::IntegerValue()")) return 0;
- LOG_API("IntegerValue");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> num;
if (obj->IsNumber()) {
num = obj;
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::IntegerValue()")) return 0;
+ LOG_API(isolate, "IntegerValue");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
num = i::Execution::ToInteger(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(0);
+ EXCEPTION_BAILOUT_CHECK(isolate, 0);
}
if (num->IsSmi()) {
return i::Smi::cast(*num)->value();
@@ -2113,52 +2287,55 @@ int64_t Value::IntegerValue() const {
Local<Int32> Value::ToInt32() const {
- if (IsDeadCheck("v8::Value::ToInt32()")) return Local<Int32>();
- LOG_API("ToInt32");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> num;
if (obj->IsSmi()) {
num = obj;
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::ToInt32()")) return Local<Int32>();
+ LOG_API(isolate, "ToInt32");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
num = i::Execution::ToInt32(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<Int32>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Int32>());
}
return Local<Int32>(ToApi<Int32>(num));
}
Local<Uint32> Value::ToUint32() const {
- if (IsDeadCheck("v8::Value::ToUint32()")) return Local<Uint32>();
- LOG_API("ToUInt32");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> num;
if (obj->IsSmi()) {
num = obj;
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::ToUint32()")) return Local<Uint32>();
+ LOG_API(isolate, "ToUInt32");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
num = i::Execution::ToUint32(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<Uint32>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Uint32>());
}
return Local<Uint32>(ToApi<Uint32>(num));
}
Local<Uint32> Value::ToArrayIndex() const {
- if (IsDeadCheck("v8::Value::ToArrayIndex()")) return Local<Uint32>();
- LOG_API("ToArrayIndex");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsSmi()) {
if (i::Smi::cast(*obj)->value() >= 0) return Utils::Uint32ToLocal(obj);
return Local<Uint32>();
}
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::ToArrayIndex()")) return Local<Uint32>();
+ LOG_API(isolate, "ToArrayIndex");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> string_obj =
i::Execution::ToString(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<Uint32>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Uint32>());
i::Handle<i::String> str = i::Handle<i::String>::cast(string_obj);
uint32_t index;
if (str->AsArrayIndex(&index)) {
@@ -2166,7 +2343,7 @@ Local<Uint32> Value::ToArrayIndex() const {
if (index <= static_cast<uint32_t>(i::Smi::kMaxValue)) {
value = i::Handle<i::Object>(i::Smi::FromInt(index));
} else {
- value = i::Factory::NewNumber(index);
+ value = isolate->factory()->NewNumber(index);
}
return Utils::Uint32ToLocal(value);
}
@@ -2175,18 +2352,18 @@ Local<Uint32> Value::ToArrayIndex() const {
int32_t Value::Int32Value() const {
- if (IsDeadCheck("v8::Value::Int32Value()")) return 0;
- LOG_API("Int32Value");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsSmi()) {
return i::Smi::cast(*obj)->value();
} else {
- LOG_API("Int32Value (slow)");
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::Int32Value()")) return 0;
+ LOG_API(isolate, "Int32Value (slow)");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> num =
i::Execution::ToInt32(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(0);
+ EXCEPTION_BAILOUT_CHECK(isolate, 0);
if (num->IsSmi()) {
return i::Smi::cast(*num)->value();
} else {
@@ -2197,13 +2374,14 @@ int32_t Value::Int32Value() const {
bool Value::Equals(Handle<Value> that) const {
- if (IsDeadCheck("v8::Value::Equals()")
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::Equals()")
|| EmptyCheck("v8::Value::Equals()", this)
|| EmptyCheck("v8::Value::Equals()", that)) {
return false;
}
- LOG_API("Equals");
- ENTER_V8;
+ LOG_API(isolate, "Equals");
+ ENTER_V8(isolate);
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> other = Utils::OpenHandle(*that);
// If both obj and other are JSObjects, we'd better compare by identity
@@ -2213,21 +2391,22 @@ bool Value::Equals(Handle<Value> that) const {
return *obj == *other;
}
i::Object** args[1] = { other.location() };
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result =
CallV8HeapFunction("EQUALS", obj, 1, args, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(false);
+ EXCEPTION_BAILOUT_CHECK(isolate, false);
return *result == i::Smi::FromInt(i::EQUAL);
}
bool Value::StrictEquals(Handle<Value> that) const {
- if (IsDeadCheck("v8::Value::StrictEquals()")
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::StrictEquals()")
|| EmptyCheck("v8::Value::StrictEquals()", this)
|| EmptyCheck("v8::Value::StrictEquals()", that)) {
return false;
}
- LOG_API("StrictEquals");
+ LOG_API(isolate, "StrictEquals");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> other = Utils::OpenHandle(*that);
// Must check HeapNumber first, since NaN !== NaN.
@@ -2253,17 +2432,18 @@ bool Value::StrictEquals(Handle<Value> that) const {
uint32_t Value::Uint32Value() const {
- if (IsDeadCheck("v8::Value::Uint32Value()")) return 0;
- LOG_API("Uint32Value");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsSmi()) {
return i::Smi::cast(*obj)->value();
} else {
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Value::Uint32Value()")) return 0;
+ LOG_API(isolate, "Uint32Value");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> num =
i::Execution::ToUint32(obj, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(0);
+ EXCEPTION_BAILOUT_CHECK(isolate, 0);
if (num->IsSmi()) {
return i::Smi::cast(*num)->value();
} else {
@@ -2275,13 +2455,14 @@ uint32_t Value::Uint32Value() const {
bool v8::Object::Set(v8::Handle<Value> key, v8::Handle<Value> value,
v8::PropertyAttribute attribs) {
- ON_BAILOUT("v8::Object::Set()", return false);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::Set()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::Object> self = Utils::OpenHandle(this);
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj = i::SetProperty(
self,
key_obj,
@@ -2289,25 +2470,26 @@ bool v8::Object::Set(v8::Handle<Value> key, v8::Handle<Value> value,
static_cast<PropertyAttributes>(attribs),
i::kNonStrictMode);
has_pending_exception = obj.is_null();
- EXCEPTION_BAILOUT_CHECK(false);
+ EXCEPTION_BAILOUT_CHECK(isolate, false);
return true;
}
bool v8::Object::Set(uint32_t index, v8::Handle<Value> value) {
- ON_BAILOUT("v8::Object::Set()", return false);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::Set()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj = i::SetElement(
self,
index,
value_obj,
i::kNonStrictMode);
has_pending_exception = obj.is_null();
- EXCEPTION_BAILOUT_CHECK(false);
+ EXCEPTION_BAILOUT_CHECK(isolate, false);
return true;
}
@@ -2315,28 +2497,30 @@ bool v8::Object::Set(uint32_t index, v8::Handle<Value> value) {
bool v8::Object::ForceSet(v8::Handle<Value> key,
v8::Handle<Value> value,
v8::PropertyAttribute attribs) {
- ON_BAILOUT("v8::Object::ForceSet()", return false);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::ForceSet()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj = i::ForceSetProperty(
self,
key_obj,
value_obj,
static_cast<PropertyAttributes>(attribs));
has_pending_exception = obj.is_null();
- EXCEPTION_BAILOUT_CHECK(false);
+ EXCEPTION_BAILOUT_CHECK(isolate, false);
return true;
}
bool v8::Object::ForceDelete(v8::Handle<Value> key) {
- ON_BAILOUT("v8::Object::ForceDelete()", return false);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::ForceDelete()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
@@ -2344,42 +2528,46 @@ bool v8::Object::ForceDelete(v8::Handle<Value> key) {
// as optimized code does not always handle access checks.
i::Deoptimizer::DeoptimizeGlobalObject(*self);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj = i::ForceDeleteProperty(self, key_obj);
has_pending_exception = obj.is_null();
- EXCEPTION_BAILOUT_CHECK(false);
+ EXCEPTION_BAILOUT_CHECK(isolate, false);
return obj->IsTrue();
}
Local<Value> v8::Object::Get(v8::Handle<Value> key) {
- ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::Get()", return Local<v8::Value>());
+ ENTER_V8(isolate);
i::Handle<i::Object> self = Utils::OpenHandle(this);
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = i::GetProperty(self, key_obj);
has_pending_exception = result.is_null();
- EXCEPTION_BAILOUT_CHECK(Local<Value>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
return Utils::ToLocal(result);
}
Local<Value> v8::Object::Get(uint32_t index) {
- ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::Get()", return Local<v8::Value>());
+ ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = i::GetElement(self, index);
has_pending_exception = result.is_null();
- EXCEPTION_BAILOUT_CHECK(Local<Value>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
return Utils::ToLocal(result);
}
Local<Value> v8::Object::GetPrototype() {
- ON_BAILOUT("v8::Object::GetPrototype()", return Local<v8::Value>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::GetPrototype()",
+ return Local<v8::Value>());
+ ENTER_V8(isolate);
i::Handle<i::Object> self = Utils::OpenHandle(this);
i::Handle<i::Object> result = i::GetPrototype(self);
return Utils::ToLocal(result);
@@ -2387,23 +2575,26 @@ Local<Value> v8::Object::GetPrototype() {
bool v8::Object::SetPrototype(Handle<Value> value) {
- ON_BAILOUT("v8::Object::SetPrototype()", return false);
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::SetPrototype()", return false);
+ ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = i::SetPrototype(self, value_obj);
has_pending_exception = result.is_null();
- EXCEPTION_BAILOUT_CHECK(false);
+ EXCEPTION_BAILOUT_CHECK(isolate, false);
return true;
}
Local<Object> v8::Object::FindInstanceInPrototypeChain(
v8::Handle<FunctionTemplate> tmpl) {
- ON_BAILOUT("v8::Object::FindInstanceInPrototypeChain()",
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate,
+ "v8::Object::FindInstanceInPrototypeChain()",
return Local<v8::Object>());
- ENTER_V8;
+ ENTER_V8(isolate);
i::JSObject* object = *Utils::OpenHandle(this);
i::FunctionTemplateInfo* tmpl_info = *Utils::OpenHandle(*tmpl);
while (!object->IsInstanceOf(tmpl_info)) {
@@ -2416,24 +2607,29 @@ Local<Object> v8::Object::FindInstanceInPrototypeChain(
Local<Array> v8::Object::GetPropertyNames() {
- ON_BAILOUT("v8::Object::GetPropertyNames()", return Local<v8::Array>());
- ENTER_V8;
- v8::HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::GetPropertyNames()",
+ return Local<v8::Array>());
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::FixedArray> value =
i::GetKeysInFixedArrayFor(self, i::INCLUDE_PROTOS);
// Because we use caching to speed up enumeration it is important
// to never change the result of the basic enumeration function so
// we clone the result.
- i::Handle<i::FixedArray> elms = i::Factory::CopyFixedArray(value);
- i::Handle<i::JSArray> result = i::Factory::NewJSArrayWithElements(elms);
- return scope.Close(Utils::ToLocal(result));
+ i::Handle<i::FixedArray> elms = isolate->factory()->CopyFixedArray(value);
+ i::Handle<i::JSArray> result =
+ isolate->factory()->NewJSArrayWithElements(elms);
+ return Utils::ToLocal(scope.CloseAndEscape(result));
}
Local<String> v8::Object::ObjectProtoToString() {
- ON_BAILOUT("v8::Object::ObjectProtoToString()", return Local<v8::String>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::ObjectProtoToString()",
+ return Local<v8::String>());
+ ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> name(self->class_name());
@@ -2484,8 +2680,10 @@ Local<String> v8::Object::ObjectProtoToString() {
Local<String> v8::Object::GetConstructorName() {
- ON_BAILOUT("v8::Object::GetConstructorName()", return Local<v8::String>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::GetConstructorName()",
+ return Local<v8::String>());
+ ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> name(self->constructor_name());
return Utils::ToLocal(name);
@@ -2493,9 +2691,10 @@ Local<String> v8::Object::GetConstructorName() {
bool v8::Object::Delete(v8::Handle<String> key) {
- ON_BAILOUT("v8::Object::Delete()", return false);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::Delete()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
return i::DeleteProperty(self, key_obj)->IsTrue();
@@ -2503,8 +2702,9 @@ bool v8::Object::Delete(v8::Handle<String> key) {
bool v8::Object::Has(v8::Handle<String> key) {
- ON_BAILOUT("v8::Object::Has()", return false);
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::Has()", return false);
+ ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
return self->HasProperty(*key_obj);
@@ -2512,8 +2712,10 @@ bool v8::Object::Has(v8::Handle<String> key) {
bool v8::Object::Delete(uint32_t index) {
- ON_BAILOUT("v8::Object::DeleteProperty()", return false);
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::DeleteProperty()",
+ return false);
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
return i::DeleteElement(self, index)->IsTrue();
@@ -2521,7 +2723,8 @@ bool v8::Object::Delete(uint32_t index) {
bool v8::Object::Has(uint32_t index) {
- ON_BAILOUT("v8::Object::HasProperty()", return false);
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::HasProperty()", return false);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
return self->HasElement(index);
}
@@ -2533,9 +2736,10 @@ bool Object::SetAccessor(Handle<String> name,
v8::Handle<Value> data,
AccessControl settings,
PropertyAttribute attributes) {
- ON_BAILOUT("v8::Object::SetAccessor()", return false);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::SetAccessor()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::AccessorInfo> info = MakeAccessorInfo(name,
getter, setter, data,
settings, attributes);
@@ -2545,43 +2749,56 @@ bool Object::SetAccessor(Handle<String> name,
bool v8::Object::HasRealNamedProperty(Handle<String> key) {
- ON_BAILOUT("v8::Object::HasRealNamedProperty()", return false);
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::HasRealNamedProperty()",
+ return false);
return Utils::OpenHandle(this)->HasRealNamedProperty(
*Utils::OpenHandle(*key));
}
bool v8::Object::HasRealIndexedProperty(uint32_t index) {
- ON_BAILOUT("v8::Object::HasRealIndexedProperty()", return false);
+ ON_BAILOUT(Utils::OpenHandle(this)->GetIsolate(),
+ "v8::Object::HasRealIndexedProperty()",
+ return false);
return Utils::OpenHandle(this)->HasRealElementProperty(index);
}
bool v8::Object::HasRealNamedCallbackProperty(Handle<String> key) {
- ON_BAILOUT("v8::Object::HasRealNamedCallbackProperty()", return false);
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate,
+ "v8::Object::HasRealNamedCallbackProperty()",
+ return false);
+ ENTER_V8(isolate);
return Utils::OpenHandle(this)->HasRealNamedCallbackProperty(
*Utils::OpenHandle(*key));
}
bool v8::Object::HasNamedLookupInterceptor() {
- ON_BAILOUT("v8::Object::HasNamedLookupInterceptor()", return false);
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::HasNamedLookupInterceptor()",
+ return false);
return Utils::OpenHandle(this)->HasNamedInterceptor();
}
bool v8::Object::HasIndexedLookupInterceptor() {
- ON_BAILOUT("v8::Object::HasIndexedLookupInterceptor()", return false);
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::HasIndexedLookupInterceptor()",
+ return false);
return Utils::OpenHandle(this)->HasIndexedInterceptor();
}
Local<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
Handle<String> key) {
- ON_BAILOUT("v8::Object::GetRealNamedPropertyInPrototypeChain()",
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate,
+ "v8::Object::GetRealNamedPropertyInPrototypeChain()",
return Local<Value>());
- ENTER_V8;
+ ENTER_V8(isolate);
i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::LookupResult lookup;
@@ -2601,8 +2818,10 @@ Local<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
Local<Value> v8::Object::GetRealNamedProperty(Handle<String> key) {
- ON_BAILOUT("v8::Object::GetRealNamedProperty()", return Local<Value>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::GetRealNamedProperty()",
+ return Local<Value>());
+ ENTER_V8(isolate);
i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::LookupResult lookup;
@@ -2625,9 +2844,10 @@ Local<Value> v8::Object::GetRealNamedProperty(Handle<String> key) {
// Because the object gets a new map, existing inline cache caching
// the old map of this object will fail.
void v8::Object::TurnOnAccessCheck() {
- ON_BAILOUT("v8::Object::TurnOnAccessCheck()", return);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::TurnOnAccessCheck()", return);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
// When turning on access checks for a global object deoptimize all functions
@@ -2635,7 +2855,7 @@ void v8::Object::TurnOnAccessCheck() {
i::Deoptimizer::DeoptimizeGlobalObject(*obj);
i::Handle<i::Map> new_map =
- i::Factory::CopyMapDropTransitions(i::Handle<i::Map>(obj->map()));
+ isolate->factory()->CopyMapDropTransitions(i::Handle<i::Map>(obj->map()));
new_map->set_is_access_check_needed(true);
obj->set_map(*new_map);
}
@@ -2647,21 +2867,23 @@ bool v8::Object::IsDirty() {
Local<v8::Object> v8::Object::Clone() {
- ON_BAILOUT("v8::Object::Clone()", return Local<Object>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::Clone()", return Local<Object>());
+ ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::JSObject> result = i::Copy(self);
has_pending_exception = result.is_null();
- EXCEPTION_BAILOUT_CHECK(Local<Object>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Object>());
return Utils::ToLocal(result);
}
int v8::Object::GetIdentityHash() {
- ON_BAILOUT("v8::Object::GetIdentityHash()", return 0);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::GetIdentityHash()", return 0);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props_obj(i::GetHiddenProperties(self, true));
if (!hidden_props_obj->IsJSObject()) {
@@ -2672,7 +2894,7 @@ int v8::Object::GetIdentityHash() {
}
i::Handle<i::JSObject> hidden_props =
i::Handle<i::JSObject>::cast(hidden_props_obj);
- i::Handle<i::String> hash_symbol = i::Factory::identity_hash_symbol();
+ i::Handle<i::String> hash_symbol = isolate->factory()->identity_hash_symbol();
if (hidden_props->HasLocalProperty(*hash_symbol)) {
i::Handle<i::Object> hash = i::GetProperty(hidden_props, hash_symbol);
CHECK(!hash.is_null());
@@ -2685,7 +2907,7 @@ int v8::Object::GetIdentityHash() {
do {
// Generate a random 32-bit hash value but limit range to fit
// within a smi.
- hash_value = i::V8::Random() & i::Smi::kMaxValue;
+ hash_value = i::V8::Random(self->GetIsolate()) & i::Smi::kMaxValue;
attempts++;
} while (hash_value == 0 && attempts < 30);
hash_value = hash_value != 0 ? hash_value : 1; // never return 0
@@ -2701,14 +2923,15 @@ int v8::Object::GetIdentityHash() {
bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
v8::Handle<v8::Value> value) {
- ON_BAILOUT("v8::Object::SetHiddenValue()", return false);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::SetHiddenValue()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, true));
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj = i::SetProperty(
hidden_props,
key_obj,
@@ -2716,24 +2939,26 @@ bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
static_cast<PropertyAttributes>(None),
i::kNonStrictMode);
has_pending_exception = obj.is_null();
- EXCEPTION_BAILOUT_CHECK(false);
+ EXCEPTION_BAILOUT_CHECK(isolate, false);
return true;
}
v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
- ON_BAILOUT("v8::Object::GetHiddenValue()", return Local<v8::Value>());
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::GetHiddenValue()",
+ return Local<v8::Value>());
+ ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, false));
if (hidden_props->IsUndefined()) {
return v8::Local<v8::Value>();
}
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = i::GetProperty(hidden_props, key_obj);
has_pending_exception = result.is_null();
- EXCEPTION_BAILOUT_CHECK(v8::Local<v8::Value>());
+ EXCEPTION_BAILOUT_CHECK(isolate, v8::Local<v8::Value>());
if (result->IsUndefined()) {
return v8::Local<v8::Value>();
}
@@ -2742,9 +2967,10 @@ v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
- ON_BAILOUT("v8::DeleteHiddenValue()", return false);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::DeleteHiddenValue()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, false));
if (hidden_props->IsUndefined()) {
@@ -2756,11 +2982,44 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
}
+namespace {
+
+void PrepareExternalArrayElements(i::Handle<i::JSObject> object,
+ void* data,
+ ExternalArrayType array_type,
+ int length) {
+ i::Isolate* isolate = object->GetIsolate();
+ i::Handle<i::ExternalArray> array =
+ isolate->factory()->NewExternalArray(length, array_type, data);
+
+ // If the object already has external elements, create a new, unique
+ // map if the element type is now changing, because assumptions about
+ // generated code based on the receiver's map will be invalid.
+ i::Handle<i::HeapObject> elements(object->elements());
+ bool cant_reuse_map =
+ elements->map()->IsUndefined() ||
+ !elements->map()->has_external_array_elements() ||
+ elements->map() != isolate->heap()->MapForExternalArrayType(array_type);
+ if (cant_reuse_map) {
+ i::Handle<i::Map> external_array_map =
+ isolate->factory()->GetExternalArrayElementsMap(
+ i::Handle<i::Map>(object->map()),
+ array_type,
+ object->HasFastProperties());
+ object->set_map(*external_array_map);
+ }
+ object->set_elements(*array);
+}
+
+} // namespace
+
+
void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) {
- ON_BAILOUT("v8::SetElementsToPixelData()", return);
- ENTER_V8;
- HandleScope scope;
- if (!ApiCheck(length <= i::PixelArray::kMaxLength,
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::SetElementsToPixelData()", return);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
+ if (!ApiCheck(length <= i::ExternalPixelArray::kMaxLength,
"v8::Object::SetIndexedPropertiesToPixelData()",
"length exceeds max acceptable value")) {
return;
@@ -2771,26 +3030,25 @@ void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) {
"JSArray is not supported")) {
return;
}
- i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(length, data);
- i::Handle<i::Map> pixel_array_map =
- i::Factory::GetPixelArrayElementsMap(i::Handle<i::Map>(self->map()));
- self->set_map(*pixel_array_map);
- self->set_elements(*pixels);
+ PrepareExternalArrayElements(self, data, kExternalPixelArray, length);
}
bool v8::Object::HasIndexedPropertiesInPixelData() {
- ON_BAILOUT("v8::HasIndexedPropertiesInPixelData()", return false);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- return self->HasPixelElements();
+ ON_BAILOUT(self->GetIsolate(), "v8::HasIndexedPropertiesInPixelData()",
+ return false);
+ return self->HasExternalPixelElements();
}
uint8_t* v8::Object::GetIndexedPropertiesPixelData() {
- ON_BAILOUT("v8::GetIndexedPropertiesPixelData()", return NULL);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- if (self->HasPixelElements()) {
- return i::PixelArray::cast(self->elements())->external_pointer();
+ ON_BAILOUT(self->GetIsolate(), "v8::GetIndexedPropertiesPixelData()",
+ return NULL);
+ if (self->HasExternalPixelElements()) {
+ return i::ExternalPixelArray::cast(self->elements())->
+ external_pixel_pointer();
} else {
return NULL;
}
@@ -2798,23 +3056,24 @@ uint8_t* v8::Object::GetIndexedPropertiesPixelData() {
int v8::Object::GetIndexedPropertiesPixelDataLength() {
- ON_BAILOUT("v8::GetIndexedPropertiesPixelDataLength()", return -1);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- if (self->HasPixelElements()) {
- return i::PixelArray::cast(self->elements())->length();
+ ON_BAILOUT(self->GetIsolate(), "v8::GetIndexedPropertiesPixelDataLength()",
+ return -1);
+ if (self->HasExternalPixelElements()) {
+ return i::ExternalPixelArray::cast(self->elements())->length();
} else {
return -1;
}
}
-
void v8::Object::SetIndexedPropertiesToExternalArrayData(
void* data,
ExternalArrayType array_type,
int length) {
- ON_BAILOUT("v8::SetIndexedPropertiesToExternalArrayData()", return);
- ENTER_V8;
- HandleScope scope;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::SetIndexedPropertiesToExternalArrayData()", return);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
if (!ApiCheck(length <= i::ExternalArray::kMaxLength,
"v8::Object::SetIndexedPropertiesToExternalArrayData()",
"length exceeds max acceptable value")) {
@@ -2826,25 +3085,24 @@ void v8::Object::SetIndexedPropertiesToExternalArrayData(
"JSArray is not supported")) {
return;
}
- i::Handle<i::ExternalArray> array =
- i::Factory::NewExternalArray(length, array_type, data);
- i::Handle<i::Map> slow_map =
- i::Factory::GetSlowElementsMap(i::Handle<i::Map>(self->map()));
- self->set_map(*slow_map);
- self->set_elements(*array);
+ PrepareExternalArrayElements(self, data, array_type, length);
}
bool v8::Object::HasIndexedPropertiesInExternalArrayData() {
- ON_BAILOUT("v8::HasIndexedPropertiesInExternalArrayData()", return false);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ ON_BAILOUT(self->GetIsolate(),
+ "v8::HasIndexedPropertiesInExternalArrayData()",
+ return false);
return self->HasExternalArrayElements();
}
void* v8::Object::GetIndexedPropertiesExternalArrayData() {
- ON_BAILOUT("v8::GetIndexedPropertiesExternalArrayData()", return NULL);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ ON_BAILOUT(self->GetIsolate(),
+ "v8::GetIndexedPropertiesExternalArrayData()",
+ return NULL);
if (self->HasExternalArrayElements()) {
return i::ExternalArray::cast(self->elements())->external_pointer();
} else {
@@ -2854,9 +3112,10 @@ void* v8::Object::GetIndexedPropertiesExternalArrayData() {
ExternalArrayType v8::Object::GetIndexedPropertiesExternalArrayDataType() {
- ON_BAILOUT("v8::GetIndexedPropertiesExternalArrayDataType()",
- return static_cast<ExternalArrayType>(-1));
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ ON_BAILOUT(self->GetIsolate(),
+ "v8::GetIndexedPropertiesExternalArrayDataType()",
+ return static_cast<ExternalArrayType>(-1));
switch (self->elements()->map()->instance_type()) {
case i::EXTERNAL_BYTE_ARRAY_TYPE:
return kExternalByteArray;
@@ -2872,6 +3131,8 @@ ExternalArrayType v8::Object::GetIndexedPropertiesExternalArrayDataType() {
return kExternalUnsignedIntArray;
case i::EXTERNAL_FLOAT_ARRAY_TYPE:
return kExternalFloatArray;
+ case i::EXTERNAL_PIXEL_ARRAY_TYPE:
+ return kExternalPixelArray;
default:
return static_cast<ExternalArrayType>(-1);
}
@@ -2879,8 +3140,10 @@ ExternalArrayType v8::Object::GetIndexedPropertiesExternalArrayDataType() {
int v8::Object::GetIndexedPropertiesExternalArrayDataLength() {
- ON_BAILOUT("v8::GetIndexedPropertiesExternalArrayDataLength()", return 0);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ ON_BAILOUT(self->GetIsolate(),
+ "v8::GetIndexedPropertiesExternalArrayDataLength()",
+ return 0);
if (self->HasExternalArrayElements()) {
return i::ExternalArray::cast(self->elements())->length();
} else {
@@ -2896,37 +3159,40 @@ Local<v8::Object> Function::NewInstance() const {
Local<v8::Object> Function::NewInstance(int argc,
v8::Handle<v8::Value> argv[]) const {
- ON_BAILOUT("v8::Function::NewInstance()", return Local<v8::Object>());
- LOG_API("Function::NewInstance");
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Function::NewInstance()",
+ return Local<v8::Object>());
+ LOG_API(isolate, "Function::NewInstance");
+ ENTER_V8(isolate);
HandleScope scope;
i::Handle<i::JSFunction> function = Utils::OpenHandle(this);
STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
i::Object*** args = reinterpret_cast<i::Object***>(argv);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> returned =
i::Execution::New(function, argc, args, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<v8::Object>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
return scope.Close(Utils::ToLocal(i::Handle<i::JSObject>::cast(returned)));
}
Local<v8::Value> Function::Call(v8::Handle<v8::Object> recv, int argc,
v8::Handle<v8::Value> argv[]) {
- ON_BAILOUT("v8::Function::Call()", return Local<v8::Value>());
- LOG_API("Function::Call");
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Function::Call()", return Local<v8::Value>());
+ LOG_API(isolate, "Function::Call");
+ ENTER_V8(isolate);
i::Object* raw_result = NULL;
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
i::Object*** args = reinterpret_cast<i::Object***>(argv);
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> returned =
i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<Object>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Object>());
raw_result = *returned;
}
i::Handle<i::Object> result(raw_result);
@@ -2935,7 +3201,8 @@ Local<v8::Value> Function::Call(v8::Handle<v8::Object> recv, int argc,
void Function::SetName(v8::Handle<v8::String> name) {
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ENTER_V8(isolate);
i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
func->shared()->set_name(*Utils::OpenHandle(*name));
}
@@ -2974,81 +3241,17 @@ int Function::GetScriptLineNumber() const {
}
-namespace {
-
-// Tracks string usage to help make better decisions when
-// externalizing strings.
-//
-// Implementation note: internally this class only tracks fresh
-// strings and keeps a single use counter for them.
-class StringTracker {
- public:
- // Records that the given string's characters were copied to some
- // external buffer. If this happens often we should honor
- // externalization requests for the string.
- static void RecordWrite(i::Handle<i::String> string) {
- i::Address address = reinterpret_cast<i::Address>(*string);
- i::Address top = i::Heap::NewSpaceTop();
- if (IsFreshString(address, top)) {
- IncrementUseCount(top);
- }
- }
-
- // Estimates freshness and use frequency of the given string based
- // on how close it is to the new space top and the recorded usage
- // history.
- static inline bool IsFreshUnusedString(i::Handle<i::String> string) {
- i::Address address = reinterpret_cast<i::Address>(*string);
- i::Address top = i::Heap::NewSpaceTop();
- return IsFreshString(address, top) && IsUseCountLow(top);
- }
-
- private:
- static inline bool IsFreshString(i::Address string, i::Address top) {
- return top - kFreshnessLimit <= string && string <= top;
- }
-
- static inline bool IsUseCountLow(i::Address top) {
- if (last_top_ != top) return true;
- return use_count_ < kUseLimit;
- }
-
- static inline void IncrementUseCount(i::Address top) {
- if (last_top_ != top) {
- use_count_ = 0;
- last_top_ = top;
- }
- ++use_count_;
- }
-
- // How close to the new space top a fresh string has to be.
- static const int kFreshnessLimit = 1024;
-
- // The number of uses required to consider a string useful.
- static const int kUseLimit = 32;
-
- // Single use counter shared by all fresh strings.
- static int use_count_;
-
- // Last new space top when the use count above was valid.
- static i::Address last_top_;
-};
-
-int StringTracker::use_count_ = 0;
-i::Address StringTracker::last_top_ = NULL;
-
-} // namespace
-
-
int String::Length() const {
- if (IsDeadCheck("v8::String::Length()")) return 0;
- return Utils::OpenHandle(this)->length();
+ i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Length()")) return 0;
+ return str->length();
}
int String::Utf8Length() const {
- if (IsDeadCheck("v8::String::Utf8Length()")) return 0;
- return Utils::OpenHandle(this)->Utf8Length();
+ i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Utf8Length()")) return 0;
+ return str->Utf8Length();
}
@@ -3056,11 +3259,13 @@ int String::WriteUtf8(char* buffer,
int capacity,
int* nchars_ref,
WriteHints hints) const {
- if (IsDeadCheck("v8::String::WriteUtf8()")) return 0;
- LOG_API("String::WriteUtf8");
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::String::WriteUtf8()")) return 0;
+ LOG_API(isolate, "String::WriteUtf8");
+ ENTER_V8(isolate);
+ i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer();
i::Handle<i::String> str = Utils::OpenHandle(this);
- StringTracker::RecordWrite(str);
+ isolate->string_tracker()->RecordWrite(str);
if (hints & HINT_MANY_WRITES_EXPECTED) {
// Flatten the string for efficiency. This applies whether we are
// using StringInputBuffer or Get(i) to access the characters.
@@ -3111,12 +3316,14 @@ int String::WriteAscii(char* buffer,
int start,
int length,
WriteHints hints) const {
- if (IsDeadCheck("v8::String::WriteAscii()")) return 0;
- LOG_API("String::WriteAscii");
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::String::WriteAscii()")) return 0;
+ LOG_API(isolate, "String::WriteAscii");
+ ENTER_V8(isolate);
+ i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer();
ASSERT(start >= 0 && length >= -1);
i::Handle<i::String> str = Utils::OpenHandle(this);
- StringTracker::RecordWrite(str);
+ isolate->string_tracker()->RecordWrite(str);
if (hints & HINT_MANY_WRITES_EXPECTED) {
// Flatten the string for efficiency. This applies whether we are
// using StringInputBuffer or Get(i) to access the characters.
@@ -3143,12 +3350,13 @@ int String::Write(uint16_t* buffer,
int start,
int length,
WriteHints hints) const {
- if (IsDeadCheck("v8::String::Write()")) return 0;
- LOG_API("String::Write");
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::String::Write()")) return 0;
+ LOG_API(isolate, "String::Write");
+ ENTER_V8(isolate);
ASSERT(start >= 0 && length >= -1);
i::Handle<i::String> str = Utils::OpenHandle(this);
- StringTracker::RecordWrite(str);
+ isolate->string_tracker()->RecordWrite(str);
if (hints & HINT_MANY_WRITES_EXPECTED) {
// Flatten the string for efficiency. This applies whether we are
// using StringInputBuffer or Get(i) to access the characters.
@@ -3167,15 +3375,20 @@ int String::Write(uint16_t* buffer,
bool v8::String::IsExternal() const {
- EnsureInitialized("v8::String::IsExternal()");
i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::IsExternal()")) {
+ return false;
+ }
+ EnsureInitializedForIsolate(str->GetIsolate(), "v8::String::IsExternal()");
return i::StringShape(*str).IsExternalTwoByte();
}
bool v8::String::IsExternalAscii() const {
- EnsureInitialized("v8::String::IsExternalAscii()");
i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::IsExternalAscii()")) {
+ return false;
+ }
return i::StringShape(*str).IsExternalAscii();
}
@@ -3196,8 +3409,11 @@ void v8::String::VerifyExternalStringResource(
v8::String::ExternalAsciiStringResource*
v8::String::GetExternalAsciiStringResource() const {
- EnsureInitialized("v8::String::GetExternalAsciiStringResource()");
i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(),
+ "v8::String::GetExternalAsciiStringResource()")) {
+ return NULL;
+ }
if (i::StringShape(*str).IsExternalAscii()) {
void* resource = i::Handle<i::ExternalAsciiString>::cast(str)->resource();
return reinterpret_cast<ExternalAsciiStringResource*>(resource);
@@ -3208,21 +3424,21 @@ v8::String::ExternalAsciiStringResource*
double Number::Value() const {
- if (IsDeadCheck("v8::Number::Value()")) return 0;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Number::Value()")) return 0;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
return obj->Number();
}
bool Boolean::Value() const {
- if (IsDeadCheck("v8::Boolean::Value()")) return false;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Boolean::Value()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
return obj->IsTrue();
}
int64_t Integer::Value() const {
- if (IsDeadCheck("v8::Integer::Value()")) return 0;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Integer::Value()")) return 0;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsSmi()) {
return i::Smi::cast(*obj)->value();
@@ -3233,7 +3449,7 @@ int64_t Integer::Value() const {
int32_t Int32::Value() const {
- if (IsDeadCheck("v8::Int32::Value()")) return 0;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Int32::Value()")) return 0;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsSmi()) {
return i::Smi::cast(*obj)->value();
@@ -3244,7 +3460,7 @@ int32_t Int32::Value() const {
uint32_t Uint32::Value() const {
- if (IsDeadCheck("v8::Uint32::Value()")) return 0;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Uint32::Value()")) return 0;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsSmi()) {
return i::Smi::cast(*obj)->value();
@@ -3255,15 +3471,19 @@ uint32_t Uint32::Value() const {
int v8::Object::InternalFieldCount() {
- if (IsDeadCheck("v8::Object::InternalFieldCount()")) return 0;
i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ if (IsDeadCheck(obj->GetIsolate(), "v8::Object::InternalFieldCount()")) {
+ return 0;
+ }
return obj->GetInternalFieldCount();
}
Local<Value> v8::Object::CheckedGetInternalField(int index) {
- if (IsDeadCheck("v8::Object::GetInternalField()")) return Local<Value>();
i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ if (IsDeadCheck(obj->GetIsolate(), "v8::Object::GetInternalField()")) {
+ return Local<Value>();
+ }
if (!ApiCheck(index < obj->GetInternalFieldCount(),
"v8::Object::GetInternalField()",
"Reading internal field out of bounds")) {
@@ -3280,14 +3500,17 @@ Local<Value> v8::Object::CheckedGetInternalField(int index) {
void v8::Object::SetInternalField(int index, v8::Handle<Value> value) {
- if (IsDeadCheck("v8::Object::SetInternalField()")) return;
i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ i::Isolate* isolate = obj->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Object::SetInternalField()")) {
+ return;
+ }
if (!ApiCheck(index < obj->GetInternalFieldCount(),
"v8::Object::SetInternalField()",
"Writing internal field out of bounds")) {
return;
}
- ENTER_V8;
+ ENTER_V8(isolate);
i::Handle<i::Object> val = Utils::OpenHandle(*value);
obj->SetInternalField(index, *val);
}
@@ -3311,13 +3534,15 @@ static i::Smi* EncodeAsSmi(void* ptr) {
void v8::Object::SetPointerInInternalField(int index, void* value) {
- ENTER_V8;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ENTER_V8(isolate);
if (CanBeEncodedAsSmi(value)) {
Utils::OpenHandle(this)->SetInternalField(index, EncodeAsSmi(value));
} else {
HandleScope scope;
i::Handle<i::Proxy> proxy =
- i::Factory::NewProxy(reinterpret_cast<i::Address>(value), i::TENURED);
+ isolate->factory()->NewProxy(
+ reinterpret_cast<i::Address>(value), i::TENURED);
if (!proxy.is_null())
Utils::OpenHandle(this)->SetInternalField(index, *proxy);
}
@@ -3327,15 +3552,23 @@ void v8::Object::SetPointerInInternalField(int index, void* value) {
// --- E n v i r o n m e n t ---
+
bool v8::V8::Initialize() {
- if (i::V8::IsRunning()) return true;
- HandleScope scope;
- if (i::Snapshot::Initialize()) return true;
- return i::V8::Initialize(NULL);
+ i::Isolate* isolate = i::Isolate::UncheckedCurrent();
+ if (isolate != NULL && isolate->IsInitialized()) {
+ return true;
+ }
+ return InitializeHelper();
}
bool v8::V8::Dispose() {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!ApiCheck(isolate != NULL && isolate->IsDefaultIsolate(),
+ "v8::V8::Dispose()",
+ "Use v8::Isolate::Dispose() for a non-default isolate.")) {
+ return false;
+ }
i::V8::TearDown();
return true;
}
@@ -3348,38 +3581,39 @@ HeapStatistics::HeapStatistics(): total_heap_size_(0),
void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
- heap_statistics->set_total_heap_size(i::Heap::CommittedMemory());
+ i::Heap* heap = i::Isolate::Current()->heap();
+ heap_statistics->set_total_heap_size(heap->CommittedMemory());
heap_statistics->set_total_heap_size_executable(
- i::Heap::CommittedMemoryExecutable());
- heap_statistics->set_used_heap_size(i::Heap::SizeOfObjects());
- heap_statistics->set_heap_size_limit(i::Heap::MaxReserved());
+ heap->CommittedMemoryExecutable());
+ heap_statistics->set_used_heap_size(heap->SizeOfObjects());
+ heap_statistics->set_heap_size_limit(heap->MaxReserved());
}
bool v8::V8::IdleNotification() {
// Returning true tells the caller that it need not
// continue to call IdleNotification.
- if (!i::V8::IsRunning()) return true;
+ if (!i::Isolate::Current()->IsInitialized()) return true;
return i::V8::IdleNotification();
}
void v8::V8::LowMemoryNotification() {
- if (!i::V8::IsRunning()) return;
- i::Heap::CollectAllGarbage(true);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!isolate->IsInitialized()) return;
+ isolate->heap()->CollectAllGarbage(true);
}
int v8::V8::ContextDisposedNotification() {
- if (!i::V8::IsRunning()) return 0;
- return i::Heap::NotifyContextDisposed();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!isolate->IsInitialized()) return 0;
+ return isolate->heap()->NotifyContextDisposed();
}
const char* v8::V8::GetVersion() {
- static v8::internal::EmbeddedVector<char, 128> buffer;
- v8::internal::Version::GetString(buffer);
- return buffer.start();
+ return i::Version::GetVersion();
}
@@ -3399,14 +3633,15 @@ Persistent<Context> v8::Context::New(
v8::ExtensionConfiguration* extensions,
v8::Handle<ObjectTemplate> global_template,
v8::Handle<Value> global_object) {
- EnsureInitialized("v8::Context::New()");
- LOG_API("Context::New");
- ON_BAILOUT("v8::Context::New()", return Persistent<Context>());
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Context::New()");
+ LOG_API(isolate, "Context::New");
+ ON_BAILOUT(isolate, "v8::Context::New()", return Persistent<Context>());
// Enter V8 via an ENTER_V8 scope.
i::Handle<i::Context> env;
{
- ENTER_V8;
+ ENTER_V8(isolate);
v8::Handle<ObjectTemplate> proxy_template = global_template;
i::Handle<i::FunctionTemplateInfo> proxy_constructor;
i::Handle<i::FunctionTemplateInfo> global_constructor;
@@ -3435,12 +3670,13 @@ Persistent<Context> v8::Context::New(
proxy_constructor->set_needs_access_check(
global_constructor->needs_access_check());
global_constructor->set_needs_access_check(false);
- global_constructor->set_access_check_info(i::Heap::undefined_value());
+ global_constructor->set_access_check_info(
+ isolate->heap()->undefined_value());
}
}
// Create the environment.
- env = i::Bootstrapper::CreateEnvironment(
+ env = isolate->bootstrapper()->CreateEnvironment(
Utils::OpenHandle(*global_object),
proxy_template,
extensions);
@@ -3454,7 +3690,7 @@ Persistent<Context> v8::Context::New(
global_constructor->set_needs_access_check(
proxy_constructor->needs_access_check());
}
- i::RuntimeProfiler::Reset();
+ isolate->runtime_profiler()->Reset();
}
// Leave V8.
@@ -3465,8 +3701,11 @@ Persistent<Context> v8::Context::New(
void v8::Context::SetSecurityToken(Handle<Value> token) {
- if (IsDeadCheck("v8::Context::SetSecurityToken()")) return;
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::SetSecurityToken()")) {
+ return;
+ }
+ ENTER_V8(isolate);
i::Handle<i::Context> env = Utils::OpenHandle(this);
i::Handle<i::Object> token_handle = Utils::OpenHandle(*token);
env->set_security_token(*token_handle);
@@ -3474,15 +3713,22 @@ void v8::Context::SetSecurityToken(Handle<Value> token) {
void v8::Context::UseDefaultSecurityToken() {
- if (IsDeadCheck("v8::Context::UseDefaultSecurityToken()")) return;
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate,
+ "v8::Context::UseDefaultSecurityToken()")) {
+ return;
+ }
+ ENTER_V8(isolate);
i::Handle<i::Context> env = Utils::OpenHandle(this);
env->set_security_token(env->global());
}
Handle<Value> v8::Context::GetSecurityToken() {
- if (IsDeadCheck("v8::Context::GetSecurityToken()")) return Handle<Value>();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::GetSecurityToken()")) {
+ return Handle<Value>();
+ }
i::Handle<i::Context> env = Utils::OpenHandle(this);
i::Object* security_token = env->security_token();
i::Handle<i::Object> token_handle(security_token);
@@ -3497,13 +3743,17 @@ bool Context::HasOutOfMemoryException() {
bool Context::InContext() {
- return i::Top::context() != NULL;
+ return i::Isolate::Current()->context() != NULL;
}
v8::Local<v8::Context> Context::GetEntered() {
- if (IsDeadCheck("v8::Context::GetEntered()")) return Local<Context>();
- i::Handle<i::Object> last = thread_local.LastEnteredContext();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::GetEntered()")) {
+ return Local<Context>();
+ }
+ i::Handle<i::Object> last =
+ isolate->handle_scope_implementer()->LastEnteredContext();
if (last.is_null()) return Local<Context>();
i::Handle<i::Context> context = i::Handle<i::Context>::cast(last);
return Utils::ToLocal(context);
@@ -3511,8 +3761,11 @@ v8::Local<v8::Context> Context::GetEntered() {
v8::Local<v8::Context> Context::GetCurrent() {
- if (IsDeadCheck("v8::Context::GetCurrent()")) return Local<Context>();
- i::Handle<i::Object> current = i::Top::global_context();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::GetCurrent()")) {
+ return Local<Context>();
+ }
+ i::Handle<i::Object> current = isolate->global_context();
if (current.is_null()) return Local<Context>();
i::Handle<i::Context> context = i::Handle<i::Context>::cast(current);
return Utils::ToLocal(context);
@@ -3520,8 +3773,12 @@ v8::Local<v8::Context> Context::GetCurrent() {
v8::Local<v8::Context> Context::GetCalling() {
- if (IsDeadCheck("v8::Context::GetCalling()")) return Local<Context>();
- i::Handle<i::Object> calling = i::Top::GetCallingGlobalContext();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::GetCalling()")) {
+ return Local<Context>();
+ }
+ i::Handle<i::Object> calling =
+ isolate->GetCallingGlobalContext();
if (calling.is_null()) return Local<Context>();
i::Handle<i::Context> context = i::Handle<i::Context>::cast(calling);
return Utils::ToLocal(context);
@@ -3529,7 +3786,9 @@ v8::Local<v8::Context> Context::GetCalling() {
v8::Local<v8::Object> Context::Global() {
- if (IsDeadCheck("v8::Context::Global()")) return Local<v8::Object>();
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) {
+ return Local<v8::Object>();
+ }
i::Object** ctx = reinterpret_cast<i::Object**>(this);
i::Handle<i::Context> context =
i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
@@ -3539,61 +3798,74 @@ v8::Local<v8::Object> Context::Global() {
void Context::DetachGlobal() {
- if (IsDeadCheck("v8::Context::DetachGlobal()")) return;
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::DetachGlobal()")) return;
+ ENTER_V8(isolate);
i::Object** ctx = reinterpret_cast<i::Object**>(this);
i::Handle<i::Context> context =
i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
- i::Bootstrapper::DetachGlobal(context);
+ isolate->bootstrapper()->DetachGlobal(context);
}
void Context::ReattachGlobal(Handle<Object> global_object) {
- if (IsDeadCheck("v8::Context::ReattachGlobal()")) return;
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::ReattachGlobal()")) return;
+ ENTER_V8(isolate);
i::Object** ctx = reinterpret_cast<i::Object**>(this);
i::Handle<i::Context> context =
i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
- i::Bootstrapper::ReattachGlobal(context, Utils::OpenHandle(*global_object));
+ isolate->bootstrapper()->ReattachGlobal(
+ context,
+ Utils::OpenHandle(*global_object));
+}
+
+
+void V8::SetWrapperClassId(i::Object** global_handle, uint16_t class_id) {
+ i::GlobalHandles::SetWrapperClassId(global_handle, class_id);
}
Local<v8::Object> ObjectTemplate::NewInstance() {
- ON_BAILOUT("v8::ObjectTemplate::NewInstance()", return Local<v8::Object>());
- LOG_API("ObjectTemplate::NewInstance");
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::ObjectTemplate::NewInstance()",
+ return Local<v8::Object>());
+ LOG_API(isolate, "ObjectTemplate::NewInstance");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj =
i::Execution::InstantiateObject(Utils::OpenHandle(this),
&has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<v8::Object>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
return Utils::ToLocal(i::Handle<i::JSObject>::cast(obj));
}
Local<v8::Function> FunctionTemplate::GetFunction() {
- ON_BAILOUT("v8::FunctionTemplate::GetFunction()",
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::FunctionTemplate::GetFunction()",
return Local<v8::Function>());
- LOG_API("FunctionTemplate::GetFunction");
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ LOG_API(isolate, "FunctionTemplate::GetFunction");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj =
i::Execution::InstantiateFunction(Utils::OpenHandle(this),
&has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<v8::Function>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Function>());
return Utils::ToLocal(i::Handle<i::JSFunction>::cast(obj));
}
bool FunctionTemplate::HasInstance(v8::Handle<v8::Value> value) {
- ON_BAILOUT("v8::FunctionTemplate::HasInstanceOf()", return false);
+ ON_BAILOUT(i::Isolate::Current(), "v8::FunctionTemplate::HasInstanceOf()",
+ return false);
i::Object* obj = *Utils::OpenHandle(*value);
return obj->IsInstanceOf(*Utils::OpenHandle(this));
}
static Local<External> ExternalNewImpl(void* data) {
- return Utils::ToLocal(i::Factory::NewProxy(static_cast<i::Address>(data)));
+ return Utils::ToLocal(FACTORY->NewProxy(static_cast<i::Address>(data)));
}
static void* ExternalValueImpl(i::Handle<i::Object> obj) {
@@ -3602,10 +3874,11 @@ static void* ExternalValueImpl(i::Handle<i::Object> obj) {
Local<Value> v8::External::Wrap(void* data) {
+ i::Isolate* isolate = i::Isolate::Current();
STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
- LOG_API("External::Wrap");
- EnsureInitialized("v8::External::Wrap()");
- ENTER_V8;
+ LOG_API(isolate, "External::Wrap");
+ EnsureInitializedForIsolate(isolate, "v8::External::Wrap()");
+ ENTER_V8(isolate);
v8::Local<v8::Value> result = CanBeEncodedAsSmi(data)
? Utils::ToLocal(i::Handle<i::Object>(EncodeAsSmi(data)))
@@ -3630,7 +3903,7 @@ void* v8::Object::SlowGetPointerFromInternalField(int index) {
void* v8::External::FullUnwrap(v8::Handle<v8::Value> wrapper) {
- if (IsDeadCheck("v8::External::Unwrap()")) return 0;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::External::Unwrap()")) return 0;
i::Handle<i::Object> obj = Utils::OpenHandle(*wrapper);
void* result;
if (obj->IsSmi()) {
@@ -3647,58 +3920,65 @@ void* v8::External::FullUnwrap(v8::Handle<v8::Value> wrapper) {
Local<External> v8::External::New(void* data) {
STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
- LOG_API("External::New");
- EnsureInitialized("v8::External::New()");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "External::New");
+ EnsureInitializedForIsolate(isolate, "v8::External::New()");
+ ENTER_V8(isolate);
return ExternalNewImpl(data);
}
void* External::Value() const {
- if (IsDeadCheck("v8::External::Value()")) return 0;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::External::Value()")) return 0;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
return ExternalValueImpl(obj);
}
Local<String> v8::String::Empty() {
- EnsureInitialized("v8::String::Empty()");
- LOG_API("String::Empty()");
- return Utils::ToLocal(i::Factory::empty_symbol());
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::String::Empty()");
+ LOG_API(isolate, "String::Empty()");
+ return Utils::ToLocal(isolate->factory()->empty_symbol());
}
Local<String> v8::String::New(const char* data, int length) {
- EnsureInitialized("v8::String::New()");
- LOG_API("String::New(char)");
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::String::New()");
+ LOG_API(isolate, "String::New(char)");
if (length == 0) return Empty();
- ENTER_V8;
+ ENTER_V8(isolate);
if (length == -1) length = i::StrLength(data);
i::Handle<i::String> result =
- i::Factory::NewStringFromUtf8(i::Vector<const char>(data, length));
+ isolate->factory()->NewStringFromUtf8(
+ i::Vector<const char>(data, length));
return Utils::ToLocal(result);
}
Local<String> v8::String::Concat(Handle<String> left, Handle<String> right) {
- EnsureInitialized("v8::String::New()");
- LOG_API("String::New(char)");
- ENTER_V8;
i::Handle<i::String> left_string = Utils::OpenHandle(*left);
+ i::Isolate* isolate = left_string->GetIsolate();
+ EnsureInitializedForIsolate(isolate, "v8::String::New()");
+ LOG_API(isolate, "String::New(char)");
+ ENTER_V8(isolate);
i::Handle<i::String> right_string = Utils::OpenHandle(*right);
- i::Handle<i::String> result = i::Factory::NewConsString(left_string,
- right_string);
+ i::Handle<i::String> result = isolate->factory()->NewConsString(left_string,
+ right_string);
return Utils::ToLocal(result);
}
Local<String> v8::String::NewUndetectable(const char* data, int length) {
- EnsureInitialized("v8::String::NewUndetectable()");
- LOG_API("String::NewUndetectable(char)");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::String::NewUndetectable()");
+ LOG_API(isolate, "String::NewUndetectable(char)");
+ ENTER_V8(isolate);
if (length == -1) length = i::StrLength(data);
i::Handle<i::String> result =
- i::Factory::NewStringFromUtf8(i::Vector<const char>(data, length));
+ isolate->factory()->NewStringFromUtf8(
+ i::Vector<const char>(data, length));
result->MarkAsUndetectable();
return Utils::ToLocal(result);
}
@@ -3712,65 +3992,75 @@ static int TwoByteStringLength(const uint16_t* data) {
Local<String> v8::String::New(const uint16_t* data, int length) {
- EnsureInitialized("v8::String::New()");
- LOG_API("String::New(uint16_)");
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::String::New()");
+ LOG_API(isolate, "String::New(uint16_)");
if (length == 0) return Empty();
- ENTER_V8;
+ ENTER_V8(isolate);
if (length == -1) length = TwoByteStringLength(data);
i::Handle<i::String> result =
- i::Factory::NewStringFromTwoByte(i::Vector<const uint16_t>(data, length));
+ isolate->factory()->NewStringFromTwoByte(
+ i::Vector<const uint16_t>(data, length));
return Utils::ToLocal(result);
}
Local<String> v8::String::NewUndetectable(const uint16_t* data, int length) {
- EnsureInitialized("v8::String::NewUndetectable()");
- LOG_API("String::NewUndetectable(uint16_)");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::String::NewUndetectable()");
+ LOG_API(isolate, "String::NewUndetectable(uint16_)");
+ ENTER_V8(isolate);
if (length == -1) length = TwoByteStringLength(data);
i::Handle<i::String> result =
- i::Factory::NewStringFromTwoByte(i::Vector<const uint16_t>(data, length));
+ isolate->factory()->NewStringFromTwoByte(
+ i::Vector<const uint16_t>(data, length));
result->MarkAsUndetectable();
return Utils::ToLocal(result);
}
-i::Handle<i::String> NewExternalStringHandle(
+i::Handle<i::String> NewExternalStringHandle(i::Isolate* isolate,
v8::String::ExternalStringResource* resource) {
i::Handle<i::String> result =
- i::Factory::NewExternalStringFromTwoByte(resource);
+ isolate->factory()->NewExternalStringFromTwoByte(resource);
return result;
}
-i::Handle<i::String> NewExternalAsciiStringHandle(
+i::Handle<i::String> NewExternalAsciiStringHandle(i::Isolate* isolate,
v8::String::ExternalAsciiStringResource* resource) {
i::Handle<i::String> result =
- i::Factory::NewExternalStringFromAscii(resource);
+ isolate->factory()->NewExternalStringFromAscii(resource);
return result;
}
Local<String> v8::String::NewExternal(
v8::String::ExternalStringResource* resource) {
- EnsureInitialized("v8::String::NewExternal()");
- LOG_API("String::NewExternal");
- ENTER_V8;
- i::Handle<i::String> result = NewExternalStringHandle(resource);
- i::ExternalStringTable::AddString(*result);
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::String::NewExternal()");
+ LOG_API(isolate, "String::NewExternal");
+ ENTER_V8(isolate);
+ i::Handle<i::String> result = NewExternalStringHandle(isolate, resource);
+ isolate->heap()->external_string_table()->AddString(*result);
return Utils::ToLocal(result);
}
bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) {
- if (IsDeadCheck("v8::String::MakeExternal()")) return false;
- if (this->IsExternal()) return false; // Already an external string.
- ENTER_V8;
i::Handle<i::String> obj = Utils::OpenHandle(this);
- if (StringTracker::IsFreshUnusedString(obj)) return false;
+ i::Isolate* isolate = obj->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::String::MakeExternal()")) return false;
+ if (i::StringShape(*obj).IsExternalTwoByte()) {
+ return false; // Already an external string.
+ }
+ ENTER_V8(isolate);
+ if (isolate->string_tracker()->IsFreshUnusedString(obj)) {
+ return false;
+ }
bool result = obj->MakeExternal(resource);
if (result && !obj->IsSymbol()) {
- i::ExternalStringTable::AddString(*obj);
+ isolate->heap()->external_string_table()->AddString(*obj);
}
return result;
}
@@ -3778,34 +4068,43 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) {
Local<String> v8::String::NewExternal(
v8::String::ExternalAsciiStringResource* resource) {
- EnsureInitialized("v8::String::NewExternal()");
- LOG_API("String::NewExternal");
- ENTER_V8;
- i::Handle<i::String> result = NewExternalAsciiStringHandle(resource);
- i::ExternalStringTable::AddString(*result);
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::String::NewExternal()");
+ LOG_API(isolate, "String::NewExternal");
+ ENTER_V8(isolate);
+ i::Handle<i::String> result = NewExternalAsciiStringHandle(isolate, resource);
+ isolate->heap()->external_string_table()->AddString(*result);
return Utils::ToLocal(result);
}
bool v8::String::MakeExternal(
v8::String::ExternalAsciiStringResource* resource) {
- if (IsDeadCheck("v8::String::MakeExternal()")) return false;
- if (this->IsExternal()) return false; // Already an external string.
- ENTER_V8;
i::Handle<i::String> obj = Utils::OpenHandle(this);
- if (StringTracker::IsFreshUnusedString(obj)) return false;
+ i::Isolate* isolate = obj->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::String::MakeExternal()")) return false;
+ if (i::StringShape(*obj).IsExternalTwoByte()) {
+ return false; // Already an external string.
+ }
+ ENTER_V8(isolate);
+ if (isolate->string_tracker()->IsFreshUnusedString(obj)) {
+ return false;
+ }
bool result = obj->MakeExternal(resource);
if (result && !obj->IsSymbol()) {
- i::ExternalStringTable::AddString(*obj);
+ isolate->heap()->external_string_table()->AddString(*obj);
}
return result;
}
bool v8::String::CanMakeExternal() {
- if (IsDeadCheck("v8::String::CanMakeExternal()")) return false;
i::Handle<i::String> obj = Utils::OpenHandle(this);
- if (StringTracker::IsFreshUnusedString(obj)) return false;
+ i::Isolate* isolate = obj->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::String::CanMakeExternal()")) return false;
+ if (isolate->string_tracker()->IsFreshUnusedString(obj)) {
+ return false;
+ }
int size = obj->Size(); // Byte size of the original string.
if (size < i::ExternalString::kSize)
return false;
@@ -3815,34 +4114,37 @@ bool v8::String::CanMakeExternal() {
Local<v8::Object> v8::Object::New() {
- EnsureInitialized("v8::Object::New()");
- LOG_API("Object::New");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Object::New()");
+ LOG_API(isolate, "Object::New");
+ ENTER_V8(isolate);
i::Handle<i::JSObject> obj =
- i::Factory::NewJSObject(i::Top::object_function());
+ isolate->factory()->NewJSObject(isolate->object_function());
return Utils::ToLocal(obj);
}
Local<v8::Value> v8::Date::New(double time) {
- EnsureInitialized("v8::Date::New()");
- LOG_API("Date::New");
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Date::New()");
+ LOG_API(isolate, "Date::New");
if (isnan(time)) {
// Introduce only canonical NaN value into the VM, to avoid signaling NaNs.
time = i::OS::nan_value();
}
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> obj =
i::Execution::NewDate(time, &has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<v8::Value>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Value>());
return Utils::ToLocal(obj);
}
double v8::Date::NumberValue() const {
- if (IsDeadCheck("v8::Date::NumberValue()")) return 0;
- LOG_API("Date::NumberValue");
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Date::NumberValue()")) return 0;
+ LOG_API(isolate, "Date::NumberValue");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
return jsvalue->value()->Number();
@@ -3850,16 +4152,18 @@ double v8::Date::NumberValue() const {
void v8::Date::DateTimeConfigurationChangeNotification() {
- ON_BAILOUT("v8::Date::DateTimeConfigurationChangeNotification()", return);
- LOG_API("Date::DateTimeConfigurationChangeNotification");
- ENTER_V8;
-
- HandleScope scope;
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Date::DateTimeConfigurationChangeNotification()",
+ return);
+ LOG_API(isolate, "Date::DateTimeConfigurationChangeNotification");
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
// Get the function ResetDateCache (defined in date-delay.js).
i::Handle<i::String> func_name_str =
- i::Factory::LookupAsciiSymbol("ResetDateCache");
- i::MaybeObject* result = i::Top::builtins()->GetProperty(*func_name_str);
+ isolate->factory()->LookupAsciiSymbol("ResetDateCache");
+ i::MaybeObject* result =
+ isolate->js_builtins_object()->GetProperty(*func_name_str);
i::Object* object_func;
if (!result->ToObject(&object_func)) {
return;
@@ -3872,7 +4176,7 @@ void v8::Date::DateTimeConfigurationChangeNotification() {
// Call ResetDateCache(0 but expect no exceptions:
bool caught_exception = false;
i::Handle<i::Object> result =
- i::Execution::TryCall(func, i::Top::builtins(), 0, NULL,
+ i::Execution::TryCall(func, isolate->js_builtins_object(), 0, NULL,
&caught_exception);
}
}
@@ -3885,28 +4189,32 @@ static i::Handle<i::String> RegExpFlagsToString(RegExp::Flags flags) {
if ((flags & RegExp::kMultiline) != 0) flags_buf[num_flags++] = 'm';
if ((flags & RegExp::kIgnoreCase) != 0) flags_buf[num_flags++] = 'i';
ASSERT(num_flags <= static_cast<int>(ARRAY_SIZE(flags_buf)));
- return i::Factory::LookupSymbol(
+ return FACTORY->LookupSymbol(
i::Vector<const char>(flags_buf, num_flags));
}
Local<v8::RegExp> v8::RegExp::New(Handle<String> pattern,
Flags flags) {
- EnsureInitialized("v8::RegExp::New()");
- LOG_API("RegExp::New");
- ENTER_V8;
- EXCEPTION_PREAMBLE();
+ i::Isolate* isolate = Utils::OpenHandle(*pattern)->GetIsolate();
+ EnsureInitializedForIsolate(isolate, "v8::RegExp::New()");
+ LOG_API(isolate, "RegExp::New");
+ ENTER_V8(isolate);
+ EXCEPTION_PREAMBLE(isolate);
i::Handle<i::JSRegExp> obj = i::Execution::NewJSRegExp(
Utils::OpenHandle(*pattern),
RegExpFlagsToString(flags),
&has_pending_exception);
- EXCEPTION_BAILOUT_CHECK(Local<v8::RegExp>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::RegExp>());
return Utils::ToLocal(i::Handle<i::JSRegExp>::cast(obj));
}
Local<v8::String> v8::RegExp::GetSource() const {
- if (IsDeadCheck("v8::RegExp::GetSource()")) return Local<v8::String>();
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::RegExp::GetSource()")) {
+ return Local<v8::String>();
+ }
i::Handle<i::JSRegExp> obj = Utils::OpenHandle(this);
return Utils::ToLocal(i::Handle<i::String>(obj->Pattern()));
}
@@ -3923,23 +4231,29 @@ REGEXP_FLAG_ASSERT_EQ(kMultiline, MULTILINE);
#undef REGEXP_FLAG_ASSERT_EQ
v8::RegExp::Flags v8::RegExp::GetFlags() const {
- if (IsDeadCheck("v8::RegExp::GetFlags()")) return v8::RegExp::kNone;
+ if (IsDeadCheck(i::Isolate::Current(), "v8::RegExp::GetFlags()")) {
+ return v8::RegExp::kNone;
+ }
i::Handle<i::JSRegExp> obj = Utils::OpenHandle(this);
return static_cast<RegExp::Flags>(obj->GetFlags().value());
}
Local<v8::Array> v8::Array::New(int length) {
- EnsureInitialized("v8::Array::New()");
- LOG_API("Array::New");
- ENTER_V8;
- i::Handle<i::JSArray> obj = i::Factory::NewJSArray(length);
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Array::New()");
+ LOG_API(isolate, "Array::New");
+ ENTER_V8(isolate);
+ int real_length = length > 0 ? length : 0;
+ i::Handle<i::JSArray> obj = isolate->factory()->NewJSArray(real_length);
+ obj->set_length(*isolate->factory()->NewNumberFromInt(real_length));
return Utils::ToLocal(obj);
}
uint32_t v8::Array::Length() const {
- if (IsDeadCheck("v8::Array::Length()")) return 0;
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::Array::Length()")) return 0;
i::Handle<i::JSArray> obj = Utils::OpenHandle(this);
i::Object* length = obj->length();
if (length->IsSmi()) {
@@ -3951,7 +4265,8 @@ uint32_t v8::Array::Length() const {
Local<Object> Array::CloneElementAt(uint32_t index) {
- ON_BAILOUT("v8::Array::CloneElementAt()", return Local<Object>());
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Array::CloneElementAt()", return Local<Object>());
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
if (!self->HasFastElements()) {
return Local<Object>();
@@ -3962,45 +4277,49 @@ Local<Object> Array::CloneElementAt(uint32_t index) {
return Local<Object>();
}
i::Handle<i::JSObject> paragon_handle(i::JSObject::cast(paragon));
- EXCEPTION_PREAMBLE();
- ENTER_V8;
+ EXCEPTION_PREAMBLE(isolate);
+ ENTER_V8(isolate);
i::Handle<i::JSObject> result = i::Copy(paragon_handle);
has_pending_exception = result.is_null();
- EXCEPTION_BAILOUT_CHECK(Local<Object>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Object>());
return Utils::ToLocal(result);
}
Local<String> v8::String::NewSymbol(const char* data, int length) {
- EnsureInitialized("v8::String::NewSymbol()");
- LOG_API("String::NewSymbol(char)");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::String::NewSymbol()");
+ LOG_API(isolate, "String::NewSymbol(char)");
+ ENTER_V8(isolate);
if (length == -1) length = i::StrLength(data);
i::Handle<i::String> result =
- i::Factory::LookupSymbol(i::Vector<const char>(data, length));
+ isolate->factory()->LookupSymbol(i::Vector<const char>(data, length));
return Utils::ToLocal(result);
}
Local<Number> v8::Number::New(double value) {
- EnsureInitialized("v8::Number::New()");
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Number::New()");
if (isnan(value)) {
// Introduce only canonical NaN value into the VM, to avoid signaling NaNs.
value = i::OS::nan_value();
}
- ENTER_V8;
- i::Handle<i::Object> result = i::Factory::NewNumber(value);
+ ENTER_V8(isolate);
+ i::Handle<i::Object> result = isolate->factory()->NewNumber(value);
return Utils::NumberToLocal(result);
}
Local<Integer> v8::Integer::New(int32_t value) {
- EnsureInitialized("v8::Integer::New()");
+ i::Isolate* isolate = i::Isolate::UncheckedCurrent();
+ EnsureInitializedForIsolate(isolate, "v8::Integer::New()");
if (i::Smi::IsValid(value)) {
- return Utils::IntegerToLocal(i::Handle<i::Object>(i::Smi::FromInt(value)));
+ return Utils::IntegerToLocal(i::Handle<i::Object>(i::Smi::FromInt(value),
+ isolate));
}
- ENTER_V8;
- i::Handle<i::Object> result = i::Factory::NewNumber(value);
+ ENTER_V8(isolate);
+ i::Handle<i::Object> result = isolate->factory()->NewNumber(value);
return Utils::IntegerToLocal(result);
}
@@ -4010,27 +4329,30 @@ Local<Integer> Integer::NewFromUnsigned(uint32_t value) {
if (fits_into_int32_t) {
return Integer::New(static_cast<int32_t>(value));
}
- ENTER_V8;
- i::Handle<i::Object> result = i::Factory::NewNumber(value);
+ i::Isolate* isolate = i::Isolate::Current();
+ ENTER_V8(isolate);
+ i::Handle<i::Object> result = isolate->factory()->NewNumber(value);
return Utils::IntegerToLocal(result);
}
void V8::IgnoreOutOfMemoryException() {
- thread_local.set_ignore_out_of_memory(true);
+ EnterIsolateIfNeeded()->handle_scope_implementer()->set_ignore_out_of_memory(
+ true);
}
bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) {
- EnsureInitialized("v8::V8::AddMessageListener()");
- ON_BAILOUT("v8::V8::AddMessageListener()", return false);
- ENTER_V8;
- HandleScope scope;
- NeanderArray listeners(i::Factory::message_listeners());
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::V8::AddMessageListener()");
+ ON_BAILOUT(isolate, "v8::V8::AddMessageListener()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
+ NeanderArray listeners(isolate->factory()->message_listeners());
NeanderObject obj(2);
- obj.set(0, *i::Factory::NewProxy(FUNCTION_ADDR(that)));
+ obj.set(0, *isolate->factory()->NewProxy(FUNCTION_ADDR(that)));
obj.set(1, data.IsEmpty() ?
- i::Heap::undefined_value() :
+ isolate->heap()->undefined_value() :
*Utils::OpenHandle(*data));
listeners.add(obj.value());
return true;
@@ -4038,18 +4360,19 @@ bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) {
void V8::RemoveMessageListeners(MessageCallback that) {
- EnsureInitialized("v8::V8::RemoveMessageListener()");
- ON_BAILOUT("v8::V8::RemoveMessageListeners()", return);
- ENTER_V8;
- HandleScope scope;
- NeanderArray listeners(i::Factory::message_listeners());
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::V8::RemoveMessageListener()");
+ ON_BAILOUT(isolate, "v8::V8::RemoveMessageListeners()", return);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
+ NeanderArray listeners(isolate->factory()->message_listeners());
for (int i = 0; i < listeners.length(); i++) {
if (listeners.get(i)->IsUndefined()) continue; // skip deleted ones
NeanderObject listener(i::JSObject::cast(listeners.get(i)));
i::Handle<i::Proxy> callback_obj(i::Proxy::cast(listener.get(0)));
if (callback_obj->proxy() == FUNCTION_ADDR(that)) {
- listeners.set(i, i::Heap::undefined_value());
+ listeners.set(i, isolate->heap()->undefined_value());
}
}
}
@@ -4059,7 +4382,7 @@ void V8::SetCaptureStackTraceForUncaughtExceptions(
bool capture,
int frame_limit,
StackTrace::StackTraceOptions options) {
- i::Top::SetCaptureStackTraceForUncaughtExceptions(
+ i::Isolate::Current()->SetCaptureStackTraceForUncaughtExceptions(
capture,
frame_limit,
options);
@@ -4067,95 +4390,130 @@ void V8::SetCaptureStackTraceForUncaughtExceptions(
void V8::SetCounterFunction(CounterLookupCallback callback) {
- if (IsDeadCheck("v8::V8::SetCounterFunction()")) return;
- i::StatsTable::SetCounterFunction(callback);
+ i::Isolate* isolate = EnterIsolateIfNeeded();
+ if (IsDeadCheck(isolate, "v8::V8::SetCounterFunction()")) return;
+ isolate->stats_table()->SetCounterFunction(callback);
}
void V8::SetCreateHistogramFunction(CreateHistogramCallback callback) {
- if (IsDeadCheck("v8::V8::SetCreateHistogramFunction()")) return;
- i::StatsTable::SetCreateHistogramFunction(callback);
+ i::Isolate* isolate = EnterIsolateIfNeeded();
+ if (IsDeadCheck(isolate, "v8::V8::SetCreateHistogramFunction()")) return;
+ isolate->stats_table()->SetCreateHistogramFunction(callback);
}
void V8::SetAddHistogramSampleFunction(AddHistogramSampleCallback callback) {
- if (IsDeadCheck("v8::V8::SetAddHistogramSampleFunction()")) return;
- i::StatsTable::SetAddHistogramSampleFunction(callback);
+ i::Isolate* isolate = EnterIsolateIfNeeded();
+ if (IsDeadCheck(isolate, "v8::V8::SetAddHistogramSampleFunction()")) return;
+ isolate->stats_table()->
+ SetAddHistogramSampleFunction(callback);
}
void V8::EnableSlidingStateWindow() {
- if (IsDeadCheck("v8::V8::EnableSlidingStateWindow()")) return;
- i::Logger::EnableSlidingStateWindow();
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::EnableSlidingStateWindow()")) return;
+ isolate->logger()->EnableSlidingStateWindow();
}
void V8::SetFailedAccessCheckCallbackFunction(
FailedAccessCheckCallback callback) {
- if (IsDeadCheck("v8::V8::SetFailedAccessCheckCallbackFunction()")) return;
- i::Top::SetFailedAccessCheckCallback(callback);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::SetFailedAccessCheckCallbackFunction()")) {
+ return;
+ }
+ isolate->SetFailedAccessCheckCallback(callback);
+}
+
+void V8::AddObjectGroup(Persistent<Value>* objects,
+ size_t length,
+ RetainedObjectInfo* info) {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::AddObjectGroup()")) return;
+ STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**));
+ isolate->global_handles()->AddObjectGroup(
+ reinterpret_cast<i::Object***>(objects), length, info);
}
-void V8::AddObjectGroup(Persistent<Value>* objects, size_t length) {
- if (IsDeadCheck("v8::V8::AddObjectGroup()")) return;
+void V8::AddImplicitReferences(Persistent<Object> parent,
+ Persistent<Value>* children,
+ size_t length) {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::AddImplicitReferences()")) return;
STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**));
- i::GlobalHandles::AddGroup(reinterpret_cast<i::Object***>(objects), length);
+ isolate->global_handles()->AddImplicitReferences(
+ *Utils::OpenHandle(*parent),
+ reinterpret_cast<i::Object***>(children), length);
}
int V8::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
- if (IsDeadCheck("v8::V8::AdjustAmountOfExternalAllocatedMemory()")) return 0;
- return i::Heap::AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::AdjustAmountOfExternalAllocatedMemory()")) {
+ return 0;
+ }
+ return isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
+ change_in_bytes);
}
void V8::SetGlobalGCPrologueCallback(GCCallback callback) {
- if (IsDeadCheck("v8::V8::SetGlobalGCPrologueCallback()")) return;
- i::Heap::SetGlobalGCPrologueCallback(callback);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::SetGlobalGCPrologueCallback()")) return;
+ isolate->heap()->SetGlobalGCPrologueCallback(callback);
}
void V8::SetGlobalGCEpilogueCallback(GCCallback callback) {
- if (IsDeadCheck("v8::V8::SetGlobalGCEpilogueCallback()")) return;
- i::Heap::SetGlobalGCEpilogueCallback(callback);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::SetGlobalGCEpilogueCallback()")) return;
+ isolate->heap()->SetGlobalGCEpilogueCallback(callback);
}
void V8::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
- if (IsDeadCheck("v8::V8::AddGCPrologueCallback()")) return;
- i::Heap::AddGCPrologueCallback(callback, gc_type);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::AddGCPrologueCallback()")) return;
+ isolate->heap()->AddGCPrologueCallback(callback, gc_type);
}
void V8::RemoveGCPrologueCallback(GCPrologueCallback callback) {
- if (IsDeadCheck("v8::V8::RemoveGCPrologueCallback()")) return;
- i::Heap::RemoveGCPrologueCallback(callback);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::RemoveGCPrologueCallback()")) return;
+ isolate->heap()->RemoveGCPrologueCallback(callback);
}
void V8::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
- if (IsDeadCheck("v8::V8::AddGCEpilogueCallback()")) return;
- i::Heap::AddGCEpilogueCallback(callback, gc_type);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::AddGCEpilogueCallback()")) return;
+ isolate->heap()->AddGCEpilogueCallback(callback, gc_type);
}
void V8::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
- if (IsDeadCheck("v8::V8::RemoveGCEpilogueCallback()")) return;
- i::Heap::RemoveGCEpilogueCallback(callback);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::RemoveGCEpilogueCallback()")) return;
+ isolate->heap()->RemoveGCEpilogueCallback(callback);
}
void V8::AddMemoryAllocationCallback(MemoryAllocationCallback callback,
ObjectSpace space,
AllocationAction action) {
- if (IsDeadCheck("v8::V8::AddMemoryAllocationCallback()")) return;
- i::MemoryAllocator::AddMemoryAllocationCallback(callback,
- space,
- action);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::AddMemoryAllocationCallback()")) return;
+ isolate->memory_allocator()->AddMemoryAllocationCallback(
+ callback, space, action);
}
void V8::RemoveMemoryAllocationCallback(MemoryAllocationCallback callback) {
- if (IsDeadCheck("v8::V8::RemoveMemoryAllocationCallback()")) return;
- i::MemoryAllocator::RemoveMemoryAllocationCallback(callback);
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::RemoveMemoryAllocationCallback()")) return;
+ isolate->memory_allocator()->RemoveMemoryAllocationCallback(
+ callback);
}
@@ -4175,7 +4533,7 @@ void V8::ResumeProfiler() {
bool V8::IsProfilerPaused() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- return i::Logger::GetActiveProfilerModules() & PROFILER_MODULE_CPU;
+ return LOGGER->GetActiveProfilerModules() & PROFILER_MODULE_CPU;
#else
return true;
#endif
@@ -4184,21 +4542,22 @@ bool V8::IsProfilerPaused() {
void V8::ResumeProfilerEx(int flags, int tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
+ i::Isolate* isolate = i::Isolate::Current();
if (flags & PROFILER_MODULE_HEAP_SNAPSHOT) {
// Snapshot mode: resume modules, perform GC, then pause only
// those modules which haven't been started prior to making a
// snapshot.
// Make a GC prior to taking a snapshot.
- i::Heap::CollectAllGarbage(false);
+ isolate->heap()->CollectAllGarbage(false);
// Reset snapshot flag and CPU module flags.
flags &= ~(PROFILER_MODULE_HEAP_SNAPSHOT | PROFILER_MODULE_CPU);
- const int current_flags = i::Logger::GetActiveProfilerModules();
- i::Logger::ResumeProfiler(flags, tag);
- i::Heap::CollectAllGarbage(false);
- i::Logger::PauseProfiler(~current_flags & flags, tag);
+ const int current_flags = isolate->logger()->GetActiveProfilerModules();
+ isolate->logger()->ResumeProfiler(flags, tag);
+ isolate->heap()->CollectAllGarbage(false);
+ isolate->logger()->PauseProfiler(~current_flags & flags, tag);
} else {
- i::Logger::ResumeProfiler(flags, tag);
+ isolate->logger()->ResumeProfiler(flags, tag);
}
#endif
}
@@ -4206,14 +4565,14 @@ void V8::ResumeProfilerEx(int flags, int tag) {
void V8::PauseProfilerEx(int flags, int tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- i::Logger::PauseProfiler(flags, tag);
+ LOGGER->PauseProfiler(flags, tag);
#endif
}
int V8::GetActiveProfilerModules() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- return i::Logger::GetActiveProfilerModules();
+ return LOGGER->GetActiveProfilerModules();
#else
return PROFILER_MODULE_NONE;
#endif
@@ -4223,57 +4582,95 @@ int V8::GetActiveProfilerModules() {
int V8::GetLogLines(int from_pos, char* dest_buf, int max_size) {
#ifdef ENABLE_LOGGING_AND_PROFILING
ASSERT(max_size >= kMinimumSizeForLogLinesBuffer);
- return i::Logger::GetLogLines(from_pos, dest_buf, max_size);
+ return LOGGER->GetLogLines(from_pos, dest_buf, max_size);
#endif
return 0;
}
int V8::GetCurrentThreadId() {
- API_ENTRY_CHECK("V8::GetCurrentThreadId()");
- EnsureInitialized("V8::GetCurrentThreadId()");
- return i::Top::thread_id();
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "V8::GetCurrentThreadId()");
+ return isolate->thread_id();
}
void V8::TerminateExecution(int thread_id) {
- if (!i::V8::IsRunning()) return;
- API_ENTRY_CHECK("V8::GetCurrentThreadId()");
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!isolate->IsInitialized()) return;
+ API_ENTRY_CHECK("V8::TerminateExecution()");
// If the thread_id identifies the current thread just terminate
// execution right away. Otherwise, ask the thread manager to
// terminate the thread with the given id if any.
- if (thread_id == i::Top::thread_id()) {
- i::StackGuard::TerminateExecution();
+ if (thread_id == isolate->thread_id()) {
+ isolate->stack_guard()->TerminateExecution();
} else {
- i::ThreadManager::TerminateExecution(thread_id);
+ isolate->thread_manager()->TerminateExecution(thread_id);
}
}
-void V8::TerminateExecution() {
- if (!i::V8::IsRunning()) return;
- i::StackGuard::TerminateExecution();
+void V8::TerminateExecution(Isolate* isolate) {
+ // If no isolate is supplied, use the default isolate.
+ if (isolate != NULL) {
+ reinterpret_cast<i::Isolate*>(isolate)->stack_guard()->TerminateExecution();
+ } else {
+ i::Isolate::GetDefaultIsolateStackGuard()->TerminateExecution();
+ }
}
bool V8::IsExecutionTerminating() {
- if (!i::V8::IsRunning()) return false;
- if (i::Top::has_scheduled_exception()) {
- return i::Top::scheduled_exception() == i::Heap::termination_exception();
+ i::Isolate* isolate = i::Isolate::Current();
+ return IsExecutionTerminatingCheck(isolate);
+}
+
+
+Isolate* Isolate::GetCurrent() {
+ i::Isolate* isolate = i::Isolate::UncheckedCurrent();
+ return reinterpret_cast<Isolate*>(isolate);
+}
+
+
+Isolate* Isolate::New() {
+ i::Isolate* isolate = new i::Isolate();
+ return reinterpret_cast<Isolate*>(isolate);
+}
+
+
+void Isolate::Dispose() {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ if (!ApiCheck(!isolate->IsInUse(),
+ "v8::Isolate::Dispose()",
+ "Disposing the isolate that is entered by a thread.")) {
+ return;
}
- return false;
+ isolate->TearDown();
+}
+
+
+void Isolate::Enter() {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ isolate->Enter();
+}
+
+
+void Isolate::Exit() {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ isolate->Exit();
}
String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) {
- EnsureInitialized("v8::String::Utf8Value::Utf8Value()");
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::String::Utf8Value::Utf8Value()")) return;
if (obj.IsEmpty()) {
str_ = NULL;
length_ = 0;
return;
}
- ENTER_V8;
- HandleScope scope;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
TryCatch try_catch;
Handle<String> str = obj->ToString();
if (str.IsEmpty()) {
@@ -4293,14 +4690,15 @@ String::Utf8Value::~Utf8Value() {
String::AsciiValue::AsciiValue(v8::Handle<v8::Value> obj) {
- EnsureInitialized("v8::String::AsciiValue::AsciiValue()");
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::String::AsciiValue::AsciiValue()")) return;
if (obj.IsEmpty()) {
str_ = NULL;
length_ = 0;
return;
}
- ENTER_V8;
- HandleScope scope;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
TryCatch try_catch;
Handle<String> str = obj->ToString();
if (str.IsEmpty()) {
@@ -4320,14 +4718,15 @@ String::AsciiValue::~AsciiValue() {
String::Value::Value(v8::Handle<v8::Value> obj) {
- EnsureInitialized("v8::String::Value::Value()");
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::String::Value::Value()")) return;
if (obj.IsEmpty()) {
str_ = NULL;
length_ = 0;
return;
}
- ENTER_V8;
- HandleScope scope;
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
TryCatch try_catch;
Handle<String> str = obj->ToString();
if (str.IsEmpty()) {
@@ -4346,14 +4745,15 @@ String::Value::~Value() {
}
Local<Value> Exception::RangeError(v8::Handle<v8::String> raw_message) {
- LOG_API("RangeError");
- ON_BAILOUT("v8::Exception::RangeError()", return Local<Value>());
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "RangeError");
+ ON_BAILOUT(isolate, "v8::Exception::RangeError()", return Local<Value>());
+ ENTER_V8(isolate);
i::Object* error;
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
- i::Handle<i::Object> result = i::Factory::NewRangeError(message);
+ i::Handle<i::Object> result = isolate->factory()->NewRangeError(message);
error = *result;
}
i::Handle<i::Object> result(error);
@@ -4361,14 +4761,16 @@ Local<Value> Exception::RangeError(v8::Handle<v8::String> raw_message) {
}
Local<Value> Exception::ReferenceError(v8::Handle<v8::String> raw_message) {
- LOG_API("ReferenceError");
- ON_BAILOUT("v8::Exception::ReferenceError()", return Local<Value>());
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "ReferenceError");
+ ON_BAILOUT(isolate, "v8::Exception::ReferenceError()", return Local<Value>());
+ ENTER_V8(isolate);
i::Object* error;
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
- i::Handle<i::Object> result = i::Factory::NewReferenceError(message);
+ i::Handle<i::Object> result =
+ isolate->factory()->NewReferenceError(message);
error = *result;
}
i::Handle<i::Object> result(error);
@@ -4376,14 +4778,15 @@ Local<Value> Exception::ReferenceError(v8::Handle<v8::String> raw_message) {
}
Local<Value> Exception::SyntaxError(v8::Handle<v8::String> raw_message) {
- LOG_API("SyntaxError");
- ON_BAILOUT("v8::Exception::SyntaxError()", return Local<Value>());
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "SyntaxError");
+ ON_BAILOUT(isolate, "v8::Exception::SyntaxError()", return Local<Value>());
+ ENTER_V8(isolate);
i::Object* error;
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
- i::Handle<i::Object> result = i::Factory::NewSyntaxError(message);
+ i::Handle<i::Object> result = isolate->factory()->NewSyntaxError(message);
error = *result;
}
i::Handle<i::Object> result(error);
@@ -4391,14 +4794,15 @@ Local<Value> Exception::SyntaxError(v8::Handle<v8::String> raw_message) {
}
Local<Value> Exception::TypeError(v8::Handle<v8::String> raw_message) {
- LOG_API("TypeError");
- ON_BAILOUT("v8::Exception::TypeError()", return Local<Value>());
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "TypeError");
+ ON_BAILOUT(isolate, "v8::Exception::TypeError()", return Local<Value>());
+ ENTER_V8(isolate);
i::Object* error;
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
- i::Handle<i::Object> result = i::Factory::NewTypeError(message);
+ i::Handle<i::Object> result = isolate->factory()->NewTypeError(message);
error = *result;
}
i::Handle<i::Object> result(error);
@@ -4406,14 +4810,15 @@ Local<Value> Exception::TypeError(v8::Handle<v8::String> raw_message) {
}
Local<Value> Exception::Error(v8::Handle<v8::String> raw_message) {
- LOG_API("Error");
- ON_BAILOUT("v8::Exception::Error()", return Local<Value>());
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "Error");
+ ON_BAILOUT(isolate, "v8::Exception::Error()", return Local<Value>());
+ ENTER_V8(isolate);
i::Object* error;
{
- HandleScope scope;
+ i::HandleScope scope(isolate);
i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
- i::Handle<i::Object> result = i::Factory::NewError(message);
+ i::Handle<i::Object> result = isolate->factory()->NewError(message);
error = *result;
}
i::Handle<i::Object> result(error);
@@ -4425,180 +4830,216 @@ Local<Value> Exception::Error(v8::Handle<v8::String> raw_message) {
#ifdef ENABLE_DEBUGGER_SUPPORT
-static v8::Debug::EventCallback event_callback = NULL;
-
static void EventCallbackWrapper(const v8::Debug::EventDetails& event_details) {
- if (event_callback) {
- event_callback(event_details.GetEvent(),
- event_details.GetExecutionState(),
- event_details.GetEventData(),
- event_details.GetCallbackData());
+ i::Isolate* isolate = i::Isolate::Current();
+ if (isolate->debug_event_callback() != NULL) {
+ isolate->debug_event_callback()(event_details.GetEvent(),
+ event_details.GetExecutionState(),
+ event_details.GetEventData(),
+ event_details.GetCallbackData());
}
}
bool Debug::SetDebugEventListener(EventCallback that, Handle<Value> data) {
- EnsureInitialized("v8::Debug::SetDebugEventListener()");
- ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false);
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Debug::SetDebugEventListener()");
+ ON_BAILOUT(isolate, "v8::Debug::SetDebugEventListener()", return false);
+ ENTER_V8(isolate);
- event_callback = that;
+ isolate->set_debug_event_callback(that);
- HandleScope scope;
- i::Handle<i::Object> proxy = i::Factory::undefined_value();
+ i::HandleScope scope(isolate);
+ i::Handle<i::Object> proxy = isolate->factory()->undefined_value();
if (that != NULL) {
- proxy = i::Factory::NewProxy(FUNCTION_ADDR(EventCallbackWrapper));
+ proxy = isolate->factory()->NewProxy(FUNCTION_ADDR(EventCallbackWrapper));
}
- i::Debugger::SetEventListener(proxy, Utils::OpenHandle(*data));
+ isolate->debugger()->SetEventListener(proxy, Utils::OpenHandle(*data));
return true;
}
bool Debug::SetDebugEventListener2(EventCallback2 that, Handle<Value> data) {
- EnsureInitialized("v8::Debug::SetDebugEventListener2()");
- ON_BAILOUT("v8::Debug::SetDebugEventListener2()", return false);
- ENTER_V8;
- HandleScope scope;
- i::Handle<i::Object> proxy = i::Factory::undefined_value();
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Debug::SetDebugEventListener2()");
+ ON_BAILOUT(isolate, "v8::Debug::SetDebugEventListener2()", return false);
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
+ i::Handle<i::Object> proxy = isolate->factory()->undefined_value();
if (that != NULL) {
- proxy = i::Factory::NewProxy(FUNCTION_ADDR(that));
+ proxy = isolate->factory()->NewProxy(FUNCTION_ADDR(that));
}
- i::Debugger::SetEventListener(proxy, Utils::OpenHandle(*data));
+ isolate->debugger()->SetEventListener(proxy,
+ Utils::OpenHandle(*data));
return true;
}
bool Debug::SetDebugEventListener(v8::Handle<v8::Object> that,
Handle<Value> data) {
- ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false);
- ENTER_V8;
- i::Debugger::SetEventListener(Utils::OpenHandle(*that),
- Utils::OpenHandle(*data));
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Debug::SetDebugEventListener()", return false);
+ ENTER_V8(isolate);
+ isolate->debugger()->SetEventListener(Utils::OpenHandle(*that),
+ Utils::OpenHandle(*data));
return true;
}
-void Debug::DebugBreak() {
- if (!i::V8::IsRunning()) return;
- i::StackGuard::DebugBreak();
+void Debug::DebugBreak(Isolate* isolate) {
+ // If no isolate is supplied, use the default isolate.
+ if (isolate != NULL) {
+ reinterpret_cast<i::Isolate*>(isolate)->stack_guard()->DebugBreak();
+ } else {
+ i::Isolate::GetDefaultIsolateStackGuard()->DebugBreak();
+ }
}
-void Debug::CancelDebugBreak() {
- i::StackGuard::Continue(i::DEBUGBREAK);
+void Debug::CancelDebugBreak(Isolate* isolate) {
+ // If no isolate is supplied, use the default isolate.
+ if (isolate != NULL) {
+ i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ internal_isolate->stack_guard()->Continue(i::DEBUGBREAK);
+ } else {
+ i::Isolate::GetDefaultIsolateStackGuard()->Continue(i::DEBUGBREAK);
+ }
}
-void Debug::DebugBreakForCommand(ClientData* data) {
- if (!i::V8::IsRunning()) return;
- i::Debugger::EnqueueDebugCommand(data);
+void Debug::DebugBreakForCommand(ClientData* data, Isolate* isolate) {
+ // If no isolate is supplied, use the default isolate.
+ if (isolate != NULL) {
+ i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ internal_isolate->debugger()->EnqueueDebugCommand(data);
+ } else {
+ i::Isolate::GetDefaultIsolateDebugger()->EnqueueDebugCommand(data);
+ }
}
-static v8::Debug::MessageHandler message_handler = NULL;
-
static void MessageHandlerWrapper(const v8::Debug::Message& message) {
- if (message_handler) {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (isolate->message_handler()) {
v8::String::Value json(message.GetJSON());
- message_handler(*json, json.length(), message.GetClientData());
+ (isolate->message_handler())(*json, json.length(), message.GetClientData());
}
}
void Debug::SetMessageHandler(v8::Debug::MessageHandler handler,
bool message_handler_thread) {
- EnsureInitialized("v8::Debug::SetMessageHandler");
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Debug::SetMessageHandler");
+ ENTER_V8(isolate);
+
// Message handler thread not supported any more. Parameter temporally left in
- // the API for client compatability reasons.
+ // the API for client compatibility reasons.
CHECK(!message_handler_thread);
// TODO(sgjesse) support the old message handler API through a simple wrapper.
- message_handler = handler;
- if (message_handler != NULL) {
- i::Debugger::SetMessageHandler(MessageHandlerWrapper);
+ isolate->set_message_handler(handler);
+ if (handler != NULL) {
+ isolate->debugger()->SetMessageHandler(MessageHandlerWrapper);
} else {
- i::Debugger::SetMessageHandler(NULL);
+ isolate->debugger()->SetMessageHandler(NULL);
}
}
void Debug::SetMessageHandler2(v8::Debug::MessageHandler2 handler) {
- EnsureInitialized("v8::Debug::SetMessageHandler");
- ENTER_V8;
- i::Debugger::SetMessageHandler(handler);
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Debug::SetMessageHandler");
+ ENTER_V8(isolate);
+ isolate->debugger()->SetMessageHandler(handler);
}
void Debug::SendCommand(const uint16_t* command, int length,
- ClientData* client_data) {
- if (!i::V8::IsRunning()) return;
- i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length),
- client_data);
+ ClientData* client_data,
+ Isolate* isolate) {
+ // If no isolate is supplied, use the default isolate.
+ if (isolate != NULL) {
+ i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ internal_isolate->debugger()->ProcessCommand(
+ i::Vector<const uint16_t>(command, length), client_data);
+ } else {
+ i::Isolate::GetDefaultIsolateDebugger()->ProcessCommand(
+ i::Vector<const uint16_t>(command, length), client_data);
+ }
}
void Debug::SetHostDispatchHandler(HostDispatchHandler handler,
int period) {
- EnsureInitialized("v8::Debug::SetHostDispatchHandler");
- ENTER_V8;
- i::Debugger::SetHostDispatchHandler(handler, period);
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Debug::SetHostDispatchHandler");
+ ENTER_V8(isolate);
+ isolate->debugger()->SetHostDispatchHandler(handler, period);
}
void Debug::SetDebugMessageDispatchHandler(
DebugMessageDispatchHandler handler, bool provide_locker) {
- EnsureInitialized("v8::Debug::SetDebugMessageDispatchHandler");
- ENTER_V8;
- i::Debugger::SetDebugMessageDispatchHandler(handler, provide_locker);
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate,
+ "v8::Debug::SetDebugMessageDispatchHandler");
+ ENTER_V8(isolate);
+ isolate->debugger()->SetDebugMessageDispatchHandler(
+ handler, provide_locker);
}
Local<Value> Debug::Call(v8::Handle<v8::Function> fun,
v8::Handle<v8::Value> data) {
- if (!i::V8::IsRunning()) return Local<Value>();
- ON_BAILOUT("v8::Debug::Call()", return Local<Value>());
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!isolate->IsInitialized()) return Local<Value>();
+ ON_BAILOUT(isolate, "v8::Debug::Call()", return Local<Value>());
+ ENTER_V8(isolate);
i::Handle<i::Object> result;
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
if (data.IsEmpty()) {
- result = i::Debugger::Call(Utils::OpenHandle(*fun),
- i::Factory::undefined_value(),
- &has_pending_exception);
+ result = isolate->debugger()->Call(Utils::OpenHandle(*fun),
+ isolate->factory()->undefined_value(),
+ &has_pending_exception);
} else {
- result = i::Debugger::Call(Utils::OpenHandle(*fun),
- Utils::OpenHandle(*data),
- &has_pending_exception);
+ result = isolate->debugger()->Call(Utils::OpenHandle(*fun),
+ Utils::OpenHandle(*data),
+ &has_pending_exception);
}
- EXCEPTION_BAILOUT_CHECK(Local<Value>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
return Utils::ToLocal(result);
}
Local<Value> Debug::GetMirror(v8::Handle<v8::Value> obj) {
- if (!i::V8::IsRunning()) return Local<Value>();
- ON_BAILOUT("v8::Debug::GetMirror()", return Local<Value>());
- ENTER_V8;
+ i::Isolate* isolate = i::Isolate::Current();
+ if (!isolate->IsInitialized()) return Local<Value>();
+ ON_BAILOUT(isolate, "v8::Debug::GetMirror()", return Local<Value>());
+ ENTER_V8(isolate);
v8::HandleScope scope;
- i::Debug::Load();
- i::Handle<i::JSObject> debug(i::Debug::debug_context()->global());
- i::Handle<i::String> name = i::Factory::LookupAsciiSymbol("MakeMirror");
+ i::Debug* isolate_debug = isolate->debug();
+ isolate_debug->Load();
+ i::Handle<i::JSObject> debug(isolate_debug->debug_context()->global());
+ i::Handle<i::String> name =
+ isolate->factory()->LookupAsciiSymbol("MakeMirror");
i::Handle<i::Object> fun_obj = i::GetProperty(debug, name);
i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(fun_obj);
v8::Handle<v8::Function> v8_fun = Utils::ToLocal(fun);
const int kArgc = 1;
v8::Handle<v8::Value> argv[kArgc] = { obj };
- EXCEPTION_PREAMBLE();
+ EXCEPTION_PREAMBLE(isolate);
v8::Handle<v8::Value> result = v8_fun->Call(Utils::ToLocal(debug),
kArgc,
argv);
- EXCEPTION_BAILOUT_CHECK(Local<Value>());
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
return scope.Close(result);
}
bool Debug::EnableAgent(const char* name, int port, bool wait_for_connection) {
- return i::Debugger::StartAgent(name, port, wait_for_connection);
+ return i::Isolate::Current()->debugger()->StartAgent(name, port,
+ wait_for_connection);
}
void Debug::ProcessDebugMessages() {
@@ -4606,9 +5047,10 @@ void Debug::ProcessDebugMessages() {
}
Local<Context> Debug::GetDebugContext() {
- EnsureInitialized("v8::Debug::GetDebugContext()");
- ENTER_V8;
- return Utils::ToLocal(i::Debugger::GetDebugContext());
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::Debug::GetDebugContext()");
+ ENTER_V8(isolate);
+ return Utils::ToLocal(i::Isolate::Current()->debugger()->GetDebugContext());
}
#endif // ENABLE_DEBUGGER_SUPPORT
@@ -4617,115 +5059,143 @@ Local<Context> Debug::GetDebugContext() {
#ifdef ENABLE_LOGGING_AND_PROFILING
Handle<String> CpuProfileNode::GetFunctionName() const {
- IsDeadCheck("v8::CpuProfileNode::GetFunctionName");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetFunctionName");
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
const i::CodeEntry* entry = node->entry();
if (!entry->has_name_prefix()) {
return Handle<String>(ToApi<String>(
- i::Factory::LookupAsciiSymbol(entry->name())));
+ isolate->factory()->LookupAsciiSymbol(entry->name())));
} else {
- return Handle<String>(ToApi<String>(i::Factory::NewConsString(
- i::Factory::LookupAsciiSymbol(entry->name_prefix()),
- i::Factory::LookupAsciiSymbol(entry->name()))));
+ return Handle<String>(ToApi<String>(isolate->factory()->NewConsString(
+ isolate->factory()->LookupAsciiSymbol(entry->name_prefix()),
+ isolate->factory()->LookupAsciiSymbol(entry->name()))));
}
}
Handle<String> CpuProfileNode::GetScriptResourceName() const {
- IsDeadCheck("v8::CpuProfileNode::GetScriptResourceName");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetScriptResourceName");
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
- return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
+ return Handle<String>(ToApi<String>(isolate->factory()->LookupAsciiSymbol(
node->entry()->resource_name())));
}
int CpuProfileNode::GetLineNumber() const {
- IsDeadCheck("v8::CpuProfileNode::GetLineNumber");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetLineNumber");
return reinterpret_cast<const i::ProfileNode*>(this)->entry()->line_number();
}
double CpuProfileNode::GetTotalTime() const {
- IsDeadCheck("v8::CpuProfileNode::GetTotalTime");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetTotalTime");
return reinterpret_cast<const i::ProfileNode*>(this)->GetTotalMillis();
}
double CpuProfileNode::GetSelfTime() const {
- IsDeadCheck("v8::CpuProfileNode::GetSelfTime");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetSelfTime");
return reinterpret_cast<const i::ProfileNode*>(this)->GetSelfMillis();
}
double CpuProfileNode::GetTotalSamplesCount() const {
- IsDeadCheck("v8::CpuProfileNode::GetTotalSamplesCount");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetTotalSamplesCount");
return reinterpret_cast<const i::ProfileNode*>(this)->total_ticks();
}
double CpuProfileNode::GetSelfSamplesCount() const {
- IsDeadCheck("v8::CpuProfileNode::GetSelfSamplesCount");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetSelfSamplesCount");
return reinterpret_cast<const i::ProfileNode*>(this)->self_ticks();
}
unsigned CpuProfileNode::GetCallUid() const {
- IsDeadCheck("v8::CpuProfileNode::GetCallUid");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetCallUid");
return reinterpret_cast<const i::ProfileNode*>(this)->entry()->GetCallUid();
}
int CpuProfileNode::GetChildrenCount() const {
- IsDeadCheck("v8::CpuProfileNode::GetChildrenCount");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetChildrenCount");
return reinterpret_cast<const i::ProfileNode*>(this)->children()->length();
}
const CpuProfileNode* CpuProfileNode::GetChild(int index) const {
- IsDeadCheck("v8::CpuProfileNode::GetChild");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfileNode::GetChild");
const i::ProfileNode* child =
reinterpret_cast<const i::ProfileNode*>(this)->children()->at(index);
return reinterpret_cast<const CpuProfileNode*>(child);
}
+void CpuProfile::Delete() {
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfile::Delete");
+ i::CpuProfiler::DeleteProfile(reinterpret_cast<i::CpuProfile*>(this));
+ if (i::CpuProfiler::GetProfilesCount() == 0 &&
+ !i::CpuProfiler::HasDetachedProfiles()) {
+ // If this was the last profile, clean up all accessory data as well.
+ i::CpuProfiler::DeleteAllProfiles();
+ }
+}
+
+
unsigned CpuProfile::GetUid() const {
- IsDeadCheck("v8::CpuProfile::GetUid");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfile::GetUid");
return reinterpret_cast<const i::CpuProfile*>(this)->uid();
}
Handle<String> CpuProfile::GetTitle() const {
- IsDeadCheck("v8::CpuProfile::GetTitle");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfile::GetTitle");
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
- return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
+ return Handle<String>(ToApi<String>(isolate->factory()->LookupAsciiSymbol(
profile->title())));
}
const CpuProfileNode* CpuProfile::GetBottomUpRoot() const {
- IsDeadCheck("v8::CpuProfile::GetBottomUpRoot");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfile::GetBottomUpRoot");
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
return reinterpret_cast<const CpuProfileNode*>(profile->bottom_up()->root());
}
const CpuProfileNode* CpuProfile::GetTopDownRoot() const {
- IsDeadCheck("v8::CpuProfile::GetTopDownRoot");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfile::GetTopDownRoot");
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
return reinterpret_cast<const CpuProfileNode*>(profile->top_down()->root());
}
int CpuProfiler::GetProfilesCount() {
- IsDeadCheck("v8::CpuProfiler::GetProfilesCount");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfiler::GetProfilesCount");
return i::CpuProfiler::GetProfilesCount();
}
const CpuProfile* CpuProfiler::GetProfile(int index,
Handle<Value> security_token) {
- IsDeadCheck("v8::CpuProfiler::GetProfile");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfiler::GetProfile");
return reinterpret_cast<const CpuProfile*>(
i::CpuProfiler::GetProfile(
security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
@@ -4735,7 +5205,8 @@ const CpuProfile* CpuProfiler::GetProfile(int index,
const CpuProfile* CpuProfiler::FindProfile(unsigned uid,
Handle<Value> security_token) {
- IsDeadCheck("v8::CpuProfiler::FindProfile");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfiler::FindProfile");
return reinterpret_cast<const CpuProfile*>(
i::CpuProfiler::FindProfile(
security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
@@ -4744,14 +5215,16 @@ const CpuProfile* CpuProfiler::FindProfile(unsigned uid,
void CpuProfiler::StartProfiling(Handle<String> title) {
- IsDeadCheck("v8::CpuProfiler::StartProfiling");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfiler::StartProfiling");
i::CpuProfiler::StartProfiling(*Utils::OpenHandle(*title));
}
const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title,
Handle<Value> security_token) {
- IsDeadCheck("v8::CpuProfiler::StopProfiling");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfiler::StopProfiling");
return reinterpret_cast<const CpuProfile*>(
i::CpuProfiler::StopProfiling(
security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
@@ -4759,79 +5232,62 @@ const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title,
}
+void CpuProfiler::DeleteAllProfiles() {
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::CpuProfiler::DeleteAllProfiles");
+ i::CpuProfiler::DeleteAllProfiles();
+}
+
+
static i::HeapGraphEdge* ToInternal(const HeapGraphEdge* edge) {
return const_cast<i::HeapGraphEdge*>(
reinterpret_cast<const i::HeapGraphEdge*>(edge));
}
HeapGraphEdge::Type HeapGraphEdge::GetType() const {
- IsDeadCheck("v8::HeapGraphEdge::GetType");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapGraphEdge::GetType");
return static_cast<HeapGraphEdge::Type>(ToInternal(this)->type());
}
Handle<Value> HeapGraphEdge::GetName() const {
- IsDeadCheck("v8::HeapGraphEdge::GetName");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapGraphEdge::GetName");
i::HeapGraphEdge* edge = ToInternal(this);
switch (edge->type()) {
case i::HeapGraphEdge::kContextVariable:
case i::HeapGraphEdge::kInternal:
case i::HeapGraphEdge::kProperty:
case i::HeapGraphEdge::kShortcut:
- return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
+ return Handle<String>(ToApi<String>(isolate->factory()->LookupAsciiSymbol(
edge->name())));
case i::HeapGraphEdge::kElement:
case i::HeapGraphEdge::kHidden:
- return Handle<Number>(ToApi<Number>(i::Factory::NewNumberFromInt(
+ return Handle<Number>(ToApi<Number>(isolate->factory()->NewNumberFromInt(
edge->index())));
default: UNREACHABLE();
}
- return ImplementationUtilities::Undefined();
+ return v8::Undefined();
}
const HeapGraphNode* HeapGraphEdge::GetFromNode() const {
- IsDeadCheck("v8::HeapGraphEdge::GetFromNode");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapGraphEdge::GetFromNode");
const i::HeapEntry* from = ToInternal(this)->From();
return reinterpret_cast<const HeapGraphNode*>(from);
}
const HeapGraphNode* HeapGraphEdge::GetToNode() const {
- IsDeadCheck("v8::HeapGraphEdge::GetToNode");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapGraphEdge::GetToNode");
const i::HeapEntry* to = ToInternal(this)->to();
return reinterpret_cast<const HeapGraphNode*>(to);
}
-static i::HeapGraphPath* ToInternal(const HeapGraphPath* path) {
- return const_cast<i::HeapGraphPath*>(
- reinterpret_cast<const i::HeapGraphPath*>(path));
-}
-
-
-int HeapGraphPath::GetEdgesCount() const {
- return ToInternal(this)->path()->length();
-}
-
-
-const HeapGraphEdge* HeapGraphPath::GetEdge(int index) const {
- return reinterpret_cast<const HeapGraphEdge*>(
- ToInternal(this)->path()->at(index));
-}
-
-
-const HeapGraphNode* HeapGraphPath::GetFromNode() const {
- return GetEdgesCount() > 0 ? GetEdge(0)->GetFromNode() : NULL;
-}
-
-
-const HeapGraphNode* HeapGraphPath::GetToNode() const {
- const int count = GetEdgesCount();
- return count > 0 ? GetEdge(count - 1)->GetToNode() : NULL;
-}
-
-
static i::HeapEntry* ToInternal(const HeapGraphNode* entry) {
return const_cast<i::HeapEntry*>(
reinterpret_cast<const i::HeapEntry*>(entry));
@@ -4839,156 +5295,146 @@ static i::HeapEntry* ToInternal(const HeapGraphNode* entry) {
HeapGraphNode::Type HeapGraphNode::GetType() const {
- IsDeadCheck("v8::HeapGraphNode::GetType");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapGraphNode::GetType");
return static_cast<HeapGraphNode::Type>(ToInternal(this)->type());
}
Handle<String> HeapGraphNode::GetName() const {
- IsDeadCheck("v8::HeapGraphNode::GetName");
- return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapGraphNode::GetName");
+ return Handle<String>(ToApi<String>(isolate->factory()->LookupAsciiSymbol(
ToInternal(this)->name())));
}
uint64_t HeapGraphNode::GetId() const {
- IsDeadCheck("v8::HeapGraphNode::GetId");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapGraphNode::GetId");
ASSERT(ToInternal(this)->snapshot()->type() != i::HeapSnapshot::kAggregated);
return ToInternal(this)->id();
}
int HeapGraphNode::GetInstancesCount() const {
- IsDeadCheck("v8::HeapGraphNode::GetInstancesCount");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapGraphNode::GetInstancesCount");
ASSERT(ToInternal(this)->snapshot()->type() == i::HeapSnapshot::kAggregated);
return static_cast<int>(ToInternal(this)->id());
}
int HeapGraphNode::GetSelfSize() const {
- IsDeadCheck("v8::HeapGraphNode::GetSelfSize");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapGraphNode::GetSelfSize");
return ToInternal(this)->self_size();
}
int HeapGraphNode::GetRetainedSize(bool exact) const {
- IsDeadCheck("v8::HeapSnapshot::GetRetainedSize");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetRetainedSize");
return ToInternal(this)->RetainedSize(exact);
}
int HeapGraphNode::GetChildrenCount() const {
- IsDeadCheck("v8::HeapSnapshot::GetChildrenCount");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetChildrenCount");
return ToInternal(this)->children().length();
}
const HeapGraphEdge* HeapGraphNode::GetChild(int index) const {
- IsDeadCheck("v8::HeapSnapshot::GetChild");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetChild");
return reinterpret_cast<const HeapGraphEdge*>(
&ToInternal(this)->children()[index]);
}
int HeapGraphNode::GetRetainersCount() const {
- IsDeadCheck("v8::HeapSnapshot::GetRetainersCount");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetRetainersCount");
return ToInternal(this)->retainers().length();
}
const HeapGraphEdge* HeapGraphNode::GetRetainer(int index) const {
- IsDeadCheck("v8::HeapSnapshot::GetRetainer");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetRetainer");
return reinterpret_cast<const HeapGraphEdge*>(
ToInternal(this)->retainers()[index]);
}
-int HeapGraphNode::GetRetainingPathsCount() const {
- IsDeadCheck("v8::HeapSnapshot::GetRetainingPathsCount");
- return ToInternal(this)->GetRetainingPaths()->length();
-}
-
-
-const HeapGraphPath* HeapGraphNode::GetRetainingPath(int index) const {
- IsDeadCheck("v8::HeapSnapshot::GetRetainingPath");
- return reinterpret_cast<const HeapGraphPath*>(
- ToInternal(this)->GetRetainingPaths()->at(index));
-}
-
-
const HeapGraphNode* HeapGraphNode::GetDominatorNode() const {
- IsDeadCheck("v8::HeapSnapshot::GetDominatorNode");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetDominatorNode");
return reinterpret_cast<const HeapGraphNode*>(ToInternal(this)->dominator());
}
-const HeapGraphNode* HeapSnapshotsDiff::GetAdditionsRoot() const {
- IsDeadCheck("v8::HeapSnapshotsDiff::GetAdditionsRoot");
- i::HeapSnapshotsDiff* diff =
- const_cast<i::HeapSnapshotsDiff*>(
- reinterpret_cast<const i::HeapSnapshotsDiff*>(this));
- return reinterpret_cast<const HeapGraphNode*>(diff->additions_root());
-}
-
-
-const HeapGraphNode* HeapSnapshotsDiff::GetDeletionsRoot() const {
- IsDeadCheck("v8::HeapSnapshotsDiff::GetDeletionsRoot");
- i::HeapSnapshotsDiff* diff =
- const_cast<i::HeapSnapshotsDiff*>(
- reinterpret_cast<const i::HeapSnapshotsDiff*>(this));
- return reinterpret_cast<const HeapGraphNode*>(diff->deletions_root());
-}
-
-
static i::HeapSnapshot* ToInternal(const HeapSnapshot* snapshot) {
return const_cast<i::HeapSnapshot*>(
reinterpret_cast<const i::HeapSnapshot*>(snapshot));
}
+void HeapSnapshot::Delete() {
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::Delete");
+ if (i::HeapProfiler::GetSnapshotsCount() > 1) {
+ ToInternal(this)->Delete();
+ } else {
+ // If this is the last snapshot, clean up all accessory data as well.
+ i::HeapProfiler::DeleteAllSnapshots();
+ }
+}
+
+
HeapSnapshot::Type HeapSnapshot::GetType() const {
- IsDeadCheck("v8::HeapSnapshot::GetType");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetType");
return static_cast<HeapSnapshot::Type>(ToInternal(this)->type());
}
unsigned HeapSnapshot::GetUid() const {
- IsDeadCheck("v8::HeapSnapshot::GetUid");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetUid");
return ToInternal(this)->uid();
}
Handle<String> HeapSnapshot::GetTitle() const {
- IsDeadCheck("v8::HeapSnapshot::GetTitle");
- return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetTitle");
+ return Handle<String>(ToApi<String>(isolate->factory()->LookupAsciiSymbol(
ToInternal(this)->title())));
}
const HeapGraphNode* HeapSnapshot::GetRoot() const {
- IsDeadCheck("v8::HeapSnapshot::GetHead");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetHead");
return reinterpret_cast<const HeapGraphNode*>(ToInternal(this)->root());
}
const HeapGraphNode* HeapSnapshot::GetNodeById(uint64_t id) const {
- IsDeadCheck("v8::HeapSnapshot::GetNodeById");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::GetNodeById");
return reinterpret_cast<const HeapGraphNode*>(
ToInternal(this)->GetEntryById(id));
}
-const HeapSnapshotsDiff* HeapSnapshot::CompareWith(
- const HeapSnapshot* snapshot) const {
- IsDeadCheck("v8::HeapSnapshot::CompareWith");
- return reinterpret_cast<const HeapSnapshotsDiff*>(
- ToInternal(this)->CompareWith(ToInternal(snapshot)));
-}
-
-
void HeapSnapshot::Serialize(OutputStream* stream,
HeapSnapshot::SerializationFormat format) const {
- IsDeadCheck("v8::HeapSnapshot::Serialize");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapSnapshot::Serialize");
ApiCheck(format == kJSON,
"v8::HeapSnapshot::Serialize",
"Unknown serialization format");
@@ -5004,20 +5450,23 @@ void HeapSnapshot::Serialize(OutputStream* stream,
int HeapProfiler::GetSnapshotsCount() {
- IsDeadCheck("v8::HeapProfiler::GetSnapshotsCount");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshotsCount");
return i::HeapProfiler::GetSnapshotsCount();
}
const HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
- IsDeadCheck("v8::HeapProfiler::GetSnapshot");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshot");
return reinterpret_cast<const HeapSnapshot*>(
i::HeapProfiler::GetSnapshot(index));
}
const HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) {
- IsDeadCheck("v8::HeapProfiler::FindSnapshot");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapProfiler::FindSnapshot");
return reinterpret_cast<const HeapSnapshot*>(
i::HeapProfiler::FindSnapshot(uid));
}
@@ -5026,7 +5475,8 @@ const HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) {
const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title,
HeapSnapshot::Type type,
ActivityControl* control) {
- IsDeadCheck("v8::HeapProfiler::TakeSnapshot");
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapProfiler::TakeSnapshot");
i::HeapSnapshot::Type internal_type = i::HeapSnapshot::kFull;
switch (type) {
case HeapSnapshot::kFull:
@@ -5043,6 +5493,20 @@ const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title,
*Utils::OpenHandle(*title), internal_type, control));
}
+
+void HeapProfiler::DeleteAllSnapshots() {
+ i::Isolate* isolate = i::Isolate::Current();
+ IsDeadCheck(isolate, "v8::HeapProfiler::DeleteAllSnapshots");
+ i::HeapProfiler::DeleteAllSnapshots();
+}
+
+
+void HeapProfiler::DefineWrapperClass(uint16_t class_id,
+ WrapperInfoCallback callback) {
+ i::Isolate::Current()->heap_profiler()->DefineWrapperClass(class_id,
+ callback);
+}
+
#endif // ENABLE_LOGGING_AND_PROFILING
@@ -5107,27 +5571,23 @@ void Testing::PrepareStressRun(int run) {
}
-namespace internal {
+void Testing::DeoptimizeAll() {
+ internal::Deoptimizer::DeoptimizeAll();
+}
-HandleScopeImplementer* HandleScopeImplementer::instance() {
- return &thread_local;
-}
+namespace internal {
void HandleScopeImplementer::FreeThreadResources() {
- thread_local.Free();
+ Free();
}
char* HandleScopeImplementer::ArchiveThread(char* storage) {
- return thread_local.ArchiveThreadHelper(storage);
-}
-
-
-char* HandleScopeImplementer::ArchiveThreadHelper(char* storage) {
+ Isolate* isolate = Isolate::Current();
v8::ImplementationUtilities::HandleScopeData* current =
- v8::ImplementationUtilities::CurrentHandleScope();
+ isolate->handle_scope_data();
handle_scope_data_ = *current;
memcpy(storage, this, sizeof(*this));
@@ -5139,18 +5599,13 @@ char* HandleScopeImplementer::ArchiveThreadHelper(char* storage) {
int HandleScopeImplementer::ArchiveSpacePerThread() {
- return sizeof(thread_local);
+ return sizeof(HandleScopeImplementer);
}
char* HandleScopeImplementer::RestoreThread(char* storage) {
- return thread_local.RestoreThreadHelper(storage);
-}
-
-
-char* HandleScopeImplementer::RestoreThreadHelper(char* storage) {
memcpy(this, storage, sizeof(*this));
- *v8::ImplementationUtilities::CurrentHandleScope() = handle_scope_data_;
+ *Isolate::Current()->handle_scope_data() = handle_scope_data_;
return storage + ArchiveSpacePerThread();
}
@@ -5176,16 +5631,16 @@ void HandleScopeImplementer::IterateThis(ObjectVisitor* v) {
void HandleScopeImplementer::Iterate(ObjectVisitor* v) {
v8::ImplementationUtilities::HandleScopeData* current =
- v8::ImplementationUtilities::CurrentHandleScope();
- thread_local.handle_scope_data_ = *current;
- thread_local.IterateThis(v);
+ Isolate::Current()->handle_scope_data();
+ handle_scope_data_ = *current;
+ IterateThis(v);
}
char* HandleScopeImplementer::Iterate(ObjectVisitor* v, char* storage) {
- HandleScopeImplementer* thread_local =
+ HandleScopeImplementer* scope_implementer =
reinterpret_cast<HandleScopeImplementer*>(storage);
- thread_local->IterateThis(v);
+ scope_implementer->IterateThis(v);
return storage + ArchiveSpacePerThread();
}
diff --git a/src/api.h b/src/api.h
index d07d75b9..6d46713e 100644
--- a/src/api.h
+++ b/src/api.h
@@ -122,7 +122,7 @@ template <typename T> static inline T ToCData(v8::internal::Object* obj) {
template <typename T>
static inline v8::internal::Handle<v8::internal::Object> FromCData(T obj) {
STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address));
- return v8::internal::Factory::NewProxy(
+ return FACTORY->NewProxy(
reinterpret_cast<v8::internal::Address>(reinterpret_cast<intptr_t>(obj)));
}
@@ -157,7 +157,6 @@ class RegisteredExtension {
RegisteredExtension* next_auto_;
ExtensionTraversalState state_;
static RegisteredExtension* first_extension_;
- static RegisteredExtension* first_auto_extension_;
};
@@ -321,16 +320,83 @@ MAKE_OPEN_HANDLE(StackFrame, JSObject)
namespace internal {
+// Tracks string usage to help make better decisions when
+// externalizing strings.
+//
+// Implementation note: internally this class only tracks fresh
+// strings and keeps a single use counter for them.
+class StringTracker {
+ public:
+ // Records that the given string's characters were copied to some
+ // external buffer. If this happens often we should honor
+ // externalization requests for the string.
+ void RecordWrite(Handle<String> string) {
+ Address address = reinterpret_cast<Address>(*string);
+ Address top = isolate_->heap()->NewSpaceTop();
+ if (IsFreshString(address, top)) {
+ IncrementUseCount(top);
+ }
+ }
+
+ // Estimates freshness and use frequency of the given string based
+ // on how close it is to the new space top and the recorded usage
+ // history.
+ inline bool IsFreshUnusedString(Handle<String> string) {
+ Address address = reinterpret_cast<Address>(*string);
+ Address top = isolate_->heap()->NewSpaceTop();
+ return IsFreshString(address, top) && IsUseCountLow(top);
+ }
+
+ private:
+ StringTracker() : use_count_(0), last_top_(NULL), isolate_(NULL) { }
+
+ static inline bool IsFreshString(Address string, Address top) {
+ return top - kFreshnessLimit <= string && string <= top;
+ }
+
+ inline bool IsUseCountLow(Address top) {
+ if (last_top_ != top) return true;
+ return use_count_ < kUseLimit;
+ }
+
+ inline void IncrementUseCount(Address top) {
+ if (last_top_ != top) {
+ use_count_ = 0;
+ last_top_ = top;
+ }
+ ++use_count_;
+ }
+
+ // Single use counter shared by all fresh strings.
+ int use_count_;
+
+ // Last new space top when the use count above was valid.
+ Address last_top_;
+
+ Isolate* isolate_;
+
+ // How close to the new space top a fresh string has to be.
+ static const int kFreshnessLimit = 1024;
+
+ // The number of uses required to consider a string useful.
+ static const int kUseLimit = 32;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(StringTracker);
+};
+
+
// This class is here in order to be able to declare it a friend of
// HandleScope. Moving these methods to be members of HandleScope would be
-// neat in some ways, but it would expose external implementation details in
+// neat in some ways, but it would expose internal implementation details in
// our public header file, which is undesirable.
//
-// There is a singleton instance of this class to hold the per-thread data.
-// For multithreaded V8 programs this data is copied in and out of storage
+// An isolate has a single instance of this class to hold the current thread's
+// data. In multithreaded V8 programs this data is copied in and out of storage
// so that the currently executing thread always has its own copy of this
// data.
-class HandleScopeImplementer {
+ISOLATED_CLASS HandleScopeImplementer {
public:
HandleScopeImplementer()
@@ -341,16 +407,14 @@ class HandleScopeImplementer {
ignore_out_of_memory_(false),
call_depth_(0) { }
- static HandleScopeImplementer* instance();
-
// Threading support for handle data.
static int ArchiveSpacePerThread();
- static char* RestoreThread(char* from);
- static char* ArchiveThread(char* to);
- static void FreeThreadResources();
+ char* RestoreThread(char* from);
+ char* ArchiveThread(char* to);
+ void FreeThreadResources();
// Garbage collection support.
- static void Iterate(v8::internal::ObjectVisitor* v);
+ void Iterate(v8::internal::ObjectVisitor* v);
static char* Iterate(v8::internal::ObjectVisitor* v, char* data);
diff --git a/src/apiutils.h b/src/apiutils.h
index 9683aa43..68579af1 100644
--- a/src/apiutils.h
+++ b/src/apiutils.h
@@ -31,11 +31,6 @@
namespace v8 {
class ImplementationUtilities {
public:
- static v8::Handle<v8::Primitive> Undefined();
- static v8::Handle<v8::Primitive> Null();
- static v8::Handle<v8::Boolean> True();
- static v8::Handle<v8::Boolean> False();
-
static int GetNameCount(ExtensionConfiguration* that) {
return that->name_count_;
}
@@ -68,8 +63,6 @@ class ImplementationUtilities {
// to access the HandleScope data.
typedef v8::HandleScope::Data HandleScopeData;
- static HandleScopeData* CurrentHandleScope();
-
#ifdef DEBUG
static void ZapHandleRange(internal::Object** begin, internal::Object** end);
#endif
diff --git a/src/arguments.h b/src/arguments.h
index 5cf8deaa..c80548f4 100644
--- a/src/arguments.h
+++ b/src/arguments.h
@@ -65,7 +65,6 @@ class Arguments BASE_EMBEDDED {
int length() const { return length_; }
Object** arguments() { return arguments_; }
-
private:
int length_;
Object** arguments_;
@@ -77,15 +76,16 @@ class Arguments BASE_EMBEDDED {
// can.
class CustomArguments : public Relocatable {
public:
- inline CustomArguments(Object* data,
+ inline CustomArguments(Isolate* isolate,
+ Object* data,
Object* self,
- JSObject* holder) {
+ JSObject* holder) : Relocatable(isolate) {
values_[2] = self;
values_[1] = holder;
values_[0] = data;
}
- inline CustomArguments() {
+ inline explicit CustomArguments(Isolate* isolate) : Relocatable(isolate) {
#ifdef DEBUG
for (size_t i = 0; i < ARRAY_SIZE(values_); i++) {
values_[i] = reinterpret_cast<Object*>(kZapValue);
@@ -99,6 +99,8 @@ class CustomArguments : public Relocatable {
Object* values_[3];
};
+#define RUNTIME_CALLING_CONVENTION Arguments args, Isolate* isolate
+#define RUNTIME_GET_ISOLATE ASSERT(isolate == Isolate::Current())
} } // namespace v8::internal
diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h
index 3b811021..bd76d9ab 100644
--- a/src/arm/assembler-arm-inl.h
+++ b/src/arm/assembler-arm-inl.h
@@ -203,11 +203,12 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
visitor->VisitExternalReference(target_reference_address());
#ifdef ENABLE_DEBUGGER_SUPPORT
- } else if (Debug::has_break_points() &&
- ((RelocInfo::IsJSReturn(mode) &&
+ // TODO(isolates): Get a cached isolate below.
+ } else if (((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
- IsPatchedDebugBreakSlotSequence()))) {
+ IsPatchedDebugBreakSlotSequence())) &&
+ Isolate::Current()->debug()->has_break_points()) {
visitor->VisitDebugTarget(this);
#endif
} else if (mode == RelocInfo::RUNTIME_ENTRY) {
@@ -217,10 +218,10 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
template<typename StaticVisitor>
-void RelocInfo::Visit() {
+void RelocInfo::Visit(Heap* heap) {
RelocInfo::Mode mode = rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
- StaticVisitor::VisitPointer(target_object_address());
+ StaticVisitor::VisitPointer(heap, target_object_address());
} else if (RelocInfo::IsCodeTarget(mode)) {
StaticVisitor::VisitCodeTarget(this);
} else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
@@ -228,7 +229,7 @@ void RelocInfo::Visit() {
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
StaticVisitor::VisitExternalReference(target_reference_address());
#ifdef ENABLE_DEBUGGER_SUPPORT
- } else if (Debug::has_break_points() &&
+ } else if (heap->isolate()->debug()->has_break_points() &&
((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index c91d4ba2..be34df9c 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -44,11 +44,11 @@
namespace v8 {
namespace internal {
-// Safe default is no features.
-unsigned CpuFeatures::supported_ = 0;
-unsigned CpuFeatures::enabled_ = 0;
-unsigned CpuFeatures::found_by_runtime_probing_ = 0;
-
+CpuFeatures::CpuFeatures()
+ : supported_(0),
+ enabled_(0),
+ found_by_runtime_probing_(0) {
+}
#ifdef __arm__
static uint64_t CpuFeaturesImpliedByCompiler() {
@@ -148,7 +148,7 @@ Operand::Operand(Handle<Object> handle) {
rm_ = no_reg;
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
- ASSERT(!Heap::InNewSpace(obj));
+ ASSERT(!HEAP->InNewSpace(obj));
if (obj->IsHeapObject()) {
imm32_ = reinterpret_cast<intptr_t>(handle.location());
rmode_ = RelocInfo::EMBEDDED_OBJECT;
@@ -266,21 +266,22 @@ const Instr kLdrStrOffsetMask = 0x00000fff;
// Spare buffer.
static const int kMinimalBufferSize = 4*KB;
-static byte* spare_buffer_ = NULL;
Assembler::Assembler(void* buffer, int buffer_size)
- : positions_recorder_(this),
- allow_peephole_optimization_(false) {
+ : AssemblerBase(Isolate::Current()),
+ positions_recorder_(this),
+ allow_peephole_optimization_(false),
+ emit_debug_code_(FLAG_debug_code) {
allow_peephole_optimization_ = FLAG_peephole_optimization;
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
buffer_size = kMinimalBufferSize;
- if (spare_buffer_ != NULL) {
- buffer = spare_buffer_;
- spare_buffer_ = NULL;
+ if (isolate()->assembler_spare_buffer() != NULL) {
+ buffer = isolate()->assembler_spare_buffer();
+ isolate()->set_assembler_spare_buffer(NULL);
}
}
if (buffer == NULL) {
@@ -315,8 +316,9 @@ Assembler::Assembler(void* buffer, int buffer_size)
Assembler::~Assembler() {
ASSERT(const_pool_blocked_nesting_ == 0);
if (own_buffer_) {
- if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
- spare_buffer_ = buffer_;
+ if (isolate()->assembler_spare_buffer() == NULL &&
+ buffer_size_ == kMinimalBufferSize) {
+ isolate()->set_assembler_spare_buffer(buffer_);
} else {
DeleteArray(buffer_);
}
@@ -713,7 +715,7 @@ static bool fits_shifter(uint32_t imm32,
*instr ^= kMovMvnFlip;
return true;
} else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) {
- if (CpuFeatures::IsSupported(ARMv7)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
if (imm32 < 0x10000) {
*instr ^= kMovwLeaveCCFlip;
*instr |= EncodeMovwImmediate(imm32);
@@ -767,11 +769,36 @@ bool Operand::must_use_constant_pool() const {
}
-bool Operand::is_single_instruction() const {
+bool Operand::is_single_instruction(Instr instr) const {
if (rm_.is_valid()) return true;
- if (must_use_constant_pool()) return false;
uint32_t dummy1, dummy2;
- return fits_shifter(imm32_, &dummy1, &dummy2, NULL);
+ if (must_use_constant_pool() ||
+ !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) {
+ // The immediate operand cannot be encoded as a shifter operand, or use of
+ // constant pool is required. For a mov instruction not setting the
+ // condition code additional instruction conventions can be used.
+ if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
+ if (must_use_constant_pool() ||
+ !Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
+ // mov instruction will be an ldr from constant pool (one instruction).
+ return true;
+ } else {
+ // mov instruction will be a mov or movw followed by movt (two
+ // instructions).
+ return false;
+ }
+ } else {
+ // If this is not a mov or mvn instruction there will always an additional
+ // instructions - either mov or ldr. The mov might actually be two
+ // instructions mov or movw followed by movt so including the actual
+ // instruction two or three instructions will be generated.
+ return false;
+ }
+ } else {
+ // No use of constant pool and the immediate operand can be encoded as a
+ // shifter operand.
+ return true;
+ }
}
@@ -794,7 +821,8 @@ void Assembler::addrmod1(Instr instr,
CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
Condition cond = Instruction::ConditionField(instr);
if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
- if (x.must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) {
+ if (x.must_use_constant_pool() ||
+ !isolate()->cpu_features()->IsSupported(ARMv7)) {
RecordRelocInfo(x.rmode_, x.imm32_);
ldr(rd, MemOperand(pc, 0), cond);
} else {
@@ -1237,7 +1265,7 @@ void Assembler::usat(Register dst,
const Operand& src,
Condition cond) {
// v6 and above.
- ASSERT(CpuFeatures::IsSupported(ARMv7));
+ ASSERT(isolate()->cpu_features()->IsSupported(ARMv7));
ASSERT(!dst.is(pc) && !src.rm_.is(pc));
ASSERT((satpos >= 0) && (satpos <= 31));
ASSERT((src.shift_op_ == ASR) || (src.shift_op_ == LSL));
@@ -1265,7 +1293,7 @@ void Assembler::ubfx(Register dst,
int width,
Condition cond) {
// v7 and above.
- ASSERT(CpuFeatures::IsSupported(ARMv7));
+ ASSERT(isolate()->cpu_features()->IsSupported(ARMv7));
ASSERT(!dst.is(pc) && !src.is(pc));
ASSERT((lsb >= 0) && (lsb <= 31));
ASSERT((width >= 1) && (width <= (32 - lsb)));
@@ -1285,7 +1313,7 @@ void Assembler::sbfx(Register dst,
int width,
Condition cond) {
// v7 and above.
- ASSERT(CpuFeatures::IsSupported(ARMv7));
+ ASSERT(isolate()->cpu_features()->IsSupported(ARMv7));
ASSERT(!dst.is(pc) && !src.is(pc));
ASSERT((lsb >= 0) && (lsb <= 31));
ASSERT((width >= 1) && (width <= (32 - lsb)));
@@ -1300,7 +1328,7 @@ void Assembler::sbfx(Register dst,
// bfc dst, #lsb, #width
void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
// v7 and above.
- ASSERT(CpuFeatures::IsSupported(ARMv7));
+ ASSERT(isolate()->cpu_features()->IsSupported(ARMv7));
ASSERT(!dst.is(pc));
ASSERT((lsb >= 0) && (lsb <= 31));
ASSERT((width >= 1) && (width <= (32 - lsb)));
@@ -1319,7 +1347,7 @@ void Assembler::bfi(Register dst,
int width,
Condition cond) {
// v7 and above.
- ASSERT(CpuFeatures::IsSupported(ARMv7));
+ ASSERT(isolate()->cpu_features()->IsSupported(ARMv7));
ASSERT(!dst.is(pc) && !src.is(pc));
ASSERT((lsb >= 0) && (lsb <= 31));
ASSERT((width >= 1) && (width <= (32 - lsb)));
@@ -1591,7 +1619,7 @@ void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
void Assembler::ldrd(Register dst1, Register dst2,
const MemOperand& src, Condition cond) {
- ASSERT(CpuFeatures::IsEnabled(ARMv7));
+ ASSERT(isolate()->cpu_features()->IsEnabled(ARMv7));
ASSERT(src.rm().is(no_reg));
ASSERT(!dst1.is(lr)); // r14.
ASSERT_EQ(0, dst1.code() % 2);
@@ -1606,7 +1634,7 @@ void Assembler::strd(Register src1, Register src2,
ASSERT(!src1.is(lr)); // r14.
ASSERT_EQ(0, src1.code() % 2);
ASSERT_EQ(src1.code() + 1, src2.code());
- ASSERT(CpuFeatures::IsEnabled(ARMv7));
+ ASSERT(isolate()->cpu_features()->IsEnabled(ARMv7));
addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
}
@@ -1842,7 +1870,7 @@ void Assembler::vldr(const DwVfpRegister dst,
// Instruction details available in ARM DDI 0406A, A8-628.
// cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
// Vdst(15-12) | 1011(11-8) | offset
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
int u = 1;
if (offset < 0) {
offset = -offset;
@@ -1884,7 +1912,7 @@ void Assembler::vldr(const SwVfpRegister dst,
// Instruction details available in ARM DDI 0406A, A8-628.
// cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
// Vdst(15-12) | 1010(11-8) | offset
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
int u = 1;
if (offset < 0) {
offset = -offset;
@@ -1928,7 +1956,7 @@ void Assembler::vstr(const DwVfpRegister src,
// Instruction details available in ARM DDI 0406A, A8-786.
// cond(31-28) | 1101(27-24)| U000(23-20) | | Rbase(19-16) |
// Vsrc(15-12) | 1011(11-8) | (offset/4)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
int u = 1;
if (offset < 0) {
offset = -offset;
@@ -1969,7 +1997,7 @@ void Assembler::vstr(const SwVfpRegister src,
// Instruction details available in ARM DDI 0406A, A8-786.
// cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
// Vdst(15-12) | 1010(11-8) | (offset/4)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
int u = 1;
if (offset < 0) {
offset = -offset;
@@ -2015,7 +2043,7 @@ static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
// Only works for little endian floating point formats.
// We don't support VFP on the mixed endian floating point platform.
static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(Isolate::Current()->cpu_features()->IsEnabled(VFP3));
// VMOV can accept an immediate of the form:
//
@@ -2068,7 +2096,7 @@ void Assembler::vmov(const DwVfpRegister dst,
const Condition cond) {
// Dd = immediate
// Instruction details available in ARM DDI 0406B, A8-640.
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
uint32_t enc;
if (FitsVMOVDoubleImmediate(imm, &enc)) {
@@ -2105,7 +2133,7 @@ void Assembler::vmov(const SwVfpRegister dst,
const Condition cond) {
// Sd = Sm
// Instruction details available in ARM DDI 0406B, A8-642.
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
int sd, d, sm, m;
dst.split_code(&sd, &d);
src.split_code(&sm, &m);
@@ -2118,7 +2146,7 @@ void Assembler::vmov(const DwVfpRegister dst,
const Condition cond) {
// Dd = Dm
// Instruction details available in ARM DDI 0406B, A8-642.
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0xB*B20 |
dst.code()*B12 | 0x5*B9 | B8 | B6 | src.code());
}
@@ -2132,7 +2160,7 @@ void Assembler::vmov(const DwVfpRegister dst,
// Instruction details available in ARM DDI 0406A, A8-646.
// cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
// Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
ASSERT(!src1.is(pc) && !src2.is(pc));
emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
src1.code()*B12 | 0xB*B8 | B4 | dst.code());
@@ -2147,7 +2175,7 @@ void Assembler::vmov(const Register dst1,
// Instruction details available in ARM DDI 0406A, A8-646.
// cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
// Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
ASSERT(!dst1.is(pc) && !dst2.is(pc));
emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
dst1.code()*B12 | 0xB*B8 | B4 | src.code());
@@ -2161,7 +2189,7 @@ void Assembler::vmov(const SwVfpRegister dst,
// Instruction details available in ARM DDI 0406A, A8-642.
// cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
// Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
ASSERT(!src.is(pc));
int sn, n;
dst.split_code(&sn, &n);
@@ -2176,7 +2204,7 @@ void Assembler::vmov(const Register dst,
// Instruction details available in ARM DDI 0406A, A8-642.
// cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
// Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
ASSERT(!dst.is(pc));
int sn, n;
src.split_code(&sn, &n);
@@ -2301,7 +2329,7 @@ void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
const SwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
}
@@ -2310,7 +2338,7 @@ void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
const SwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
}
@@ -2319,7 +2347,7 @@ void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
const SwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
}
@@ -2328,7 +2356,7 @@ void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
}
@@ -2337,7 +2365,7 @@ void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
}
@@ -2346,7 +2374,7 @@ void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
const SwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
}
@@ -2355,11 +2383,19 @@ void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
VFPConversionMode mode,
const Condition cond) {
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
}
+void Assembler::vneg(const DwVfpRegister dst,
+ const DwVfpRegister src,
+ const Condition cond) {
+ emit(cond | 0xE*B24 | 0xB*B20 | B16 | dst.code()*B12 |
+ 0x5*B9 | B8 | B6 | src.code());
+}
+
+
void Assembler::vabs(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond) {
@@ -2377,7 +2413,7 @@ void Assembler::vadd(const DwVfpRegister dst,
// Instruction details available in ARM DDI 0406A, A8-536.
// cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
// Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
dst.code()*B12 | 0x5*B9 | B8 | src2.code());
}
@@ -2392,7 +2428,7 @@ void Assembler::vsub(const DwVfpRegister dst,
// Instruction details available in ARM DDI 0406A, A8-784.
// cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
// Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 1(6) | M=?(5) | 0(4) | Vm(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
dst.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
}
@@ -2407,7 +2443,7 @@ void Assembler::vmul(const DwVfpRegister dst,
// Instruction details available in ARM DDI 0406A, A8-784.
// cond(31-28) | 11100(27-23)| D=?(22) | 10(21-20) | Vn(19-16) |
// Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0x2*B20 | src1.code()*B16 |
dst.code()*B12 | 0x5*B9 | B8 | src2.code());
}
@@ -2422,7 +2458,7 @@ void Assembler::vdiv(const DwVfpRegister dst,
// Instruction details available in ARM DDI 0406A, A8-584.
// cond(31-28) | 11101(27-23)| D=?(22) | 00(21-20) | Vn(19-16) |
// Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=? | 0(6) | M=?(5) | 0(4) | Vm(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(cond | 0xE*B24 | B23 | src1.code()*B16 |
dst.code()*B12 | 0x5*B9 | B8 | src2.code());
}
@@ -2435,7 +2471,7 @@ void Assembler::vcmp(const DwVfpRegister src1,
// Instruction details available in ARM DDI 0406A, A8-570.
// cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) |
// Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | Vm(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 |
src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
}
@@ -2448,7 +2484,7 @@ void Assembler::vcmp(const DwVfpRegister src1,
// Instruction details available in ARM DDI 0406A, A8-570.
// cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0101 (19-16) |
// Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | 0000(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
ASSERT(src2 == 0.0);
emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
src1.code()*B12 | 0x5*B9 | B8 | B6);
@@ -2459,7 +2495,7 @@ void Assembler::vmsr(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
// Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0xE*B20 | B16 |
dst.code()*B12 | 0xA*B8 | B4);
}
@@ -2469,7 +2505,7 @@ void Assembler::vmrs(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
// Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0xF*B20 | B16 |
dst.code()*B12 | 0xA*B8 | B4);
}
@@ -2480,7 +2516,7 @@ void Assembler::vsqrt(const DwVfpRegister dst,
const Condition cond) {
// cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0001 (19-16) |
// Vd(15-12) | 101(11-9) | sz(8)=1 | 11 (7-6) | M(5)=? | 0(4) | Vm(3-0)
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(VFP3));
emit(cond | 0xE*B24 | B23 | 0x3*B20 | B16 |
dst.code()*B12 | 0x5*B9 | B8 | 3*B6 | src.code());
}
@@ -2633,7 +2669,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Serializer::TooLateToEnableNow();
}
#endif
- if (!Serializer::enabled() && !FLAG_debug_code) {
+ if (!Serializer::enabled() && !emit_debug_code()) {
return;
}
}
@@ -2711,8 +2747,8 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
RecordComment("[ Constant Pool");
// Put down constant pool marker "Undefined instruction" as specified by
- // A3.1 Instruction set encoding.
- emit(0x03000000 | num_prinfo_);
+ // A5.6 (ARMv7) Instruction set encoding.
+ emit(kConstantPoolMarker | num_prinfo_);
// Emit constant pool entries.
for (int i = 0; i < num_prinfo_; i++) {
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index f5eb5075..91e6244b 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -389,8 +389,11 @@ class Operand BASE_EMBEDDED {
INLINE(bool is_reg() const);
// Return true if this operand fits in one instruction so that no
- // 2-instruction solution with a load into the ip register is necessary.
- bool is_single_instruction() const;
+ // 2-instruction solution with a load into the ip register is necessary. If
+ // the instruction this operand is used for is a MOV or MVN instruction the
+ // actual instruction to use is required for this calculation. For other
+ // instructions instr is ignored.
+ bool is_single_instruction(Instr instr = 0) const;
bool must_use_constant_pool() const;
inline int32_t immediate() const {
@@ -465,20 +468,20 @@ class MemOperand BASE_EMBEDDED {
// CpuFeatures keeps track of which features are supported by the target CPU.
// Supported features must be enabled by a Scope before use.
-class CpuFeatures : public AllStatic {
+class CpuFeatures {
public:
// Detect features of the target CPU. Set safe defaults if the serializer
// is enabled (snapshots must be portable).
- static void Probe(bool portable);
+ void Probe(bool portable);
// Check whether a feature is supported by the target CPU.
- static bool IsSupported(CpuFeature f) {
+ bool IsSupported(CpuFeature f) const {
if (f == VFP3 && !FLAG_enable_vfp3) return false;
return (supported_ & (1u << f)) != 0;
}
// Check whether a feature is currently enabled.
- static bool IsEnabled(CpuFeature f) {
+ bool IsEnabled(CpuFeature f) const {
return (enabled_ & (1u << f)) != 0;
}
@@ -486,16 +489,23 @@ class CpuFeatures : public AllStatic {
class Scope BASE_EMBEDDED {
#ifdef DEBUG
public:
- explicit Scope(CpuFeature f) {
- ASSERT(CpuFeatures::IsSupported(f));
+ explicit Scope(CpuFeature f)
+ : cpu_features_(Isolate::Current()->cpu_features()),
+ isolate_(Isolate::Current()) {
+ ASSERT(cpu_features_->IsSupported(f));
ASSERT(!Serializer::enabled() ||
- (found_by_runtime_probing_ & (1u << f)) == 0);
- old_enabled_ = CpuFeatures::enabled_;
- CpuFeatures::enabled_ |= 1u << f;
+ (cpu_features_->found_by_runtime_probing_ & (1u << f)) == 0);
+ old_enabled_ = cpu_features_->enabled_;
+ cpu_features_->enabled_ |= 1u << f;
+ }
+ ~Scope() {
+ ASSERT_EQ(Isolate::Current(), isolate_);
+ cpu_features_->enabled_ = old_enabled_;
}
- ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
private:
unsigned old_enabled_;
+ CpuFeatures* cpu_features_;
+ Isolate* isolate_;
#else
public:
explicit Scope(CpuFeature f) {}
@@ -503,9 +513,15 @@ class CpuFeatures : public AllStatic {
};
private:
- static unsigned supported_;
- static unsigned enabled_;
- static unsigned found_by_runtime_probing_;
+ CpuFeatures();
+
+ unsigned supported_;
+ unsigned enabled_;
+ unsigned found_by_runtime_probing_;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
};
@@ -533,7 +549,7 @@ extern const Instr kAndBicFlip;
-class Assembler : public Malloced {
+class Assembler : public AssemblerBase {
public:
// Create an assembler. Instructions and relocation information are emitted
// into a buffer, with the instructions starting from the beginning and the
@@ -551,6 +567,9 @@ class Assembler : public Malloced {
Assembler(void* buffer, int buffer_size);
~Assembler();
+ // Overrides the default provided by FLAG_debug_code.
+ void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
+
// GetCode emits any pending (non-emitted) code and fills the descriptor
// desc. GetCode() is idempotent; it returns the same result if no other
// Assembler functions are invoked in between GetCode() calls.
@@ -989,6 +1008,9 @@ class Assembler : public Malloced {
VFPConversionMode mode = kDefaultRoundToZero,
const Condition cond = al);
+ void vneg(const DwVfpRegister dst,
+ const DwVfpRegister src,
+ const Condition cond = al);
void vabs(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond = al);
@@ -1148,6 +1170,8 @@ class Assembler : public Malloced {
void CheckConstPool(bool force_emit, bool require_jump);
protected:
+ bool emit_debug_code() const { return emit_debug_code_; }
+
int buffer_space() const { return reloc_info_writer.pos() - pc_; }
// Read/patch instructions
@@ -1276,6 +1300,7 @@ class Assembler : public Malloced {
PositionsRecorder positions_recorder_;
bool allow_peephole_optimization_;
+ bool emit_debug_code_;
friend class PositionsRecorder;
friend class EnsureSpace;
};
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 961d3ce5..f401cfd6 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -68,7 +68,7 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm,
// JumpToExternalReference expects r0 to contain the number of arguments
// including the receiver and the extra arguments.
__ add(r0, r0, Operand(num_extra_args + 1));
- __ JumpToExternalReference(ExternalReference(id));
+ __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
}
@@ -310,6 +310,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// construct call and normal call.
static void ArrayNativeCode(MacroAssembler* masm,
Label* call_generic_code) {
+ Counters* counters = masm->isolate()->counters();
Label argc_one_or_more, argc_two_or_more;
// Check for array construction with zero arguments or one.
@@ -325,7 +326,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
r5,
JSArray::kPreallocatedArrayElements,
call_generic_code);
- __ IncrementCounter(&Counters::array_function_native, 1, r3, r4);
+ __ IncrementCounter(counters->array_function_native(), 1, r3, r4);
// Setup return value, remove receiver from stack and return.
__ mov(r0, r2);
__ add(sp, sp, Operand(kPointerSize));
@@ -361,7 +362,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
r7,
true,
call_generic_code);
- __ IncrementCounter(&Counters::array_function_native, 1, r2, r4);
+ __ IncrementCounter(counters->array_function_native(), 1, r2, r4);
// Setup return value, remove receiver and argument from stack and return.
__ mov(r0, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
@@ -385,7 +386,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
r7,
false,
call_generic_code);
- __ IncrementCounter(&Counters::array_function_native, 1, r2, r6);
+ __ IncrementCounter(counters->array_function_native(), 1, r2, r6);
// Fill arguments as array elements. Copy from the top of the stack (last
// element) to the array backing store filling it backwards. Note:
@@ -442,8 +443,9 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
// Jump to the generic array code if the specialized code cannot handle
// the construction.
__ bind(&generic_array_code);
- Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
- Handle<Code> array_code(code);
+
+ Handle<Code> array_code =
+ masm->isolate()->builtins()->ArrayCodeGeneric();
__ Jump(array_code, RelocInfo::CODE_TARGET);
}
@@ -474,8 +476,8 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
// Jump to the generic construct code in case the specialized code cannot
// handle the construction.
__ bind(&generic_constructor);
- Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
- Handle<Code> generic_construct_stub(code);
+ Handle<Code> generic_construct_stub =
+ masm->isolate()->builtins()->JSConstructStubGeneric();
__ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
}
@@ -488,7 +490,8 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
// -- sp[argc * 4] : receiver
// -----------------------------------
- __ IncrementCounter(&Counters::string_ctor_calls, 1, r2, r3);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->string_ctor_calls(), 1, r2, r3);
Register function = r1;
if (FLAG_debug_code) {
@@ -518,7 +521,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
r5, // Scratch.
false, // Is it a Smi?
&not_cached);
- __ IncrementCounter(&Counters::string_ctor_cached_number, 1, r3, r4);
+ __ IncrementCounter(counters->string_ctor_cached_number(), 1, r3, r4);
__ bind(&argument_is_string);
// ----------- S t a t e -------------
@@ -572,13 +575,13 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
__ tst(r3, Operand(kIsNotStringMask));
__ b(ne, &convert_argument);
__ mov(argument, r0);
- __ IncrementCounter(&Counters::string_ctor_conversions, 1, r3, r4);
+ __ IncrementCounter(counters->string_ctor_conversions(), 1, r3, r4);
__ b(&argument_is_string);
// Invoke the conversion builtin and put the result into r2.
__ bind(&convert_argument);
__ push(function); // Preserve the function.
- __ IncrementCounter(&Counters::string_ctor_conversions, 1, r3, r4);
+ __ IncrementCounter(counters->string_ctor_conversions(), 1, r3, r4);
__ EnterInternalFrame();
__ push(r0);
__ InvokeBuiltin(Builtins::TO_STRING, CALL_JS);
@@ -597,7 +600,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// At this point the argument is already a string. Call runtime to
// create a string wrapper.
__ bind(&gc_required);
- __ IncrementCounter(&Counters::string_ctor_gc_required, 1, r3, r4);
+ __ IncrementCounter(counters->string_ctor_gc_required(), 1, r3, r4);
__ EnterInternalFrame();
__ push(argument);
__ CallRuntime(Runtime::kNewStringWrapper, 1);
@@ -633,7 +636,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// Set expected number of arguments to zero (not changing r0).
__ mov(r2, Operand(0, RelocInfo::NONE));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
- __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
}
@@ -644,6 +647,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Should never count constructions for api objects.
ASSERT(!is_api_function || !count_constructions);
+ Isolate* isolate = masm->isolate();
+
// Enter a construct frame.
__ EnterConstructFrame();
@@ -659,7 +664,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Label undo_allocation;
#ifdef ENABLE_DEBUGGER_SUPPORT
ExternalReference debug_step_in_fp =
- ExternalReference::debug_step_in_fp_address();
+ ExternalReference::debug_step_in_fp_address(isolate);
__ mov(r2, Operand(debug_step_in_fp));
__ ldr(r2, MemOperand(r2));
__ tst(r2, r2);
@@ -905,8 +910,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// r1: constructor function
if (is_api_function) {
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
- Handle<Code> code = Handle<Code>(
- Builtins::builtin(Builtins::HandleApiCallConstruct));
+ Handle<Code> code =
+ masm->isolate()->builtins()->HandleApiCallConstruct();
ParameterCount expected(0);
__ InvokeCode(code, expected, expected,
RelocInfo::CODE_TARGET, CALL_FUNCTION);
@@ -963,7 +968,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ LeaveConstructFrame();
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
__ add(sp, sp, Operand(kPointerSize));
- __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
+ __ IncrementCounter(isolate->counters()->constructed_objects(), 1, r1, r2);
__ Jump(lr);
}
@@ -1003,7 +1008,8 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// Set up the roots register.
- ExternalReference roots_address = ExternalReference::roots_address();
+ ExternalReference roots_address =
+ ExternalReference::roots_address(masm->isolate());
__ mov(r10, Operand(roots_address));
// Push the function and the receiver onto the stack.
@@ -1039,7 +1045,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// Invoke the code and pass argc as r0.
__ mov(r0, Operand(r3));
if (is_construct) {
- __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
+ __ Call(masm->isolate()->builtins()->JSConstructCall(),
RelocInfo::CODE_TARGET);
} else {
ParameterCount actual(r0);
@@ -1169,7 +1175,7 @@ void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
// Probe the CPU to set the supported features, because this builtin
// may be called before the initialization performs CPU setup.
- CpuFeatures::Probe(false);
+ masm->isolate()->cpu_features()->Probe(false);
// Lookup the function in the JavaScript frame and push it as an
// argument to the on-stack replacement function.
@@ -1332,8 +1338,8 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// Expected number of arguments is 0 for CALL_NON_FUNCTION.
__ mov(r2, Operand(0, RelocInfo::NONE));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
- __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
- RelocInfo::CODE_TARGET);
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
__ bind(&function);
}
@@ -1348,8 +1354,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ mov(r2, Operand(r2, ASR, kSmiTagSize));
__ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
__ cmp(r2, r0); // Check formal and actual parameter counts.
- __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
- RelocInfo::CODE_TARGET, ne);
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET,
+ ne);
ParameterCount expected(0);
__ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 1c6d709f..441adfe3 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -91,11 +91,15 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
&gc,
TAG_OBJECT);
+ int map_index = strict_mode_ == kStrictMode
+ ? Context::STRICT_MODE_FUNCTION_MAP_INDEX
+ : Context::FUNCTION_MAP_INDEX;
+
// Compute the function map in the current global context and set that
// as the map of the allocated object.
__ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset));
- __ ldr(r2, MemOperand(r2, Context::SlotOffset(Context::FUNCTION_MAP_INDEX)));
+ __ ldr(r2, MemOperand(r2, Context::SlotOffset(map_index)));
__ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
// Initialize the rest of the function. We don't have to update the
@@ -397,20 +401,18 @@ class FloatingPointHelper : public AllStatic {
Register scratch2,
Label* not_number);
- // Loads the number from object into dst as a 32-bit integer if possible. If
- // the object cannot be converted to a 32-bit integer control continues at
- // the label not_int32. If VFP is supported double_scratch is used
- // but not scratch2.
- // Floating point value in the 32-bit integer range will be rounded
- // to an integer.
- static void LoadNumberAsInteger(MacroAssembler* masm,
- Register object,
- Register dst,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- DwVfpRegister double_scratch,
- Label* not_int32);
+ // Convert the smi or heap number in object to an int32 using the rules
+ // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
+ // and brought into the range -2^31 .. +2^31 - 1.
+ static void ConvertNumberToInt32(MacroAssembler* masm,
+ Register object,
+ Register dst,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ DwVfpRegister double_scratch,
+ Label* not_int32);
// Load the number from object into double_dst in the double format.
// Control will jump to not_int32 if the value cannot be exactly represented
@@ -500,7 +502,7 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
FloatingPointHelper::Destination destination,
Register scratch1,
Register scratch2) {
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
__ vmov(d7.high(), scratch1);
@@ -568,7 +570,8 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
// Handle loading a double from a heap number.
- if (CpuFeatures::IsSupported(VFP3) && destination == kVFPRegisters) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3) &&
+ destination == kVFPRegisters) {
CpuFeatures::Scope scope(VFP3);
// Load the double from tagged HeapNumber to double register.
__ sub(scratch1, object, Operand(kHeapObjectTag));
@@ -582,7 +585,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
// Handle loading a double from a smi.
__ bind(&is_smi);
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Convert smi to double using VFP instructions.
__ SmiUntag(scratch1, object);
@@ -606,27 +609,46 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
}
-void FloatingPointHelper::LoadNumberAsInteger(MacroAssembler* masm,
- Register object,
- Register dst,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- DwVfpRegister double_scratch,
- Label* not_int32) {
+void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm,
+ Register object,
+ Register dst,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ DwVfpRegister double_scratch,
+ Label* not_number) {
if (FLAG_debug_code) {
__ AbortIfNotRootValue(heap_number_map,
Heap::kHeapNumberMapRootIndex,
"HeapNumberMap register clobbered.");
}
- Label is_smi, done;
+ Label is_smi;
+ Label done;
+ Label not_in_int32_range;
+
__ JumpIfSmi(object, &is_smi);
__ ldr(scratch1, FieldMemOperand(object, HeapNumber::kMapOffset));
__ cmp(scratch1, heap_number_map);
- __ b(ne, not_int32);
- __ ConvertToInt32(
- object, dst, scratch1, scratch2, double_scratch, not_int32);
+ __ b(ne, not_number);
+ __ ConvertToInt32(object,
+ dst,
+ scratch1,
+ scratch2,
+ double_scratch,
+ &not_in_int32_range);
__ jmp(&done);
+
+ __ bind(&not_in_int32_range);
+ __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
+ __ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+
+ __ EmitOutOfInt32RangeTruncate(dst,
+ scratch1,
+ scratch2,
+ scratch3);
+ __ jmp(&done);
+
__ bind(&is_smi);
__ SmiUntag(dst, object);
__ bind(&done);
@@ -654,7 +676,7 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
__ JumpIfNotSmi(object, &obj_is_not_smi);
__ SmiUntag(scratch1, object);
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ vmov(single_scratch, scratch1);
__ vcvt_f64_s32(double_dst, single_scratch);
@@ -722,7 +744,7 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
// Load the number.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Load the double value.
__ sub(scratch1, object, Operand(kHeapObjectTag));
@@ -796,7 +818,7 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
// Object is a heap number.
// Convert the floating point value to a 32-bit integer.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
SwVfpRegister single_scratch = double_scratch.low();
// Load the double value.
@@ -927,7 +949,8 @@ void FloatingPointHelper::CallCCodeForDoubleOperation(
__ push(lr);
__ PrepareCallCFunction(4, scratch); // Two doubles are 4 arguments.
// Call C routine that may not cause GC or other trouble.
- __ CallCFunction(ExternalReference::double_fp_operation(op), 4);
+ __ CallCFunction(ExternalReference::double_fp_operation(op, masm->isolate()),
+ 4);
// Store answer in the overwritable heap number.
#if !defined(USE_ARM_EABI)
// Double returned in fp coprocessor register 0 and 1, encoded as
@@ -1007,7 +1030,7 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
// The two objects are identical. If we know that one of them isn't NaN then
// we now know they test equal.
if (cond != eq || !never_nan_nan) {
- // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
+ // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
// so we do the second best thing - test it ourselves.
// They are both equal and they are not both Smis so both of them are not
// Smis. If it's not a heap number, then return equal.
@@ -1130,7 +1153,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
}
// Lhs is a smi, rhs is a number.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
// Convert lhs to a double in d7.
CpuFeatures::Scope scope(VFP3);
__ SmiToDoubleVFPRegister(lhs, d7, r7, s15);
@@ -1170,7 +1193,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
}
// Rhs is a smi, lhs is a heap number.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Load the double from lhs, tagged HeapNumber r1, to d7.
__ sub(r7, lhs, Operand(kHeapObjectTag));
@@ -1282,7 +1305,7 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm,
// Call C routine that may not cause GC or other trouble.
__ push(lr);
__ PrepareCallCFunction(4, r5); // Two doubles count as 4 arguments.
- __ CallCFunction(ExternalReference::compare_doubles(), 4);
+ __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()), 4);
__ pop(pc); // Return.
}
}
@@ -1350,7 +1373,7 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
// Both are heap numbers. Load them up then jump to the code we have
// for that.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ sub(r7, rhs, Operand(kHeapObjectTag));
__ vldr(d6, r7, HeapNumber::kValueOffset);
@@ -1435,11 +1458,12 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
// number string cache for smis is just the smi value, and the hash for
// doubles is the xor of the upper and lower words. See
// Heap::GetNumberStringCache.
+ Isolate* isolate = masm->isolate();
Label is_smi;
Label load_result_from_cache;
if (!object_is_smi) {
__ JumpIfSmi(object, &is_smi);
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (isolate->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ CheckMap(object,
scratch1,
@@ -1496,7 +1520,7 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
__ bind(&load_result_from_cache);
__ ldr(result,
FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
- __ IncrementCounter(&Counters::number_to_string_native,
+ __ IncrementCounter(isolate->counters()->number_to_string_native(),
1,
scratch1,
scratch2);
@@ -1572,7 +1596,8 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ bind(&both_loaded_as_doubles);
// The arguments have been converted to doubles and stored in d6 and d7, if
// VFP3 is supported, or in r0, r1, r2, and r3.
- if (CpuFeatures::IsSupported(VFP3)) {
+ Isolate* isolate = masm->isolate();
+ if (isolate->cpu_features()->IsSupported(VFP3)) {
__ bind(&lhs_not_nan);
CpuFeatures::Scope scope(VFP3);
Label no_nan;
@@ -1642,7 +1667,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow);
- __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3);
+ __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3);
StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
lhs_,
rhs_,
@@ -1682,7 +1707,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
// The stub returns zero for false, and a non-zero value for true.
void ToBooleanStub::Generate(MacroAssembler* masm) {
// This stub uses VFP3 instructions.
- ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(Isolate::Current()->cpu_features()->IsEnabled(VFP3));
Label false_result;
Label not_heap_number;
@@ -1768,7 +1793,9 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
Register rhs,
const Builtins::JavaScript& builtin) {
Label slow, slow_reverse, do_the_call;
- bool use_fp_registers = CpuFeatures::IsSupported(VFP3) && Token::MOD != op_;
+ bool use_fp_registers =
+ Isolate::Current()->cpu_features()->IsSupported(VFP3) &&
+ Token::MOD != op_;
ASSERT((lhs.is(r0) && rhs.is(r1)) || (lhs.is(r1) && rhs.is(r0)));
Register heap_number_map = r6;
@@ -1784,7 +1811,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
// If we have floating point hardware, inline ADD, SUB, MUL, and DIV,
// using registers d7 and d6 for the double values.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ mov(r7, Operand(rhs, ASR, kSmiTagSize));
__ vmov(s15, r7);
@@ -1880,7 +1907,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
__ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
}
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Convert smi in r0 to double in d7.
__ mov(r7, Operand(r0, ASR, kSmiTagSize));
@@ -1937,7 +1964,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
__ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
}
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Convert smi in r1 to double in d6.
__ mov(r7, Operand(r1, ASR, kSmiTagSize));
@@ -1994,7 +2021,8 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
__ PrepareCallCFunction(4, r4); // Two doubles count as 4 arguments.
// Call C routine that may not cause GC or other trouble. r5 is callee
// save.
- __ CallCFunction(ExternalReference::double_fp_operation(op_), 4);
+ __ CallCFunction(
+ ExternalReference::double_fp_operation(op_, masm->isolate()), 4);
// Store answer in the overwritable heap number.
#if !defined(USE_ARM_EABI)
// Double returned in fp coprocessor register 0 and 1, encoded as
@@ -2149,7 +2177,7 @@ void GenericBinaryOpStub::HandleNonSmiBitwiseOp(MacroAssembler* masm,
// The code below for writing into heap numbers isn't capable of writing
// the register as an unsigned int so we go to slow case if we hit this
// case.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
__ b(mi, &result_not_a_smi);
} else {
__ b(mi, &slow);
@@ -2197,7 +2225,7 @@ void GenericBinaryOpStub::HandleNonSmiBitwiseOp(MacroAssembler* masm,
// result.
__ mov(r0, Operand(r5));
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
// Convert the int32 in r2 to the heap number in r0. r3 is corrupted.
CpuFeatures::Scope scope(VFP3);
__ vmov(s0, r2);
@@ -2798,7 +2826,7 @@ void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
__ Push(r2, r1, r0);
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
+ ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()),
5,
1);
}
@@ -2829,7 +2857,8 @@ void TypeRecordingBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
__ Push(r2, r1, r0);
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch)),
+ ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch),
+ masm->isolate()),
5,
1);
}
@@ -2855,6 +2884,9 @@ void TypeRecordingBinaryOpStub::Generate(MacroAssembler* masm) {
case TRBinaryOpIC::HEAP_NUMBER:
GenerateHeapNumberStub(masm);
break;
+ case TRBinaryOpIC::ODDBALL:
+ GenerateOddballStub(masm);
+ break;
case TRBinaryOpIC::STRING:
GenerateStringStub(masm);
break;
@@ -2870,7 +2902,8 @@ void TypeRecordingBinaryOpStub::Generate(MacroAssembler* masm) {
const char* TypeRecordingBinaryOpStub::GetName() {
if (name_ != NULL) return name_;
const int kMaxNameLength = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
+ kMaxNameLength);
if (name_ == NULL) return "OOM";
const char* op_name = Token::Name(op_);
const char* overwrite_name;
@@ -3024,6 +3057,7 @@ void TypeRecordingBinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
Register right = r0;
Register scratch1 = r7;
Register scratch2 = r9;
+ Register scratch3 = r4;
ASSERT(smi_operands || (not_numbers != NULL));
if (smi_operands && FLAG_debug_code) {
@@ -3043,7 +3077,8 @@ void TypeRecordingBinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
// Load left and right operands into d6 and d7 or r0/r1 and r2/r3
// depending on whether VFP3 is available or not.
FloatingPointHelper::Destination destination =
- CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ?
+ Isolate::Current()->cpu_features()->IsSupported(VFP3) &&
+ op_ != Token::MOD ?
FloatingPointHelper::kVFPRegisters :
FloatingPointHelper::kCoreRegisters;
@@ -3111,22 +3146,24 @@ void TypeRecordingBinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
__ SmiUntag(r2, right);
} else {
// Convert operands to 32-bit integers. Right in r2 and left in r3.
- FloatingPointHelper::LoadNumberAsInteger(masm,
- left,
- r3,
- heap_number_map,
- scratch1,
- scratch2,
- d0,
- not_numbers);
- FloatingPointHelper::LoadNumberAsInteger(masm,
- right,
- r2,
- heap_number_map,
- scratch1,
- scratch2,
- d0,
- not_numbers);
+ FloatingPointHelper::ConvertNumberToInt32(masm,
+ left,
+ r3,
+ heap_number_map,
+ scratch1,
+ scratch2,
+ scratch3,
+ d0,
+ not_numbers);
+ FloatingPointHelper::ConvertNumberToInt32(masm,
+ right,
+ r2,
+ heap_number_map,
+ scratch1,
+ scratch2,
+ scratch3,
+ d0,
+ not_numbers);
}
Label result_not_a_smi;
@@ -3153,7 +3190,7 @@ void TypeRecordingBinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
// The code below for writing into heap numbers isn't capable of
// writing the register as an unsigned int so we go to slow case if we
// hit this case.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
__ b(mi, &result_not_a_smi);
} else {
__ b(mi, not_numbers);
@@ -3192,7 +3229,7 @@ void TypeRecordingBinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
// result.
__ mov(r0, Operand(r5));
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
// Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
// mentioned above SHR needs to always produce a positive result.
CpuFeatures::Scope scope(VFP3);
@@ -3321,7 +3358,8 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
// Jump to type transition if they are not. The registers r0 and r1 (right
// and left) are preserved for the runtime call.
FloatingPointHelper::Destination destination =
- CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ?
+ Isolate::Current()->cpu_features()->IsSupported(VFP3) &&
+ op_ != Token::MOD ?
FloatingPointHelper::kVFPRegisters :
FloatingPointHelper::kCoreRegisters;
@@ -3391,9 +3429,20 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
__ add(scratch2, scratch1, Operand(0x40000000), SetCC);
// If not try to return a heap number.
__ b(mi, &return_heap_number);
+ // Check for minus zero. Return heap number for minus zero.
+ Label not_zero;
+ __ cmp(scratch1, Operand(0));
+ __ b(ne, &not_zero);
+ __ vmov(scratch2, d5.high());
+ __ tst(scratch2, Operand(HeapNumber::kSignMask));
+ __ b(ne, &return_heap_number);
+ __ bind(&not_zero);
+
// Tag the result and return.
__ SmiTag(r0, scratch1);
__ Ret();
+ } else {
+ // DIV just falls through to allocating a heap number.
}
if (result_type_ >= (op_ == Token::DIV) ? TRBinaryOpIC::HEAP_NUMBER
@@ -3496,7 +3545,7 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
// to return a heap number if we can.
// The non vfp3 code does not support this special case, so jump to
// runtime if we don't support it.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
__ b(mi,
(result_type_ <= TRBinaryOpIC::INT32) ? &transition
: &return_heap_number);
@@ -3522,7 +3571,7 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
__ Ret();
__ bind(&return_heap_number);
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
heap_number_result = r5;
GenerateHeapResultAllocation(masm,
@@ -3571,14 +3620,42 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
}
-void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
- Label not_numbers, call_runtime;
- ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER);
+void TypeRecordingBinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
+ Label call_runtime;
- GenerateFPOperation(masm, false, &not_numbers, &call_runtime);
+ if (op_ == Token::ADD) {
+ // Handle string addition here, because it is the only operation
+ // that does not do a ToNumber conversion on the operands.
+ GenerateAddStrings(masm);
+ }
- __ bind(&not_numbers);
- GenerateTypeTransition(masm);
+ // Convert oddball arguments to numbers.
+ Label check, done;
+ __ CompareRoot(r1, Heap::kUndefinedValueRootIndex);
+ __ b(ne, &check);
+ if (Token::IsBitOp(op_)) {
+ __ mov(r1, Operand(Smi::FromInt(0)));
+ } else {
+ __ LoadRoot(r1, Heap::kNanValueRootIndex);
+ }
+ __ jmp(&done);
+ __ bind(&check);
+ __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
+ __ b(ne, &done);
+ if (Token::IsBitOp(op_)) {
+ __ mov(r0, Operand(Smi::FromInt(0)));
+ } else {
+ __ LoadRoot(r0, Heap::kNanValueRootIndex);
+ }
+ __ bind(&done);
+
+ GenerateHeapNumberStub(masm);
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
+ Label call_runtime;
+ GenerateFPOperation(masm, false, &call_runtime, &call_runtime);
__ bind(&call_runtime);
GenerateCallRuntime(masm);
@@ -3729,7 +3806,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
const Register cache_entry = r0;
const bool tagged = (argument_type_ == TAGGED);
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
if (tagged) {
// Argument is a number and is on stack and in r0.
@@ -3764,17 +3841,20 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ eor(r1, r2, Operand(r3));
__ eor(r1, r1, Operand(r1, ASR, 16));
__ eor(r1, r1, Operand(r1, ASR, 8));
- ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
- __ And(r1, r1, Operand(TranscendentalCache::kCacheSize - 1));
+ ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
+ __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
// r2 = low 32 bits of double value.
// r3 = high 32 bits of double value.
// r1 = TranscendentalCache::hash(double value).
- __ mov(cache_entry,
- Operand(ExternalReference::transcendental_cache_array_address()));
- // r0 points to cache array.
- __ ldr(cache_entry, MemOperand(cache_entry,
- type_ * sizeof(TranscendentalCache::caches_[0])));
+ Isolate* isolate = masm->isolate();
+ ExternalReference cache_array =
+ ExternalReference::transcendental_cache_array_address(isolate);
+ __ mov(cache_entry, Operand(cache_array));
+ // cache_entry points to cache array.
+ int cache_array_index
+ = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
+ __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
// r0 points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
__ cmp(cache_entry, Operand(0, RelocInfo::NONE));
@@ -3782,7 +3862,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
#ifdef DEBUG
// Check that the layout of cache elements match expectations.
- { TranscendentalCache::Element test_elem[2];
+ { TranscendentalCache::SubCache::Element test_elem[2];
char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
@@ -3814,14 +3894,16 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
}
__ Ret();
- } // if (CpuFeatures::IsSupported(VFP3))
+ } // if (Isolate::Current()->cpu_features()->IsSupported(VFP3))
__ bind(&calculate);
if (tagged) {
__ bind(&invalid_cache);
- __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+ ExternalReference runtime_function =
+ ExternalReference(RuntimeFunction(), masm->isolate());
+ __ TailCallExternalReference(runtime_function, 1, 1);
} else {
- if (!CpuFeatures::IsSupported(VFP3)) UNREACHABLE();
+ if (!Isolate::Current()->cpu_features()->IsSupported(VFP3)) UNREACHABLE();
CpuFeatures::Scope scope(VFP3);
Label no_update;
@@ -3882,18 +3964,20 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
Register scratch) {
+ Isolate* isolate = masm->isolate();
+
__ push(lr);
__ PrepareCallCFunction(2, scratch);
__ vmov(r0, r1, d2);
switch (type_) {
case TranscendentalCache::SIN:
- __ CallCFunction(ExternalReference::math_sin_double_function(), 2);
+ __ CallCFunction(ExternalReference::math_sin_double_function(isolate), 2);
break;
case TranscendentalCache::COS:
- __ CallCFunction(ExternalReference::math_cos_double_function(), 2);
+ __ CallCFunction(ExternalReference::math_cos_double_function(isolate), 2);
break;
case TranscendentalCache::LOG:
- __ CallCFunction(ExternalReference::math_log_double_function(), 2);
+ __ CallCFunction(ExternalReference::math_log_double_function(isolate), 2);
break;
default:
UNIMPLEMENTED();
@@ -4018,7 +4102,7 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
__ mov(r0, Operand(r2));
}
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
// Convert the int32 in r1 to the heap number in r0. r2 is corrupted.
CpuFeatures::Scope scope(VFP3);
__ vmov(s0, r1);
@@ -4056,6 +4140,113 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
}
+void MathPowStub::Generate(MacroAssembler* masm) {
+ Label call_runtime;
+
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+
+ Label base_not_smi;
+ Label exponent_not_smi;
+ Label convert_exponent;
+
+ const Register base = r0;
+ const Register exponent = r1;
+ const Register heapnumbermap = r5;
+ const Register heapnumber = r6;
+ const DoubleRegister double_base = d0;
+ const DoubleRegister double_exponent = d1;
+ const DoubleRegister double_result = d2;
+ const SwVfpRegister single_scratch = s0;
+ const Register scratch = r9;
+ const Register scratch2 = r7;
+
+ __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
+ __ ldr(base, MemOperand(sp, 1 * kPointerSize));
+ __ ldr(exponent, MemOperand(sp, 0 * kPointerSize));
+
+ // Convert base to double value and store it in d0.
+ __ JumpIfNotSmi(base, &base_not_smi);
+ // Base is a Smi. Untag and convert it.
+ __ SmiUntag(base);
+ __ vmov(single_scratch, base);
+ __ vcvt_f64_s32(double_base, single_scratch);
+ __ b(&convert_exponent);
+
+ __ bind(&base_not_smi);
+ __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset));
+ __ cmp(scratch, heapnumbermap);
+ __ b(ne, &call_runtime);
+ // Base is a heapnumber. Load it into double register.
+ __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
+
+ __ bind(&convert_exponent);
+ __ JumpIfNotSmi(exponent, &exponent_not_smi);
+ __ SmiUntag(exponent);
+
+ // The base is in a double register and the exponent is
+ // an untagged smi. Allocate a heap number and call a
+ // C function for integer exponents. The register containing
+ // the heap number is callee-saved.
+ __ AllocateHeapNumber(heapnumber,
+ scratch,
+ scratch2,
+ heapnumbermap,
+ &call_runtime);
+ __ push(lr);
+ __ PrepareCallCFunction(3, scratch);
+ __ mov(r2, exponent);
+ __ vmov(r0, r1, double_base);
+ __ CallCFunction(
+ ExternalReference::power_double_int_function(masm->isolate()), 3);
+ __ pop(lr);
+ __ GetCFunctionDoubleResult(double_result);
+ __ vstr(double_result,
+ FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
+ __ mov(r0, heapnumber);
+ __ Ret(2 * kPointerSize);
+
+ __ bind(&exponent_not_smi);
+ __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
+ __ cmp(scratch, heapnumbermap);
+ __ b(ne, &call_runtime);
+ // Exponent is a heapnumber. Load it into double register.
+ __ vldr(double_exponent,
+ FieldMemOperand(exponent, HeapNumber::kValueOffset));
+
+ // The base and the exponent are in double registers.
+ // Allocate a heap number and call a C function for
+ // double exponents. The register containing
+ // the heap number is callee-saved.
+ __ AllocateHeapNumber(heapnumber,
+ scratch,
+ scratch2,
+ heapnumbermap,
+ &call_runtime);
+ __ push(lr);
+ __ PrepareCallCFunction(4, scratch);
+ __ vmov(r0, r1, double_base);
+ __ vmov(r2, r3, double_exponent);
+ __ CallCFunction(
+ ExternalReference::power_double_double_function(masm->isolate()), 4);
+ __ pop(lr);
+ __ GetCFunctionDoubleResult(double_result);
+ __ vstr(double_result,
+ FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
+ __ mov(r0, heapnumber);
+ __ Ret(2 * kPointerSize);
+ }
+
+ __ bind(&call_runtime);
+ __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
+}
+
+
+bool CEntryStub::NeedsImmovableCode() {
+ return true;
+}
+
+
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
__ Throw(r0);
}
@@ -4077,15 +4268,16 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
// r4: number of arguments including receiver (C callee-saved)
// r5: pointer to builtin function (C callee-saved)
// r6: pointer to the first argument (C callee-saved)
+ Isolate* isolate = masm->isolate();
if (do_gc) {
// Passing r0.
__ PrepareCallCFunction(1, r1);
- __ CallCFunction(ExternalReference::perform_gc_function(), 1);
+ __ CallCFunction(ExternalReference::perform_gc_function(isolate), 1);
}
ExternalReference scope_depth =
- ExternalReference::heap_always_allocate_scope_depth();
+ ExternalReference::heap_always_allocate_scope_depth(isolate);
if (always_allocate) {
__ mov(r0, Operand(scope_depth));
__ ldr(r1, MemOperand(r0));
@@ -4114,6 +4306,9 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
}
#endif
+ __ mov(r2, Operand(ExternalReference::isolate_address()));
+
+
// TODO(1242173): To let the GC traverse the return address of the exit
// frames, we need to know where the return address is. Right now,
// we store it on the stack to be able to find it again, but we never
@@ -4167,15 +4362,16 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ b(eq, throw_out_of_memory_exception);
// Retrieve the pending exception and clear the variable.
- __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
+ __ mov(ip, Operand(ExternalReference::the_hole_value_location(isolate)));
__ ldr(r3, MemOperand(ip));
- __ mov(ip, Operand(ExternalReference(Top::k_pending_exception_address)));
+ __ mov(ip, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ isolate)));
__ ldr(r0, MemOperand(ip));
__ str(r3, MemOperand(ip));
// Special handling of termination exceptions which are uncatchable
// by javascript code.
- __ cmp(r0, Operand(Factory::termination_exception()));
+ __ cmp(r0, Operand(isolate->factory()->termination_exception()));
__ b(eq, throw_termination_exception);
// Handle normal exception.
@@ -4283,11 +4479,13 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// r2: receiver
// r3: argc
// r4: argv
+ Isolate* isolate = masm->isolate();
__ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used.
int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
__ mov(r7, Operand(Smi::FromInt(marker)));
__ mov(r6, Operand(Smi::FromInt(marker)));
- __ mov(r5, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+ __ mov(r5,
+ Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate)));
__ ldr(r5, MemOperand(r5));
__ Push(r8, r7, r6, r5);
@@ -4296,7 +4494,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
#ifdef ENABLE_LOGGING_AND_PROFILING
// If this is the outermost JS call, set js_entry_sp value.
- ExternalReference js_entry_sp(Top::k_js_entry_sp_address);
+ ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate);
__ mov(r5, Operand(ExternalReference(js_entry_sp)));
__ ldr(r6, MemOperand(r5));
__ cmp(r6, Operand(0, RelocInfo::NONE));
@@ -4310,7 +4508,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// exception field in the JSEnv and return a failure sentinel.
// Coming in here the fp will be invalid because the PushTryHandler below
// sets it to 0 to signal the existence of the JSEntry frame.
- __ mov(ip, Operand(ExternalReference(Top::k_pending_exception_address)));
+ __ mov(ip, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ isolate)));
__ str(r0, MemOperand(ip));
__ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
__ b(&exit);
@@ -4325,9 +4524,10 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// saved values before returning a failure to C.
// Clear any pending exceptions.
- __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
+ __ mov(ip, Operand(ExternalReference::the_hole_value_location(isolate)));
__ ldr(r5, MemOperand(ip));
- __ mov(ip, Operand(ExternalReference(Top::k_pending_exception_address)));
+ __ mov(ip, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ isolate)));
__ str(r5, MemOperand(ip));
// Invoke the function by calling through JS entry trampoline builtin.
@@ -4341,10 +4541,11 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// r3: argc
// r4: argv
if (is_construct) {
- ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
+ ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
+ isolate);
__ mov(ip, Operand(construct_entry));
} else {
- ExternalReference entry(Builtins::JSEntryTrampoline);
+ ExternalReference entry(Builtins::kJSEntryTrampoline, isolate);
__ mov(ip, Operand(entry));
}
__ ldr(ip, MemOperand(ip)); // deref address
@@ -4360,7 +4561,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// displacement since the current stack pointer (sp) points directly
// to the stack handler.
__ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset));
- __ mov(ip, Operand(ExternalReference(Top::k_handler_address)));
+ __ mov(ip, Operand(ExternalReference(Isolate::k_handler_address, isolate)));
__ str(r3, MemOperand(ip));
// No need to restore registers
__ add(sp, sp, Operand(StackHandlerConstants::kSize));
@@ -4378,7 +4579,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
__ bind(&exit); // r0 holds result
// Restore the top frame descriptors from the stack.
__ pop(r3);
- __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+ __ mov(ip,
+ Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate)));
__ str(r3, MemOperand(ip));
// Reset the stack to the callee saved registers.
@@ -4535,7 +4737,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ b(ne, &slow);
// Null is not instance of anything.
- __ cmp(scratch, Operand(Factory::null_value()));
+ __ cmp(scratch, Operand(FACTORY->null_value()));
__ b(ne, &object_not_null);
__ mov(r0, Operand(Smi::FromInt(1)));
__ Ret(HasArgsInRegisters() ? 0 : 2);
@@ -4662,7 +4864,7 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
__ mov(r1, Operand(r1, LSR, kSmiTagSize));
__ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize));
__ bind(&add_arguments_object);
- __ add(r1, r1, Operand(Heap::kArgumentsObjectSize / kPointerSize));
+ __ add(r1, r1, Operand(GetArgumentsObjectSize() / kPointerSize));
// Do the allocation of both objects in one go.
__ AllocateInNewSpace(
@@ -4674,23 +4876,28 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
// Get the arguments boilerplate from the current (global) context.
- int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
__ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset));
- __ ldr(r4, MemOperand(r4, offset));
+ __ ldr(r4, MemOperand(r4,
+ Context::SlotOffset(GetArgumentsBoilerplateIndex())));
// Copy the JS object part.
__ CopyFields(r0, r4, r3.bit(), JSObject::kHeaderSize / kPointerSize);
- // Setup the callee in-object property.
- STATIC_ASSERT(Heap::arguments_callee_index == 0);
- __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
- __ str(r3, FieldMemOperand(r0, JSObject::kHeaderSize));
+ if (type_ == NEW_NON_STRICT) {
+ // Setup the callee in-object property.
+ STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
+ __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
+ const int kCalleeOffset = JSObject::kHeaderSize +
+ Heap::kArgumentsCalleeIndex * kPointerSize;
+ __ str(r3, FieldMemOperand(r0, kCalleeOffset));
+ }
// Get the length (smi tagged) and set that as an in-object property too.
- STATIC_ASSERT(Heap::arguments_length_index == 1);
+ STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
__ ldr(r1, MemOperand(sp, 0 * kPointerSize));
- __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize + kPointerSize));
+ __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize +
+ Heap::kArgumentsLengthIndex * kPointerSize));
// If there are no actual arguments, we're done.
Label done;
@@ -4702,7 +4909,7 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
// Setup the elements pointer in the allocated arguments object and
// initialize the header in the elements fixed array.
- __ add(r4, r0, Operand(Heap::kArgumentsObjectSize));
+ __ add(r4, r0, Operand(GetArgumentsObjectSize()));
__ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
__ LoadRoot(r3, Heap::kFixedArrayMapRootIndex);
__ str(r3, FieldMemOperand(r4, FixedArray::kMapOffset));
@@ -4769,10 +4976,11 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
Register last_match_info_elements = r6;
// Ensure that a RegExp stack is allocated.
+ Isolate* isolate = masm->isolate();
ExternalReference address_of_regexp_stack_memory_address =
- ExternalReference::address_of_regexp_stack_memory_address();
+ ExternalReference::address_of_regexp_stack_memory_address(isolate);
ExternalReference address_of_regexp_stack_memory_size =
- ExternalReference::address_of_regexp_stack_memory_size();
+ ExternalReference::address_of_regexp_stack_memory_size(isolate);
__ mov(r0, Operand(address_of_regexp_stack_memory_size));
__ ldr(r0, MemOperand(r0, 0));
__ tst(r0, Operand(r0));
@@ -4913,7 +5121,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ CompareObjectType(r7, r0, r0, CODE_TYPE);
__ b(ne, &runtime);
- // r3: encoding of subject string (1 if ascii, 0 if two_byte);
+ // r3: encoding of subject string (1 if ASCII, 0 if two_byte);
// r7: code
// subject: Subject string
// regexp_data: RegExp data (FixedArray)
@@ -4923,20 +5131,25 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ mov(r1, Operand(r1, ASR, kSmiTagSize));
// r1: previous index
- // r3: encoding of subject string (1 if ascii, 0 if two_byte);
+ // r3: encoding of subject string (1 if ASCII, 0 if two_byte);
// r7: code
// subject: Subject string
// regexp_data: RegExp data (FixedArray)
// All checks done. Now push arguments for native regexp code.
- __ IncrementCounter(&Counters::regexp_entry_native, 1, r0, r2);
+ __ IncrementCounter(isolate->counters()->regexp_entry_native(), 1, r0, r2);
- static const int kRegExpExecuteArguments = 7;
+ // Isolates: note we add an additional parameter here (isolate pointer).
+ static const int kRegExpExecuteArguments = 8;
static const int kParameterRegisters = 4;
__ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters);
// Stack pointer now points to cell where return address is to be written.
// Arguments are before that on the stack or in registers.
+ // Argument 8 (sp[16]): Pass current isolate address.
+ __ mov(r0, Operand(ExternalReference::isolate_address()));
+ __ str(r0, MemOperand(sp, 4 * kPointerSize));
+
// Argument 7 (sp[12]): Indicate that this is a direct call from JavaScript.
__ mov(r0, Operand(1));
__ str(r0, MemOperand(sp, 3 * kPointerSize));
@@ -4950,7 +5163,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ str(r0, MemOperand(sp, 2 * kPointerSize));
// Argument 5 (sp[4]): static offsets vector buffer.
- __ mov(r0, Operand(ExternalReference::address_of_static_offsets_vector()));
+ __ mov(r0,
+ Operand(ExternalReference::address_of_static_offsets_vector(isolate)));
__ str(r0, MemOperand(sp, 1 * kPointerSize));
// For arguments 4 and 3 get string length, calculate start of string data and
@@ -4998,9 +5212,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system.
// TODO(592): Rerunning the RegExp to get the stack overflow exception.
- __ mov(r1, Operand(ExternalReference::the_hole_value_location()));
+ __ mov(r1, Operand(ExternalReference::the_hole_value_location(isolate)));
__ ldr(r1, MemOperand(r1, 0));
- __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
+ __ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ isolate)));
__ ldr(r0, MemOperand(r2, 0));
__ cmp(r0, r1);
__ b(eq, &runtime);
@@ -5020,7 +5235,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ bind(&failure);
// For failure and exception return null.
- __ mov(r0, Operand(Factory::null_value()));
+ __ mov(r0, Operand(FACTORY->null_value()));
__ add(sp, sp, Operand(4 * kPointerSize));
__ Ret();
@@ -5053,7 +5268,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Get the static offsets vector filled by the native regexp code.
ExternalReference address_of_static_offsets_vector =
- ExternalReference::address_of_static_offsets_vector();
+ ExternalReference::address_of_static_offsets_vector(isolate);
__ mov(r2, Operand(address_of_static_offsets_vector));
// r1: number of capture registers
@@ -5125,7 +5340,7 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
// Interleave operations for better latency.
__ ldr(r2, ContextOperand(cp, Context::GLOBAL_INDEX));
__ add(r3, r0, Operand(JSRegExpResult::kSize));
- __ mov(r4, Operand(Factory::empty_fixed_array()));
+ __ mov(r4, Operand(FACTORY->empty_fixed_array()));
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset));
__ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset));
__ ldr(r2, ContextOperand(r2, Context::REGEXP_RESULT_MAP_INDEX));
@@ -5146,13 +5361,13 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
// r5: Number of elements in array, untagged.
// Set map.
- __ mov(r2, Operand(Factory::fixed_array_map()));
+ __ mov(r2, Operand(FACTORY->fixed_array_map()));
__ str(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
// Set FixedArray length.
__ mov(r6, Operand(r5, LSL, kSmiTagSize));
__ str(r6, FieldMemOperand(r3, FixedArray::kLengthOffset));
// Fill contents of fixed-array with the-hole.
- __ mov(r2, Operand(Factory::the_hole_value()));
+ __ mov(r2, Operand(FACTORY->the_hole_value()));
__ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
// Fill fixed array elements with hole.
// r0: JSArray, tagged.
@@ -5229,7 +5444,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ mov(r0, Operand(argc_)); // Setup the number of arguments.
__ mov(r2, Operand(0, RelocInfo::NONE));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
- __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)),
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
}
@@ -5242,7 +5457,8 @@ const char* CompareStub::GetName() {
if (name_ != NULL) return name_;
const int kMaxNameLength = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
+ kMaxNameLength);
if (name_ == NULL) return "OOM";
const char* cc_name;
@@ -5455,7 +5671,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
__ b(ne, &slow_case_);
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
- // At this point code register contains smi tagged ascii char code.
+ // At this point code register contains smi tagged ASCII char code.
STATIC_ASSERT(kSmiTag == 0);
__ add(result_, result_, Operand(code_, LSL, kPointerSizeLog2 - kSmiTagSize));
__ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
@@ -5787,7 +6003,6 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
Register symbol_table = c2;
__ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
- // Load undefined value
Register undefined = scratch4;
__ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
@@ -5808,6 +6023,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
// mask: capacity mask
// first_symbol_table_element: address of the first element of
// the symbol table
+ // undefined: the undefined object
// scratch: -
// Perform a number of probes in the symbol table.
@@ -5835,20 +6051,32 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
kPointerSizeLog2));
// If entry is undefined no string with this hash can be found.
- __ cmp(candidate, undefined);
+ Label is_string;
+ __ CompareObjectType(candidate, scratch, scratch, ODDBALL_TYPE);
+ __ b(ne, &is_string);
+
+ __ cmp(undefined, candidate);
__ b(eq, not_found);
+ // Must be null (deleted entry).
+ if (FLAG_debug_code) {
+ __ LoadRoot(ip, Heap::kNullValueRootIndex);
+ __ cmp(ip, candidate);
+ __ Assert(eq, "oddball in symbol table is not undefined or null");
+ }
+ __ jmp(&next_probe[i]);
+
+ __ bind(&is_string);
+
+ // Check that the candidate is a non-external ASCII string. The instance
+ // type is still in the scratch register from the CompareObjectType
+ // operation.
+ __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]);
// If length is not 2 the string is not a candidate.
__ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset));
__ cmp(scratch, Operand(Smi::FromInt(2)));
__ b(ne, &next_probe[i]);
- // Check that the candidate is a non-external ascii string.
- __ ldr(scratch, FieldMemOperand(candidate, HeapObject::kMapOffset));
- __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
- __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch,
- &next_probe[i]);
-
// Check if the two characters match.
// Assumes that word load is little endian.
__ ldrh(scratch, FieldMemOperand(candidate, SeqAsciiString::kHeaderSize));
@@ -5923,7 +6151,6 @@ void SubStringStub::Generate(MacroAssembler* masm) {
static const int kFromOffset = 1 * kPointerSize;
static const int kStringOffset = 2 * kPointerSize;
-
// Check bounds and smi-ness.
Register to = r6;
Register from = r7;
@@ -6004,7 +6231,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// r3: from index (untaged smi)
// r5: string.
// r7 (a.k.a. from): from offset (smi)
- // Check for flat ascii string.
+ // Check for flat ASCII string.
Label non_ascii_flat;
__ tst(r1, Operand(kStringEncodingMask));
STATIC_ASSERT(kTwoByteStringTag == 0);
@@ -6024,7 +6251,8 @@ void SubStringStub::Generate(MacroAssembler* masm) {
Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string);
- __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
@@ -6033,7 +6261,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ bind(&make_two_character_string);
__ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime);
__ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
- __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
+ __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
@@ -6059,7 +6287,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
COPY_ASCII | DEST_ALWAYS_ALIGNED);
- __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
+ __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
@@ -6091,7 +6319,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(
masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED);
- __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
+ __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
@@ -6163,6 +6391,8 @@ void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
void StringCompareStub::Generate(MacroAssembler* masm) {
Label runtime;
+ Counters* counters = masm->isolate()->counters();
+
// Stack frame on entry.
// sp[0]: right string
// sp[4]: left string
@@ -6174,17 +6404,17 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
STATIC_ASSERT(EQUAL == 0);
STATIC_ASSERT(kSmiTag == 0);
__ mov(r0, Operand(Smi::FromInt(EQUAL)));
- __ IncrementCounter(&Counters::string_compare_native, 1, r1, r2);
+ __ IncrementCounter(counters->string_compare_native(), 1, r1, r2);
__ add(sp, sp, Operand(2 * kPointerSize));
__ Ret();
__ bind(&not_same);
- // Check that both objects are sequential ascii strings.
+ // Check that both objects are sequential ASCII strings.
__ JumpIfNotBothSequentialAsciiStrings(r1, r0, r2, r3, &runtime);
- // Compare flat ascii strings natively. Remove arguments from stack first.
- __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3);
+ // Compare flat ASCII strings natively. Remove arguments from stack first.
+ __ IncrementCounter(counters->string_compare_native(), 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5);
@@ -6199,6 +6429,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
Label string_add_runtime, call_builtin;
Builtins::JavaScript builtin_id = Builtins::ADD;
+ Counters* counters = masm->isolate()->counters();
+
// Stack on entry:
// sp[0]: second argument (right).
// sp[4]: first argument (left).
@@ -6254,7 +6486,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ cmp(r3, Operand(Smi::FromInt(0)), ne);
__ b(ne, &strings_not_empty); // If either string was empty, return r0.
- __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
+ __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
__ Ret();
@@ -6275,12 +6507,12 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// Adding two lengths can't overflow.
STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2);
__ add(r6, r2, Operand(r3));
- // Use the runtime system when adding two one character strings, as it
- // contains optimizations for this specific case using the symbol table.
+ // Use the symbol table when adding two one character strings, as it
+ // helps later optimizations to return a symbol here.
__ cmp(r6, Operand(2));
__ b(ne, &longer_than_two);
- // Check that both strings are non-external ascii strings.
+ // Check that both strings are non-external ASCII strings.
if (flags_ != NO_STRING_ADD_FLAGS) {
__ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
@@ -6299,7 +6531,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string);
- __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
+ __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
__ Ret();
@@ -6312,7 +6544,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ mov(r6, Operand(2));
__ AllocateAsciiString(r0, r6, r4, r5, r9, &string_add_runtime);
__ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
- __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
+ __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
__ Ret();
@@ -6328,7 +6560,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ b(hs, &string_add_runtime);
// If result is not supposed to be flat, allocate a cons string object.
- // If both strings are ascii the result is an ascii cons string.
+ // If both strings are ASCII the result is an ASCII cons string.
if (flags_ != NO_STRING_ADD_FLAGS) {
__ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
@@ -6349,13 +6581,13 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset));
__ str(r1, FieldMemOperand(r7, ConsString::kSecondOffset));
__ mov(r0, Operand(r7));
- __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
+ __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
__ Ret();
__ bind(&non_ascii);
// At least one of the strings is two-byte. Check whether it happens
- // to contain only ascii characters.
+ // to contain only ASCII characters.
// r4: first instance type.
// r5: second instance type.
__ tst(r4, Operand(kAsciiDataHintMask));
@@ -6431,7 +6663,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r7: result string.
StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true);
__ mov(r0, Operand(r7));
- __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
+ __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
__ Ret();
@@ -6472,7 +6704,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false);
__ mov(r0, Operand(r7));
- __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
+ __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
__ Ret();
@@ -6536,56 +6768,6 @@ void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
}
-void StringCharAtStub::Generate(MacroAssembler* masm) {
- // Expects two arguments (object, index) on the stack:
- // lr: return address
- // sp[0]: index
- // sp[4]: object
- Register object = r1;
- Register index = r0;
- Register scratch1 = r2;
- Register scratch2 = r3;
- Register result = r0;
-
- // Get object and index from the stack.
- __ pop(index);
- __ pop(object);
-
- Label need_conversion;
- Label index_out_of_range;
- Label done;
- StringCharAtGenerator generator(object,
- index,
- scratch1,
- scratch2,
- result,
- &need_conversion,
- &need_conversion,
- &index_out_of_range,
- STRING_INDEX_IS_NUMBER);
- generator.GenerateFast(masm);
- __ b(&done);
-
- __ bind(&index_out_of_range);
- // When the index is out of range, the spec requires us to return
- // the empty string.
- __ LoadRoot(result, Heap::kEmptyStringRootIndex);
- __ jmp(&done);
-
- __ bind(&need_conversion);
- // Move smi zero into the result register, which will trigger
- // conversion.
- __ mov(result, Operand(Smi::FromInt(0)));
- __ b(&done);
-
- StubRuntimeCallHelper call_helper;
- generator.GenerateSlow(masm, call_helper);
-
- __ bind(&done);
- __ Ret();
-}
-
-
void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
ASSERT(state_ == CompareIC::SMIS);
Label miss;
@@ -6625,7 +6807,7 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
// Inlining the double comparison and falling back to the general compare
// stub if NaN is involved or VFP3 is unsupported.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Load left and right operand
@@ -6684,7 +6866,8 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
__ push(lr);
// Call the runtime system in a fresh internal frame.
- ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss));
+ ExternalReference miss =
+ ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
__ EnterInternalFrame();
__ Push(r1, r0);
__ mov(ip, Operand(Smi::FromInt(op_)));
@@ -6727,158 +6910,6 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
}
-void GenerateFastPixelArrayLoad(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register elements_map,
- Register elements,
- Register scratch1,
- Register scratch2,
- Register result,
- Label* not_pixel_array,
- Label* key_not_smi,
- Label* out_of_range) {
- // Register use:
- //
- // receiver - holds the receiver on entry.
- // Unchanged unless 'result' is the same register.
- //
- // key - holds the smi key on entry.
- // Unchanged unless 'result' is the same register.
- //
- // elements - set to be the receiver's elements on exit.
- //
- // elements_map - set to be the map of the receiver's elements
- // on exit.
- //
- // result - holds the result of the pixel array load on exit,
- // tagged as a smi if successful.
- //
- // Scratch registers:
- //
- // scratch1 - used a scratch register in map check, if map
- // check is successful, contains the length of the
- // pixel array, the pointer to external elements and
- // the untagged result.
- //
- // scratch2 - holds the untaged key.
-
- // Some callers already have verified that the key is a smi. key_not_smi is
- // set to NULL as a sentinel for that case. Otherwise, add an explicit check
- // to ensure the key is a smi must be added.
- if (key_not_smi != NULL) {
- __ JumpIfNotSmi(key, key_not_smi);
- } else {
- if (FLAG_debug_code) {
- __ AbortIfNotSmi(key);
- }
- }
- __ SmiUntag(scratch2, key);
-
- // Verify that the receiver has pixel array elements.
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ CheckMap(elements, scratch1, Heap::kPixelArrayMapRootIndex,
- not_pixel_array, true);
-
- // Key must be in range of the pixel array.
- __ ldr(scratch1, FieldMemOperand(elements, PixelArray::kLengthOffset));
- __ cmp(scratch2, scratch1);
- __ b(hs, out_of_range); // unsigned check handles negative keys.
-
- // Perform the indexed load and tag the result as a smi.
- __ ldr(scratch1,
- FieldMemOperand(elements, PixelArray::kExternalPointerOffset));
- __ ldrb(scratch1, MemOperand(scratch1, scratch2));
- __ SmiTag(r0, scratch1);
- __ Ret();
-}
-
-
-void GenerateFastPixelArrayStore(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register value,
- Register elements,
- Register elements_map,
- Register scratch1,
- Register scratch2,
- bool load_elements_from_receiver,
- bool load_elements_map_from_elements,
- Label* key_not_smi,
- Label* value_not_smi,
- Label* not_pixel_array,
- Label* out_of_range) {
- // Register use:
- // receiver - holds the receiver and is unchanged unless the
- // store succeeds.
- // key - holds the key (must be a smi) and is unchanged.
- // value - holds the value (must be a smi) and is unchanged.
- // elements - holds the element object of the receiver on entry if
- // load_elements_from_receiver is false, otherwise used
- // internally to store the pixel arrays elements and
- // external array pointer.
- // elements_map - holds the map of the element object if
- // load_elements_map_from_elements is false, otherwise
- // loaded with the element map.
- //
- Register external_pointer = elements;
- Register untagged_key = scratch1;
- Register untagged_value = scratch2;
-
- if (load_elements_from_receiver) {
- __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- }
-
- // By passing NULL as not_pixel_array, callers signal that they have already
- // verified that the receiver has pixel array elements.
- if (not_pixel_array != NULL) {
- if (load_elements_map_from_elements) {
- __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- }
- __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
- __ cmp(elements_map, ip);
- __ b(ne, not_pixel_array);
- } else {
- if (FLAG_debug_code) {
- // Map check should have already made sure that elements is a pixel array.
- __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
- __ cmp(elements_map, ip);
- __ Assert(eq, "Elements isn't a pixel array");
- }
- }
-
- // Some callers already have verified that the key is a smi. key_not_smi is
- // set to NULL as a sentinel for that case. Otherwise, add an explicit check
- // to ensure the key is a smi must be added.
- if (key_not_smi != NULL) {
- __ JumpIfNotSmi(key, key_not_smi);
- } else {
- if (FLAG_debug_code) {
- __ AbortIfNotSmi(key);
- }
- }
-
- __ SmiUntag(untagged_key, key);
-
- // Perform bounds check.
- __ ldr(scratch2, FieldMemOperand(elements, PixelArray::kLengthOffset));
- __ cmp(untagged_key, scratch2);
- __ b(hs, out_of_range); // unsigned check handles negative keys.
-
- __ JumpIfNotSmi(value, value_not_smi);
- __ SmiUntag(untagged_value, value);
-
- // Clamp the value to [0..255].
- __ Usat(untagged_value, 8, Operand(untagged_value));
- // Get the pointer to the external array. This clobbers elements.
- __ ldr(external_pointer,
- FieldMemOperand(elements, PixelArray::kExternalPointerOffset));
- __ strb(untagged_value, MemOperand(external_pointer, untagged_key));
- __ Ret();
-}
-
-
#undef __
} } // namespace v8::internal
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index e3ef3391..1dde255c 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -235,7 +235,7 @@ class TypeRecordingBinaryOpStub: public CodeStub {
operands_type_(TRBinaryOpIC::UNINITIALIZED),
result_type_(TRBinaryOpIC::UNINITIALIZED),
name_(NULL) {
- use_vfp3_ = CpuFeatures::IsSupported(VFP3);
+ use_vfp3_ = Isolate::Current()->cpu_features()->IsSupported(VFP3);
ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
}
@@ -311,6 +311,7 @@ class TypeRecordingBinaryOpStub: public CodeStub {
void GenerateSmiStub(MacroAssembler* masm);
void GenerateInt32Stub(MacroAssembler* masm);
void GenerateHeapNumberStub(MacroAssembler* masm);
+ void GenerateOddballStub(MacroAssembler* masm);
void GenerateStringStub(MacroAssembler* masm);
void GenerateGenericStub(MacroAssembler* masm);
void GenerateAddStrings(MacroAssembler* masm);
@@ -588,6 +589,9 @@ class RegExpCEntryStub: public CodeStub {
private:
Major MajorKey() { return RegExpCEntry; }
int MinorKey() { return 0; }
+
+ bool NeedsImmovableCode() { return true; }
+
const char* GetName() { return "RegExpCEntryStub"; }
};
@@ -607,60 +611,13 @@ class DirectCEntryStub: public CodeStub {
private:
Major MajorKey() { return DirectCEntry; }
int MinorKey() { return 0; }
+
+ bool NeedsImmovableCode() { return true; }
+
const char* GetName() { return "DirectCEntryStub"; }
};
-// Generate code to load an element from a pixel array. The receiver is assumed
-// to not be a smi and to have elements, the caller must guarantee this
-// precondition. If key is not a smi, then the generated code branches to
-// key_not_smi. Callers can specify NULL for key_not_smi to signal that a smi
-// check has already been performed on key so that the smi check is not
-// generated. If key is not a valid index within the bounds of the pixel array,
-// the generated code jumps to out_of_range. receiver, key and elements are
-// unchanged throughout the generated code sequence.
-void GenerateFastPixelArrayLoad(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register elements_map,
- Register elements,
- Register scratch1,
- Register scratch2,
- Register result,
- Label* not_pixel_array,
- Label* key_not_smi,
- Label* out_of_range);
-
-// Generate code to store an element into a pixel array, clamping values between
-// [0..255]. The receiver is assumed to not be a smi and to have elements, the
-// caller must guarantee this precondition. If key is not a smi, then the
-// generated code branches to key_not_smi. Callers can specify NULL for
-// key_not_smi to signal that a smi check has already been performed on key so
-// that the smi check is not generated. If value is not a smi, the generated
-// code will branch to value_not_smi. If the receiver doesn't have pixel array
-// elements, the generated code will branch to not_pixel_array, unless
-// not_pixel_array is NULL, in which case the caller must ensure that the
-// receiver has pixel array elements. If key is not a valid index within the
-// bounds of the pixel array, the generated code jumps to out_of_range. If
-// load_elements_from_receiver is true, then the elements of receiver is loaded
-// into elements, otherwise elements is assumed to already be the receiver's
-// elements. If load_elements_map_from_elements is true, elements_map is loaded
-// from elements, otherwise it is assumed to already contain the element map.
-void GenerateFastPixelArrayStore(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register value,
- Register elements,
- Register elements_map,
- Register scratch1,
- Register scratch2,
- bool load_elements_from_receiver,
- bool load_elements_map_from_elements,
- Label* key_not_smi,
- Label* value_not_smi,
- Label* not_pixel_array,
- Label* out_of_range);
-
} } // namespace v8::internal
#endif // V8_ARM_CODE_STUBS_ARM_H_
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index d32b0091..91c47476 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -132,8 +132,6 @@ TypeInfoCodeGenState::~TypeInfoCodeGenState() {
// -------------------------------------------------------------------------
// CodeGenerator implementation
-int CodeGenerator::inlined_write_barrier_size_ = -1;
-
CodeGenerator::CodeGenerator(MacroAssembler* masm)
: deferred_(8),
masm_(masm),
@@ -307,7 +305,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
if (!scope()->HasIllegalRedeclaration()) {
Comment cmnt(masm_, "[ function body");
#ifdef DEBUG
- bool is_builtin = Bootstrapper::IsActive();
+ bool is_builtin = Isolate::Current()->bootstrapper()->IsActive();
bool should_trace =
is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
if (should_trace) {
@@ -577,11 +575,13 @@ void CodeGenerator::LoadGlobalReceiver(Register scratch) {
ArgumentsAllocationMode CodeGenerator::ArgumentsMode() {
if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION;
- ASSERT(scope()->arguments_shadow() != NULL);
+
+ // In strict mode there is no need for shadow arguments.
+ ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode());
// We don't want to do lazy arguments allocation for functions that
// have heap-allocated contexts, because it interfers with the
// uninitialized const tracking in the context objects.
- return (scope()->num_heap_slots() > 0)
+ return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode())
? EAGER_ARGUMENTS_ALLOCATION
: LAZY_ARGUMENTS_ALLOCATION;
}
@@ -599,7 +599,9 @@ void CodeGenerator::StoreArgumentsObject(bool initial) {
frame_->EmitPushRoot(Heap::kArgumentsMarkerRootIndex);
} else {
frame_->SpillAll();
- ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+ ArgumentsAccessStub stub(is_strict_mode()
+ ? ArgumentsAccessStub::NEW_STRICT
+ : ArgumentsAccessStub::NEW_NON_STRICT);
__ ldr(r2, frame_->Function());
// The receiver is below the arguments, the return address, and the
// frame pointer on the stack.
@@ -615,7 +617,9 @@ void CodeGenerator::StoreArgumentsObject(bool initial) {
Variable* arguments = scope()->arguments();
Variable* shadow = scope()->arguments_shadow();
ASSERT(arguments != NULL && arguments->AsSlot() != NULL);
- ASSERT(shadow != NULL && shadow->AsSlot() != NULL);
+ ASSERT((shadow != NULL && shadow->AsSlot() != NULL) ||
+ scope()->is_strict_mode());
+
JumpTarget done;
if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) {
// We have to skip storing into the arguments slot if it has
@@ -629,7 +633,9 @@ void CodeGenerator::StoreArgumentsObject(bool initial) {
}
StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT);
if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind();
- StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT);
+ if (shadow != NULL) {
+ StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT);
+ }
}
@@ -764,7 +770,7 @@ void CodeGenerator::ToBoolean(JumpTarget* true_target,
true_target->Branch(eq);
// Slow case.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Implements the slow case by using ToBooleanStub.
// The ToBooleanStub takes a single argument, and
@@ -961,7 +967,8 @@ void DeferredInlineSmiOperation::JumpToNonSmiInput(Condition cond) {
void DeferredInlineSmiOperation::JumpToAnswerOutOfRange(Condition cond) {
ASSERT(Token::IsBitOp(op_));
- if ((op_ == Token::SHR) && !CpuFeatures::IsSupported(VFP3)) {
+ if ((op_ == Token::SHR) &&
+ !Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
// >>> requires an unsigned to double conversion and the non VFP code
// does not support this conversion.
__ b(cond, entry_label());
@@ -1065,7 +1072,7 @@ void DeferredInlineSmiOperation::Generate() {
void DeferredInlineSmiOperation::WriteNonSmiAnswer(Register answer,
Register heap_number,
Register scratch) {
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ vmov(s0, answer);
if (op_ == Token::SHR) {
@@ -1135,7 +1142,7 @@ void DeferredInlineSmiOperation::GenerateNonSmiInput() {
// SHR is special because it is required to produce a positive answer.
__ cmp(int32, Operand(0, RelocInfo::NONE));
}
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
__ b(mi, &result_not_a_smi);
} else {
// Non VFP code cannot convert from unsigned to double, so fall back
@@ -1153,7 +1160,7 @@ void DeferredInlineSmiOperation::GenerateNonSmiInput() {
}
// Check that the *signed* result fits in a smi. Not necessary for AND, SAR
// if the shift if more than 0 or SHR if the shit is more than 1.
- if (!( (op_ == Token::AND) ||
+ if (!( (op_ == Token::AND && value_ >= 0) ||
((op_ == Token::SAR) && (shift_value > 0)) ||
((op_ == Token::SHR) && (shift_value > 1)))) {
__ add(r3, int32, Operand(0x40000000), SetCC);
@@ -1414,8 +1421,10 @@ void CodeGenerator::SmiOperation(Token::Value op,
default: UNREACHABLE();
}
deferred->BindExit();
- TypeInfo result_type =
- (op == Token::BIT_AND) ? TypeInfo::Smi() : TypeInfo::Integer32();
+ TypeInfo result_type = TypeInfo::Integer32();
+ if (op == Token::BIT_AND && int_value >= 0) {
+ result_type = TypeInfo::Smi();
+ }
frame_->EmitPush(tos, result_type);
}
break;
@@ -1714,7 +1723,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
// Load applicand.apply onto the stack. This will usually
// give us a megamorphic load site. Not super, but it works.
Load(applicand);
- Handle<String> name = Factory::LookupAsciiSymbol("apply");
+ Handle<String> name = FACTORY->LookupAsciiSymbol("apply");
frame_->Dup();
frame_->CallLoadIC(name, RelocInfo::CODE_TARGET);
frame_->EmitPush(r0);
@@ -1777,7 +1786,8 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
__ JumpIfSmi(r0, &build_args);
__ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE);
__ b(ne, &build_args);
- Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply));
+ Handle<Code> apply_code(
+ Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply));
__ ldr(r1, FieldMemOperand(r0, JSFunction::kCodeEntryOffset));
__ sub(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
__ cmp(r1, Operand(apply_code));
@@ -1992,7 +2002,7 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
// If we have a function or a constant, we need to initialize the variable.
Expression* val = NULL;
if (node->mode() == Variable::CONST) {
- val = new Literal(Factory::the_hole_value());
+ val = new Literal(FACTORY->the_hole_value());
} else {
val = node->fun(); // NULL if we don't have a function
}
@@ -2849,7 +2859,7 @@ void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
function_return_is_shadowed_ = function_return_was_shadowed;
// Get an external reference to the handler address.
- ExternalReference handler_address(Top::k_handler_address);
+ ExternalReference handler_address(Isolate::k_handler_address, isolate());
// If we can fall off the end of the try block, unlink from try chain.
if (has_valid_frame()) {
@@ -2965,7 +2975,7 @@ void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
function_return_is_shadowed_ = function_return_was_shadowed;
// Get an external reference to the handler address.
- ExternalReference handler_address(Top::k_handler_address);
+ ExternalReference handler_address(Isolate::k_handler_address, isolate());
// If we can fall off the end of the try block, unlink from the try
// chain and set the state on the frame to FALLING.
@@ -3106,10 +3116,11 @@ void CodeGenerator::InstantiateFunction(
bool pretenure) {
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
- if (scope()->is_function_scope() &&
- function_info->num_literals() == 0 &&
- !pretenure) {
- FastNewClosureStub stub;
+ if (!pretenure &&
+ scope()->is_function_scope() &&
+ function_info->num_literals() == 0) {
+ FastNewClosureStub stub(
+ function_info->strict_mode() ? kStrictMode : kNonStrictMode);
frame_->EmitPush(Operand(function_info));
frame_->SpillAll();
frame_->CallStub(&stub, 1);
@@ -3119,8 +3130,8 @@ void CodeGenerator::InstantiateFunction(
frame_->EmitPush(cp);
frame_->EmitPush(Operand(function_info));
frame_->EmitPush(Operand(pretenure
- ? Factory::true_value()
- : Factory::false_value()));
+ ? FACTORY->true_value()
+ : FACTORY->false_value()));
frame_->CallRuntime(Runtime::kNewClosure, 3);
frame_->EmitPush(r0);
}
@@ -3620,7 +3631,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
// else fall through
case ObjectLiteral::Property::COMPUTED:
if (key->handle()->IsSymbol()) {
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kStoreIC_Initialize));
Load(value);
if (property->emit_store()) {
frame_->PopToR0();
@@ -3683,11 +3695,12 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
frame_->EmitPush(Operand(Smi::FromInt(node->literal_index())));
frame_->EmitPush(Operand(node->constant_elements()));
int length = node->values()->length();
- if (node->constant_elements()->map() == Heap::fixed_cow_array_map()) {
+ if (node->constant_elements()->map() == HEAP->fixed_cow_array_map()) {
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
frame_->CallStub(&stub, 3);
- __ IncrementCounter(&Counters::cow_arrays_created_stub, 1, r1, r2);
+ __ IncrementCounter(masm_->isolate()->counters()->cow_arrays_created_stub(),
+ 1, r1, r2);
} else if (node->depth() > 1) {
frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
@@ -4243,7 +4256,8 @@ void CodeGenerator::VisitCall(Call* node) {
// Setup the name register and call the IC initialization code.
__ mov(r2, Operand(var->name()));
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> stub = StubCache::ComputeCallInitialize(arg_count, in_loop);
+ Handle<Code> stub =
+ ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop);
CodeForSourcePosition(node->position());
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
arg_count + 1);
@@ -4338,7 +4352,7 @@ void CodeGenerator::VisitCall(Call* node) {
__ mov(r2, Operand(name));
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> stub =
- StubCache::ComputeCallInitialize(arg_count, in_loop);
+ ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop);
CodeForSourcePosition(node->position());
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
__ ldr(cp, frame_->Context());
@@ -4380,7 +4394,8 @@ void CodeGenerator::VisitCall(Call* node) {
// Load the key into r2 and call the IC initialization code.
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> stub =
- StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
+ ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count,
+ in_loop);
CodeForSourcePosition(node->position());
frame_->SpillAll();
__ ldr(r2, frame_->ElementAt(arg_count + 1));
@@ -4445,7 +4460,8 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
// Call the construct call builtin that handles allocation and
// constructor invocation.
CodeForSourcePosition(node->position());
- Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kJSConstructCall));
frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, arg_count + 1);
frame_->EmitPush(r0);
@@ -4494,13 +4510,13 @@ void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
// Functions have class 'Function'.
function.Bind();
- __ mov(tos, Operand(Factory::function_class_symbol()));
+ __ mov(tos, Operand(FACTORY->function_class_symbol()));
frame_->EmitPush(tos);
leave.Jump();
// Objects with a non-function constructor have class 'Object'.
non_function_constructor.Bind();
- __ mov(tos, Operand(Factory::Object_symbol()));
+ __ mov(tos, Operand(FACTORY->Object_symbol()));
frame_->EmitPush(tos);
leave.Jump();
@@ -4601,7 +4617,7 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
Load(args->at(0));
Load(args->at(1));
- if (!CpuFeatures::IsSupported(VFP3)) {
+ if (!Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
frame_->CallRuntime(Runtime::kMath_pow, 2);
frame_->EmitPush(r0);
} else {
@@ -4755,7 +4771,7 @@ void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
- if (!CpuFeatures::IsSupported(VFP3)) {
+ if (!Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
frame_->CallRuntime(Runtime::kMath_sqrt, 1);
frame_->EmitPush(r0);
} else {
@@ -5141,7 +5157,7 @@ class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
Label entry, loop;
// The use of ip to store the valueOf symbol asumes that it is not otherwise
// used in the loop below.
- __ mov(ip, Operand(Factory::value_of_symbol()));
+ __ mov(ip, Operand(FACTORY->value_of_symbol()));
__ jmp(&entry);
__ bind(&loop);
__ ldr(scratch2_, MemOperand(map_result_, 0));
@@ -5344,9 +5360,9 @@ void CodeGenerator::GenerateRandomHeapNumber(
// Convert 32 random bits in r0 to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
__ PrepareCallCFunction(0, r1);
- __ CallCFunction(ExternalReference::random_uint32_function(), 0);
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 0);
CpuFeatures::Scope scope(VFP3);
// 0x41300000 is the top half of 1.0 x 2^20 as a double.
@@ -5367,7 +5383,7 @@ void CodeGenerator::GenerateRandomHeapNumber(
__ mov(r0, Operand(r4));
__ PrepareCallCFunction(1, r1);
__ CallCFunction(
- ExternalReference::fill_heap_number_with_random_function(), 1);
+ ExternalReference::fill_heap_number_with_random_function(isolate()), 1);
frame_->EmitPush(r0);
}
}
@@ -5468,7 +5484,7 @@ void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) {
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
Handle<FixedArray> jsfunction_result_caches(
- Top::global_context()->jsfunction_result_caches());
+ Isolate::Current()->global_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort("Attempt to use undefined cache.");
frame_->EmitPushRoot(Heap::kUndefinedValueRootIndex);
@@ -5578,8 +5594,8 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
// Fetch the map and check if array is in fast case.
// Check that object doesn't require security checks and
// has no indexed interceptor.
- __ CompareObjectType(object, tmp1, tmp2, FIRST_JS_OBJECT_TYPE);
- deferred->Branch(lt);
+ __ CompareObjectType(object, tmp1, tmp2, JS_ARRAY_TYPE);
+ deferred->Branch(ne);
__ ldrb(tmp2, FieldMemOperand(tmp1, Map::kBitFieldOffset));
__ tst(tmp2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
deferred->Branch(ne);
@@ -5658,7 +5674,7 @@ void CodeGenerator::GenerateCallFunction(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
Load(args->at(0));
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::TAGGED);
frame_->SpillAllButCopyTOSToR0();
@@ -5673,7 +5689,7 @@ void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
Load(args->at(0));
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::TAGGED);
frame_->SpillAllButCopyTOSToR0();
@@ -5688,7 +5704,7 @@ void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
Load(args->at(0));
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
TranscendentalCacheStub stub(TranscendentalCache::LOG,
TranscendentalCacheStub::TAGGED);
frame_->SpillAllButCopyTOSToR0();
@@ -5793,7 +5809,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments();
Comment cmnt(masm_, "[ CallRuntime");
- Runtime::Function* function = node->function();
+ const Runtime::Function* function = node->function();
if (function == NULL) {
// Prepare stack for calling JS runtime function.
@@ -5817,7 +5833,8 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
// Call the JS runtime function.
__ mov(r2, Operand(node->name()));
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> stub = StubCache::ComputeCallInitialize(arg_count, in_loop);
+ Handle<Code> stub =
+ ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop);
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
__ ldr(cp, frame_->Context());
frame_->EmitPush(r0);
@@ -6352,7 +6369,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
Register scratch = VirtualFrame::scratch0();
- if (check->Equals(Heap::number_symbol())) {
+ if (check->Equals(HEAP->number_symbol())) {
__ tst(tos, Operand(kSmiTagMask));
true_target()->Branch(eq);
__ ldr(tos, FieldMemOperand(tos, HeapObject::kMapOffset));
@@ -6360,7 +6377,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
__ cmp(tos, ip);
cc_reg_ = eq;
- } else if (check->Equals(Heap::string_symbol())) {
+ } else if (check->Equals(HEAP->string_symbol())) {
__ tst(tos, Operand(kSmiTagMask));
false_target()->Branch(eq);
@@ -6376,7 +6393,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
__ cmp(scratch, Operand(FIRST_NONSTRING_TYPE));
cc_reg_ = lt;
- } else if (check->Equals(Heap::boolean_symbol())) {
+ } else if (check->Equals(HEAP->boolean_symbol())) {
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(tos, ip);
true_target()->Branch(eq);
@@ -6384,7 +6401,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
__ cmp(tos, ip);
cc_reg_ = eq;
- } else if (check->Equals(Heap::undefined_symbol())) {
+ } else if (check->Equals(HEAP->undefined_symbol())) {
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(tos, ip);
true_target()->Branch(eq);
@@ -6400,7 +6417,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
cc_reg_ = eq;
- } else if (check->Equals(Heap::function_symbol())) {
+ } else if (check->Equals(HEAP->function_symbol())) {
__ tst(tos, Operand(kSmiTagMask));
false_target()->Branch(eq);
Register map_reg = scratch;
@@ -6410,7 +6427,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
__ CompareInstanceType(map_reg, tos, JS_REGEXP_TYPE);
cc_reg_ = eq;
- } else if (check->Equals(Heap::object_symbol())) {
+ } else if (check->Equals(HEAP->object_symbol())) {
__ tst(tos, Operand(kSmiTagMask));
false_target()->Branch(eq);
@@ -6572,8 +6589,10 @@ void DeferredReferenceGetNamedValue::Generate() {
Register scratch1 = VirtualFrame::scratch0();
Register scratch2 = VirtualFrame::scratch1();
ASSERT(!receiver_.is(scratch1) && !receiver_.is(scratch2));
- __ DecrementCounter(&Counters::named_load_inline, 1, scratch1, scratch2);
- __ IncrementCounter(&Counters::named_load_inline_miss, 1, scratch1, scratch2);
+ __ DecrementCounter(masm_->isolate()->counters()->named_load_inline(),
+ 1, scratch1, scratch2);
+ __ IncrementCounter(masm_->isolate()->counters()->named_load_inline_miss(),
+ 1, scratch1, scratch2);
// Ensure receiver in r0 and name in r2 to match load ic calling convention.
__ Move(r0, receiver_);
@@ -6581,7 +6600,8 @@ void DeferredReferenceGetNamedValue::Generate() {
// The rest of the instructions in the deferred code must be together.
{ Assembler::BlockConstPoolScope block_const_pool(masm_);
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kLoadIC_Initialize));
RelocInfo::Mode mode = is_contextual_
? RelocInfo::CODE_TARGET_CONTEXT
: RelocInfo::CODE_TARGET;
@@ -6643,8 +6663,10 @@ void DeferredReferenceGetKeyedValue::Generate() {
Register scratch1 = VirtualFrame::scratch0();
Register scratch2 = VirtualFrame::scratch1();
- __ DecrementCounter(&Counters::keyed_load_inline, 1, scratch1, scratch2);
- __ IncrementCounter(&Counters::keyed_load_inline_miss, 1, scratch1, scratch2);
+ __ DecrementCounter(masm_->isolate()->counters()->keyed_load_inline(),
+ 1, scratch1, scratch2);
+ __ IncrementCounter(masm_->isolate()->counters()->keyed_load_inline_miss(),
+ 1, scratch1, scratch2);
// Ensure key in r0 and receiver in r1 to match keyed load ic calling
// convention.
@@ -6655,7 +6677,8 @@ void DeferredReferenceGetKeyedValue::Generate() {
// The rest of the instructions in the deferred code must be together.
{ Assembler::BlockConstPoolScope block_const_pool(masm_);
// Call keyed load IC. It has the arguments key and receiver in r0 and r1.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a nop instruction to indicate that the
// keyed load has been inlined.
@@ -6702,9 +6725,10 @@ class DeferredReferenceSetKeyedValue: public DeferredCode {
void DeferredReferenceSetKeyedValue::Generate() {
Register scratch1 = VirtualFrame::scratch0();
Register scratch2 = VirtualFrame::scratch1();
- __ DecrementCounter(&Counters::keyed_store_inline, 1, scratch1, scratch2);
- __ IncrementCounter(
- &Counters::keyed_store_inline_miss, 1, scratch1, scratch2);
+ __ DecrementCounter(masm_->isolate()->counters()->keyed_store_inline(),
+ 1, scratch1, scratch2);
+ __ IncrementCounter(masm_->isolate()->counters()->keyed_store_inline_miss(),
+ 1, scratch1, scratch2);
// Ensure value in r0, key in r1 and receiver in r2 to match keyed store ic
// calling convention.
@@ -6717,9 +6741,10 @@ void DeferredReferenceSetKeyedValue::Generate() {
{ Assembler::BlockConstPoolScope block_const_pool(masm_);
// Call keyed store IC. It has the arguments value, key and receiver in r0,
// r1 and r2.
- Handle<Code> ic(Builtins::builtin(
- (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ (strict_mode_ == kStrictMode)
+ ? Builtins::kKeyedStoreIC_Initialize_Strict
+ : Builtins::kKeyedStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a nop instruction to indicate that the
// keyed store has been inlined.
@@ -6772,9 +6797,9 @@ void DeferredReferenceSetNamedValue::Generate() {
{ Assembler::BlockConstPoolScope block_const_pool(masm_);
// Call keyed store IC. It has the arguments value, key and receiver in r0,
// r1 and r2.
- Handle<Code> ic(Builtins::builtin(
- (strict_mode_ == kStrictMode) ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ (strict_mode_ == kStrictMode) ? Builtins::kStoreIC_Initialize_Strict
+ : Builtins::kStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a nop instruction to indicate that the
// named store has been inlined.
@@ -6798,7 +6823,7 @@ void DeferredReferenceSetNamedValue::Generate() {
void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
bool contextual_load_in_builtin =
is_contextual &&
- (Bootstrapper::IsActive() ||
+ (ISOLATE->bootstrapper()->IsActive() ||
(!info_->closure().is_null() && info_->closure()->IsBuiltin()));
if (scope()->is_global_scope() ||
@@ -6820,11 +6845,12 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
// Counter will be decremented in the deferred code. Placed here to avoid
// having it in the instruction stream below where patching will occur.
if (is_contextual) {
- __ IncrementCounter(&Counters::named_load_global_inline, 1,
- frame_->scratch0(), frame_->scratch1());
+ __ IncrementCounter(
+ masm_->isolate()->counters()->named_load_global_inline(),
+ 1, frame_->scratch0(), frame_->scratch1());
} else {
- __ IncrementCounter(&Counters::named_load_inline, 1,
- frame_->scratch0(), frame_->scratch1());
+ __ IncrementCounter(masm_->isolate()->counters()->named_load_inline(),
+ 1, frame_->scratch0(), frame_->scratch1());
}
// The following instructions are the inlined load of an in-object property.
@@ -6856,8 +6882,9 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
}
}
if (is_dont_delete) {
- __ IncrementCounter(&Counters::dont_delete_hint_hit, 1,
- frame_->scratch0(), frame_->scratch1());
+ __ IncrementCounter(
+ masm_->isolate()->counters()->dont_delete_hint_hit(),
+ 1, frame_->scratch0(), frame_->scratch1());
}
}
@@ -6893,7 +6920,7 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
// Check the map. The null map used below is patched by the inline cache
// code. Therefore we can't use a LoadRoot call.
__ ldr(scratch, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ mov(scratch2, Operand(Factory::null_value()));
+ __ mov(scratch2, Operand(FACTORY->null_value()));
__ cmp(scratch, scratch2);
deferred->Branch(ne);
@@ -6902,7 +6929,7 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
InlinedNamedLoadInstructions += 1;
#endif
// Load the (initially invalid) cell and get its value.
- masm()->mov(receiver, Operand(Factory::null_value()));
+ masm()->mov(receiver, Operand(FACTORY->null_value()));
__ ldr(receiver,
FieldMemOperand(receiver, JSGlobalPropertyCell::kValueOffset));
@@ -6912,13 +6939,13 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
#ifdef DEBUG
InlinedNamedLoadInstructions += 3;
#endif
- __ cmp(receiver, Operand(Factory::the_hole_value()));
+ __ cmp(receiver, Operand(FACTORY->the_hole_value()));
deferred->Branch(eq);
} else if (FLAG_debug_code) {
#ifdef DEBUG
InlinedNamedLoadInstructions += 3;
#endif
- __ cmp(receiver, Operand(Factory::the_hole_value()));
+ __ cmp(receiver, Operand(FACTORY->the_hole_value()));
__ b(&check_the_hole, eq);
__ bind(&cont);
}
@@ -6986,7 +7013,7 @@ void CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
Label check_inlined_codesize;
masm_->bind(&check_inlined_codesize);
#endif
- __ mov(scratch0, Operand(Factory::null_value()));
+ __ mov(scratch0, Operand(FACTORY->null_value()));
__ cmp(scratch0, scratch1);
deferred->Branch(ne);
@@ -7016,11 +7043,11 @@ void CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
// Check that this is the first inlined write barrier or that
// this inlined write barrier has the same size as all the other
// inlined write barriers.
- ASSERT((inlined_write_barrier_size_ == -1) ||
- (inlined_write_barrier_size_ ==
+ ASSERT((Isolate::Current()->inlined_write_barrier_size() == -1) ||
+ (Isolate::Current()->inlined_write_barrier_size() ==
masm()->InstructionsGeneratedSince(&record_write_start)));
- inlined_write_barrier_size_ =
- masm()->InstructionsGeneratedSince(&record_write_start);
+ Isolate::Current()->set_inlined_write_barrier_size(
+ masm()->InstructionsGeneratedSince(&record_write_start));
// Make sure that the expected number of instructions are generated.
ASSERT_EQ(GetInlinedNamedStoreInstructionsAfterPatch(),
@@ -7042,8 +7069,8 @@ void CodeGenerator::EmitKeyedLoad() {
// Counter will be decremented in the deferred code. Placed here to avoid
// having it in the instruction stream below where patching will occur.
- __ IncrementCounter(&Counters::keyed_load_inline, 1,
- frame_->scratch0(), frame_->scratch1());
+ __ IncrementCounter(masm_->isolate()->counters()->keyed_load_inline(),
+ 1, frame_->scratch0(), frame_->scratch1());
// Load the key and receiver from the stack.
bool key_is_known_smi = frame_->KnownSmiAt(0);
@@ -7079,7 +7106,7 @@ void CodeGenerator::EmitKeyedLoad() {
Label check_inlined_codesize;
masm_->bind(&check_inlined_codesize);
#endif
- __ mov(scratch2, Operand(Factory::null_value()));
+ __ mov(scratch2, Operand(FACTORY->null_value()));
__ cmp(scratch1, scratch2);
deferred->Branch(ne);
@@ -7129,9 +7156,8 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type,
// Counter will be decremented in the deferred code. Placed here to avoid
// having it in the instruction stream below where patching will occur.
- __ IncrementCounter(&Counters::keyed_store_inline, 1,
- scratch1, scratch2);
-
+ __ IncrementCounter(masm_->isolate()->counters()->keyed_store_inline(),
+ 1, scratch1, scratch2);
// Load the value, key and receiver from the stack.
@@ -7181,18 +7207,14 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type,
__ CompareObjectType(receiver, scratch1, scratch1, JS_ARRAY_TYPE);
deferred->Branch(ne);
- // Check that the key is within bounds. Both the key and the length of
- // the JSArray are smis. Use unsigned comparison to handle negative keys.
- __ ldr(scratch1, FieldMemOperand(receiver, JSArray::kLengthOffset));
- __ cmp(scratch1, key);
- deferred->Branch(ls); // Unsigned less equal.
-
// Get the elements array from the receiver.
__ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset));
if (!value_is_harmless && wb_info != LIKELY_SMI) {
Label ok;
- __ and_(scratch2, scratch1, Operand(ExternalReference::new_space_mask()));
- __ cmp(scratch2, Operand(ExternalReference::new_space_start()));
+ __ and_(scratch2,
+ scratch1,
+ Operand(ExternalReference::new_space_mask(isolate())));
+ __ cmp(scratch2, Operand(ExternalReference::new_space_start(isolate())));
__ tst(value, Operand(kSmiTagMask), ne);
deferred->Branch(ne);
#ifdef DEBUG
@@ -7201,6 +7223,7 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type,
}
// Check that the elements array is not a dictionary.
__ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset));
+
// The following instructions are the part of the inlined store keyed
// property code which can be patched. Therefore the exact number of
// instructions generated need to be fixed, so the constant pool is blocked
@@ -7216,10 +7239,18 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type,
// comparison to always fail so that we will hit the IC call in the
// deferred code which will allow the debugger to break for fast case
// stores.
- __ mov(scratch3, Operand(Factory::fixed_array_map()));
+ __ mov(scratch3, Operand(FACTORY->fixed_array_map()));
__ cmp(scratch2, scratch3);
deferred->Branch(ne);
+ // Check that the key is within bounds. Both the key and the length of
+ // the JSArray are smis (because the fixed array check above ensures the
+ // elements are in fast case). Use unsigned comparison to handle negative
+ // keys.
+ __ ldr(scratch3, FieldMemOperand(receiver, JSArray::kLengthOffset));
+ __ cmp(scratch3, key);
+ deferred->Branch(ls); // Unsigned less equal.
+
// Store the value.
__ add(scratch1, scratch1,
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
@@ -7378,7 +7409,7 @@ void Reference::SetValue(InitState init_state, WriteBarrierCharacter wb_info) {
const char* GenericBinaryOpStub::GetName() {
if (name_ != NULL) return name_;
const int len = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(len);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(len);
if (name_ == NULL) return "OOM";
const char* op_name = Token::Name(op_);
const char* overwrite_name;
@@ -7398,7 +7429,6 @@ const char* GenericBinaryOpStub::GetName() {
return name_;
}
-
#undef __
} } // namespace v8::internal
diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h
index 8f46256b..9b1f103d 100644
--- a/src/arm/codegen-arm.h
+++ b/src/arm/codegen-arm.h
@@ -268,10 +268,10 @@ class CodeGenerator: public AstVisitor {
static int GetInlinedKeyedLoadInstructionsAfterPatch() {
return FLAG_debug_code ? 32 : 13;
}
- static const int kInlinedKeyedStoreInstructionsAfterPatch = 5;
+ static const int kInlinedKeyedStoreInstructionsAfterPatch = 8;
static int GetInlinedNamedStoreInstructionsAfterPatch() {
- ASSERT(inlined_write_barrier_size_ != -1);
- return inlined_write_barrier_size_ + 4;
+ ASSERT(Isolate::Current()->inlined_write_barrier_size() != -1);
+ return Isolate::Current()->inlined_write_barrier_size() + 4;
}
private:
@@ -287,6 +287,7 @@ class CodeGenerator: public AstVisitor {
// Accessors
inline bool is_eval();
inline Scope* scope();
+ inline bool is_strict_mode();
inline StrictModeFlag strict_mode_flag();
// Generating deferred code.
@@ -575,15 +576,14 @@ class CodeGenerator: public AstVisitor {
// to some unlinking code).
bool function_return_is_shadowed_;
- // Size of inlined write barriers generated by EmitNamedStore.
- static int inlined_write_barrier_size_;
-
friend class VirtualFrame;
+ friend class Isolate;
friend class JumpTarget;
friend class Reference;
friend class FastCodeGenerator;
friend class FullCodeGenerator;
friend class FullCodeGenSyntaxChecker;
+ friend class InlineRuntimeFunctionsTable;
friend class LCodeGen;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h
index e6033a89..0ac567cb 100644
--- a/src/arm/constants-arm.h
+++ b/src/arm/constants-arm.h
@@ -89,6 +89,11 @@
namespace v8 {
namespace internal {
+// Constant pool marker.
+static const int kConstantPoolMarkerMask = 0xffe00000;
+static const int kConstantPoolMarker = 0x0c000000;
+static const int kConstantPoolLengthMask = 0x001ffff;
+
// Number of registers in normal ARM mode.
static const int kNumRegisters = 16;
@@ -388,9 +393,11 @@ enum VFPConversionMode {
// This mask does not include the "inexact" or "input denormal" cumulative
// exceptions flags, because we usually don't want to check for it.
static const uint32_t kVFPExceptionMask = 0xf;
+static const uint32_t kVFPInvalidOpExceptionBit = 1 << 0;
+static const uint32_t kVFPOverflowExceptionBit = 1 << 2;
+static const uint32_t kVFPUnderflowExceptionBit = 1 << 3;
static const uint32_t kVFPInexactExceptionBit = 1 << 4;
static const uint32_t kVFPFlushToZeroMask = 1 << 24;
-static const uint32_t kVFPInvalidExceptionBit = 1;
static const uint32_t kVFPNConditionFlagBit = 1 << 31;
static const uint32_t kVFPZConditionFlagBit = 1 << 30;
diff --git a/src/arm/cpu-arm.cc b/src/arm/cpu-arm.cc
index 51c84b33..0f5bf56b 100644
--- a/src/arm/cpu-arm.cc
+++ b/src/arm/cpu-arm.cc
@@ -42,8 +42,9 @@ namespace v8 {
namespace internal {
void CPU::Setup() {
- CpuFeatures::Probe(true);
- if (!CpuFeatures::IsSupported(VFP3) || Serializer::enabled()) {
+ CpuFeatures* cpu_features = Isolate::Current()->cpu_features();
+ cpu_features->Probe(true);
+ if (!cpu_features->IsSupported(VFP3) || Serializer::enabled()) {
V8::DisableCrankshaft();
}
}
@@ -61,7 +62,7 @@ void CPU::FlushICache(void* start, size_t size) {
// that the Icache was flushed.
// None of this code ends up in the snapshot so there are no issues
// around whether or not to generate the code when building snapshots.
- Simulator::FlushICache(start, size);
+ Simulator::FlushICache(Isolate::Current()->simulator_i_cache(), start, size);
#else
// Ideally, we would call
// syscall(__ARM_NR_cacheflush, start,
diff --git a/src/arm/debug-arm.cc b/src/arm/debug-arm.cc
index f19e6939..e6ad98cb 100644
--- a/src/arm/debug-arm.cc
+++ b/src/arm/debug-arm.cc
@@ -65,7 +65,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
patcher.masm()->mov(v8::internal::lr, v8::internal::pc);
patcher.masm()->ldr(v8::internal::pc, MemOperand(v8::internal::pc, -4));
#endif
- patcher.Emit(Debug::debug_break_return()->entry());
+ patcher.Emit(Isolate::Current()->debug()->debug_break_return()->entry());
patcher.masm()->bkpt(0);
}
@@ -115,7 +115,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
patcher.masm()->mov(v8::internal::lr, v8::internal::pc);
patcher.masm()->ldr(v8::internal::pc, MemOperand(v8::internal::pc, -4));
#endif
- patcher.Emit(Debug::debug_break_return()->entry());
+ patcher.Emit(Isolate::Current()->debug()->debug_break_slot()->entry());
}
@@ -159,7 +159,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ mov(r0, Operand(0, RelocInfo::NONE)); // no arguments
- __ mov(r1, Operand(ExternalReference::debug_break()));
+ __ mov(r1, Operand(ExternalReference::debug_break(masm->isolate())));
CEntryStub ceb(1);
__ CallStub(&ceb);
@@ -185,7 +185,9 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
// Now that the break point has been handled, resume normal execution by
// jumping to the target address intended by the caller and that was
// overwritten by the address of DebugBreakXXX.
- __ mov(ip, Operand(ExternalReference(Debug_Address::AfterBreakTarget())));
+ ExternalReference after_break_target =
+ ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate());
+ __ mov(ip, Operand(after_break_target));
__ ldr(ip, MemOperand(ip));
__ Jump(ip);
}
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index 9a5aa902..3a3dcf08 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -44,8 +44,14 @@ int Deoptimizer::patch_size() {
}
+void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
+ // Nothing to do. No new relocation information is written for lazy
+ // deoptimization on ARM.
+}
+
void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
+ HandleScope scope;
AssertNoAllocation no_allocation;
if (!function->IsOptimized()) return;
@@ -69,8 +75,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
int deoptimization_index = safepoint_entry.deoptimization_index();
int gap_code_size = safepoint_entry.gap_code_size();
// Check that we did not shoot past next safepoint.
- // TODO(srdjan): How do we guarantee that safepoint code does not
- // overlap other safepoint patching code?
CHECK(pc_offset >= last_pc_offset);
#ifdef DEBUG
// Destroy the code which is not supposed to be run again.
@@ -107,8 +111,9 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
// Add the deoptimizing code to the list.
DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
- node->set_next(deoptimizing_code_list_);
- deoptimizing_code_list_ = node;
+ DeoptimizerData* data = code->GetIsolate()->deoptimizer_data();
+ node->set_next(data->deoptimizing_code_list_);
+ data->deoptimizing_code_list_ = node;
// Set the code for the function to non-optimized version.
function->ReplaceCode(function->shared()->code());
@@ -117,6 +122,11 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
PrintF("[forced deoptimization: ");
function->PrintName();
PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
+#ifdef DEBUG
+ if (FLAG_print_code) {
+ code->PrintLn();
+ }
+#endif
}
}
@@ -278,14 +288,33 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
// There are no translation commands for the caller's pc and fp, the
// context, and the function. Set them up explicitly.
- for (int i = 0; ok && i < 4; i++) {
+ for (int i = StandardFrameConstants::kCallerPCOffset;
+ ok && i >= StandardFrameConstants::kMarkerOffset;
+ i -= kPointerSize) {
uint32_t input_value = input_->GetFrameSlot(input_offset);
if (FLAG_trace_osr) {
- PrintF(" [sp + %d] <- 0x%08x ; [sp + %d] (fixed part)\n",
+ const char* name = "UNKNOWN";
+ switch (i) {
+ case StandardFrameConstants::kCallerPCOffset:
+ name = "caller's pc";
+ break;
+ case StandardFrameConstants::kCallerFPOffset:
+ name = "fp";
+ break;
+ case StandardFrameConstants::kContextOffset:
+ name = "context";
+ break;
+ case StandardFrameConstants::kMarkerOffset:
+ name = "function";
+ break;
+ }
+ PrintF(" [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n",
output_offset,
input_value,
- input_offset);
+ input_offset,
+ name);
}
+
output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
input_offset -= kPointerSize;
output_offset -= kPointerSize;
@@ -311,7 +340,7 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
optimized_code_->entry() + pc_offset);
output_[0]->SetPc(pc);
}
- Code* continuation = Builtins::builtin(Builtins::NotifyOSR);
+ Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR);
output_[0]->SetContinuation(
reinterpret_cast<uint32_t>(continuation->entry()));
@@ -485,11 +514,13 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
FullCodeGenerator::StateField::decode(pc_and_state);
output_frame->SetState(Smi::FromInt(state));
+
// Set the continuation for the topmost frame.
if (is_topmost) {
+ Builtins* builtins = isolate_->builtins();
Code* continuation = (bailout_type_ == EAGER)
- ? Builtins::builtin(Builtins::NotifyDeoptimized)
- : Builtins::builtin(Builtins::NotifyLazyDeoptimized);
+ ? builtins->builtin(Builtins::kNotifyDeoptimized)
+ : builtins->builtin(Builtins::kNotifyLazyDeoptimized);
output_frame->SetContinuation(
reinterpret_cast<uint32_t>(continuation->entry()));
}
@@ -505,6 +536,9 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
// easily ported.
void Deoptimizer::EntryGenerator::Generate() {
GeneratePrologue();
+
+ Isolate* isolate = masm()->isolate();
+
CpuFeatures::Scope scope(VFP3);
// Save all general purpose registers before messing with them.
const int kNumberOfRegisters = Register::kNumRegisters;
@@ -559,7 +593,7 @@ void Deoptimizer::EntryGenerator::Generate() {
// r3: code address or 0 already loaded.
__ str(r4, MemOperand(sp, 0 * kPointerSize)); // Fp-to-sp delta.
// Call Deoptimizer::New().
- __ CallCFunction(ExternalReference::new_deoptimizer_function(), 5);
+ __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 5);
// Preserve "deoptimizer" object in register r0 and get the input
// frame descriptor pointer to r1 (deoptimizer->input_);
@@ -613,7 +647,8 @@ void Deoptimizer::EntryGenerator::Generate() {
// r0: deoptimizer object; r1: scratch.
__ PrepareCallCFunction(1, r1);
// Call Deoptimizer::ComputeOutputFrames().
- __ CallCFunction(ExternalReference::compute_output_frames_function(), 1);
+ __ CallCFunction(
+ ExternalReference::compute_output_frames_function(isolate), 1);
__ pop(r0); // Restore deoptimizer object (class Deoptimizer).
// Replace the current (input) frame with the output frames.
@@ -663,7 +698,7 @@ void Deoptimizer::EntryGenerator::Generate() {
__ pop(ip); // remove lr
// Set up the roots register.
- ExternalReference roots_address = ExternalReference::roots_address();
+ ExternalReference roots_address = ExternalReference::roots_address(isolate);
__ mov(r10, Operand(roots_address));
__ pop(ip); // remove pc
diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc
index 08f605b1..899b88a6 100644
--- a/src/arm/disasm-arm.cc
+++ b/src/arm/disasm-arm.cc
@@ -89,6 +89,9 @@ class Decoder {
// Returns the length of the disassembled machine instruction in bytes.
int InstructionDecode(byte* instruction);
+ static bool IsConstantPoolAt(byte* instr_ptr);
+ static int ConstantPoolSizeAt(byte* instr_ptr);
+
private:
// Bottleneck functions to print into the out_buffer.
void PrintChar(const char ch);
@@ -899,6 +902,7 @@ void Decoder::DecodeType2(Instruction* instr) {
case da_x: {
if (instr->HasW()) {
Unknown(instr); // not used in V8
+ return;
}
Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
break;
@@ -906,6 +910,7 @@ void Decoder::DecodeType2(Instruction* instr) {
case ia_x: {
if (instr->HasW()) {
Unknown(instr); // not used in V8
+ return;
}
Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
break;
@@ -992,11 +997,15 @@ void Decoder::DecodeType3(Instruction* instr) {
void Decoder::DecodeType4(Instruction* instr) {
- ASSERT(instr->Bit(22) == 0); // Privileged mode currently not supported.
- if (instr->HasL()) {
- Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
+ if (instr->Bit(22) != 0) {
+ // Privileged mode currently not supported.
+ Unknown(instr);
} else {
- Format(instr, "stm'cond'pu 'rn'w, 'rlist");
+ if (instr->HasL()) {
+ Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
+ } else {
+ Format(instr, "stm'cond'pu 'rn'w, 'rlist");
+ }
}
}
@@ -1042,6 +1051,8 @@ int Decoder::DecodeType7(Instruction* instr) {
// vmov: Rt = Sn
// vcvt: Dd = Sm
// vcvt: Sd = Dm
+// Dd = vabs(Dm)
+// Dd = vneg(Dm)
// Dd = vadd(Dn, Dm)
// Dd = vsub(Dn, Dm)
// Dd = vmul(Dn, Dm)
@@ -1067,6 +1078,9 @@ void Decoder::DecodeTypeVFP(Instruction* instr) {
} else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
// vabs
Format(instr, "vabs'cond 'Dd, 'Dm");
+ } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
+ // vneg
+ Format(instr, "vneg'cond 'Dd, 'Dm");
} else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
DecodeVCVTBetweenDoubleAndSingle(instr);
} else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
@@ -1294,7 +1308,23 @@ void Decoder::DecodeType6CoprocessorIns(Instruction* instr) {
break;
}
} else {
- UNIMPLEMENTED(); // Not used by V8.
+ Unknown(instr); // Not used by V8.
+ }
+}
+
+
+bool Decoder::IsConstantPoolAt(byte* instr_ptr) {
+ int instruction_bits = *(reinterpret_cast<int*>(instr_ptr));
+ return (instruction_bits & kConstantPoolMarkerMask) == kConstantPoolMarker;
+}
+
+
+int Decoder::ConstantPoolSizeAt(byte* instr_ptr) {
+ if (IsConstantPoolAt(instr_ptr)) {
+ int instruction_bits = *(reinterpret_cast<int*>(instr_ptr));
+ return instruction_bits & kConstantPoolLengthMask;
+ } else {
+ return -1;
}
}
@@ -1307,7 +1337,15 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
"%08x ",
instr->InstructionBits());
if (instr->ConditionField() == kSpecialCondition) {
- UNIMPLEMENTED();
+ Unknown(instr);
+ return Instruction::kInstrSize;
+ }
+ int instruction_bits = *(reinterpret_cast<int*>(instr_ptr));
+ if ((instruction_bits & kConstantPoolMarkerMask) == kConstantPoolMarker) {
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+ "constant pool begin (length %d)",
+ instruction_bits &
+ kConstantPoolLengthMask);
return Instruction::kInstrSize;
}
switch (instr->TypeValue()) {
@@ -1359,9 +1397,8 @@ namespace disasm {
const char* NameConverter::NameOfAddress(byte* addr) const {
- static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
- v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
- return tmp_buffer.start();
+ v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
+ return tmp_buffer_.start();
}
@@ -1411,12 +1448,7 @@ int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
int Disassembler::ConstantPoolSizeAt(byte* instruction) {
- int instruction_bits = *(reinterpret_cast<int*>(instruction));
- if ((instruction_bits & 0xfff00000) == 0x03000000) {
- return instruction_bits & 0x0000ffff;
- } else {
- return -1;
- }
+ return v8::internal::Decoder::ConstantPoolSizeAt(instruction);
}
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 5f5de3a9..088ba583 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -210,13 +210,18 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// function, receiver address, parameter count.
// The stub will rewrite receiever and parameter count if the previous
// stack frame was an arguments adapter frame.
- ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+ ArgumentsAccessStub stub(
+ is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
+ : ArgumentsAccessStub::NEW_NON_STRICT);
__ CallStub(&stub);
- // Duplicate the value; move-to-slot operation might clobber registers.
- __ mov(r3, r0);
+
+ Variable* arguments_shadow = scope()->arguments_shadow();
+ if (arguments_shadow != NULL) {
+ // Duplicate the value; move-to-slot operation might clobber registers.
+ __ mov(r3, r0);
+ Move(arguments_shadow->AsSlot(), r3, r1, r2);
+ }
Move(arguments->AsSlot(), r0, r1, r2);
- Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
- Move(dot_arguments_slot, r3, r1, r2);
}
if (FLAG_trace) {
@@ -557,7 +562,7 @@ void FullCodeGenerator::TestContext::Plug(bool flag) const {
void FullCodeGenerator::DoTest(Label* if_true,
Label* if_false,
Label* fall_through) {
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Emit the inlined tests assumed by the stub.
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
@@ -776,9 +781,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
prop->key()->AsLiteral()->handle()->IsSmi());
__ mov(r1, Operand(prop->key()->AsLiteral()->handle()));
- Handle<Code> ic(Builtins::builtin(is_strict()
- ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Value in r0 is ignored (declarations are statements).
}
@@ -875,6 +880,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
Comment cmnt(masm_, "[ Case body");
CaseClause* clause = clauses->at(i);
__ bind(clause->body_target()->entry_label());
+ PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
VisitStatements(clause->statements());
}
@@ -1080,10 +1086,10 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
// doesn't just get a copy of the existing unoptimized code.
if (!FLAG_always_opt &&
!FLAG_prepare_always_opt &&
+ !pretenure &&
scope()->is_function_scope() &&
- info->num_literals() == 0 &&
- !pretenure) {
- FastNewClosureStub stub;
+ info->num_literals() == 0) {
+ FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
__ mov(r0, Operand(info));
__ push(r0);
__ CallStub(&stub);
@@ -1180,7 +1186,8 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
slow));
__ mov(r0, Operand(key_literal->handle()));
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic =
+ isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
__ jmp(done);
}
@@ -1246,7 +1253,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, mode);
}
@@ -1264,7 +1271,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
// object (receiver) in r0.
__ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(var->name()));
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(r0);
@@ -1323,7 +1330,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
__ mov(r0, Operand(key_literal->handle()));
// Call keyed load IC. It has arguments key and receiver in r0 and r1.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
context()->Plug(r0);
}
@@ -1387,7 +1394,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
__ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
__ mov(r1, Operand(expr->constant_properties()));
- __ mov(r0, Operand(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
+ int flags = expr->fast_elements()
+ ? ObjectLiteral::kFastElements
+ : ObjectLiteral::kNoFlags;
+ flags |= expr->has_function()
+ ? ObjectLiteral::kHasFunction
+ : ObjectLiteral::kNoFlags;
+ __ mov(r0, Operand(Smi::FromInt(flags)));
__ Push(r3, r2, r1, r0);
if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateObjectLiteral, 4);
@@ -1426,7 +1439,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
VisitForAccumulatorValue(value);
__ mov(r2, Operand(key->handle()));
__ ldr(r1, MemOperand(sp));
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else {
@@ -1465,6 +1478,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
}
+ if (expr->has_function()) {
+ ASSERT(result_saved);
+ __ ldr(r0, MemOperand(sp));
+ __ push(r0);
+ __ CallRuntime(Runtime::kToFastProperties, 1);
+ }
+
if (result_saved) {
context()->PlugTOS();
} else {
@@ -1484,11 +1504,13 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
__ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
__ mov(r1, Operand(expr->constant_elements()));
__ Push(r3, r2, r1);
- if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
+ if (expr->constant_elements()->map() ==
+ isolate()->heap()->fixed_cow_array_map()) {
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
__ CallStub(&stub);
- __ IncrementCounter(&Counters::cow_arrays_created_stub, 1, r1, r2);
+ __ IncrementCounter(
+ isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2);
} else if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
@@ -1672,7 +1694,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
Literal* key = prop->key()->AsLiteral();
__ mov(r2, Operand(key->handle()));
// Call load IC. It has arguments receiver and property name r0 and r2.
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
}
@@ -1680,7 +1702,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
// Call keyed load IC. It has arguments key and receiver in r0 and r1.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
}
@@ -1825,9 +1847,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
__ mov(r1, r0);
__ pop(r0); // Restore value.
__ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
break;
}
@@ -1848,9 +1870,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
__ pop(r2);
}
__ pop(r0); // Restore value.
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
break;
}
@@ -1874,9 +1896,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// r2, and the global object in r1.
__ mov(r2, Operand(var->name()));
__ ldr(r1, GlobalObjectOperand());
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
@@ -1983,9 +2005,9 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
__ pop(r1);
}
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// If the assignment ends an initialization block, revert to fast case.
@@ -2029,9 +2051,9 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
__ pop(r2);
}
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// If the assignment ends an initialization block, revert to fast case.
@@ -2082,7 +2104,8 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
SetSourcePosition(expr->position());
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop);
EmitCallIC(ic, mode);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2115,7 +2138,8 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
SetSourcePosition(expr->position());
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
__ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, mode);
RecordJSReturnSite(expr);
@@ -2314,7 +2338,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Record source code position for IC call.
SetSourcePosition(prop->position());
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
__ ldr(r1, GlobalObjectOperand());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
@@ -2333,7 +2357,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// also use the fast code generator.
FunctionLiteral* lit = fun->AsFunctionLiteral();
if (lit != NULL &&
- lit->name()->Equals(Heap::empty_string()) &&
+ lit->name()->Equals(isolate()->heap()->empty_string()) &&
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
@@ -2382,7 +2406,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ mov(r0, Operand(arg_count));
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
- Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> construct_builtin =
+ isolate()->builtins()->JSConstructCall();
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
context()->Plug(r0);
}
@@ -2777,9 +2802,9 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
// Convert 32 random bits in r0 to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (isolate()->cpu_features()->IsSupported(VFP3)) {
__ PrepareCallCFunction(0, r1);
- __ CallCFunction(ExternalReference::random_uint32_function(), 0);
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 0);
CpuFeatures::Scope scope(VFP3);
// 0x41300000 is the top half of 1.0 x 2^20 as a double.
@@ -2800,7 +2825,7 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
__ mov(r0, Operand(r4));
__ PrepareCallCFunction(1, r1);
__ CallCFunction(
- ExternalReference::fill_heap_number_with_random_function(), 1);
+ ExternalReference::fill_heap_number_with_random_function(isolate()), 1);
}
context()->Plug(r0);
@@ -2855,7 +2880,8 @@ void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
- __ CallRuntime(Runtime::kMath_pow, 2);
+ MathPowStub stub;
+ __ CallStub(&stub);
context()->Plug(r0);
}
@@ -3126,8 +3152,8 @@ void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
// Fetch the map and check if array is in fast case.
// Check that object doesn't require security checks and
// has no indexed interceptor.
- __ CompareObjectType(object, scratch1, scratch2, FIRST_JS_OBJECT_TYPE);
- __ b(lt, &slow_case);
+ __ CompareObjectType(object, scratch1, scratch2, JS_ARRAY_TYPE);
+ __ b(ne, &slow_case);
// Map is now in scratch1.
__ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
@@ -3197,7 +3223,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
Handle<FixedArray> jsfunction_result_caches(
- Top::global_context()->jsfunction_result_caches());
+ isolate()->global_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort("Attempt to use undefined cache.");
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
@@ -3576,7 +3602,8 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
if (expr->is_jsruntime()) {
// Call the JS runtime function.
__ mov(r2, Operand(expr->name()));
- Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, NOT_IN_LOOP);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, NOT_IN_LOOP);
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3880,9 +3907,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
case NAMED_PROPERTY: {
__ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
__ pop(r1);
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -3897,9 +3924,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
case KEYED_PROPERTY: {
__ pop(r1); // Key.
__ pop(r2); // Receiver.
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -3923,7 +3950,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Comment cmnt(masm_, "Global variable");
__ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(proxy->name()));
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference
// error.
EmitCallIC(ic, RelocInfo::CODE_TARGET);
@@ -3976,13 +4003,13 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
}
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- if (check->Equals(Heap::number_symbol())) {
+ if (check->Equals(isolate()->heap()->number_symbol())) {
__ JumpIfSmi(r0, if_true);
__ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
__ cmp(r0, ip);
Split(eq, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::string_symbol())) {
+ } else if (check->Equals(isolate()->heap()->string_symbol())) {
__ JumpIfSmi(r0, if_false);
// Check for undetectable objects => false.
__ CompareObjectType(r0, r0, r1, FIRST_NONSTRING_TYPE);
@@ -3990,12 +4017,12 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
__ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
__ tst(r1, Operand(1 << Map::kIsUndetectable));
Split(eq, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::boolean_symbol())) {
+ } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
__ CompareRoot(r0, Heap::kTrueValueRootIndex);
__ b(eq, if_true);
__ CompareRoot(r0, Heap::kFalseValueRootIndex);
Split(eq, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::undefined_symbol())) {
+ } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
__ b(eq, if_true);
__ JumpIfSmi(r0, if_false);
@@ -4005,12 +4032,12 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
__ tst(r1, Operand(1 << Map::kIsUndetectable));
Split(ne, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::function_symbol())) {
+ } else if (check->Equals(isolate()->heap()->function_symbol())) {
__ JumpIfSmi(r0, if_false);
__ CompareObjectType(r0, r1, r0, FIRST_FUNCTION_CLASS_TYPE);
Split(ge, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::object_symbol())) {
+ } else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(r0, if_false);
__ CompareRoot(r0, Heap::kNullValueRootIndex);
__ b(eq, if_true);
@@ -4194,18 +4221,19 @@ Register FullCodeGenerator::context_register() {
void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
ASSERT(mode == RelocInfo::CODE_TARGET ||
mode == RelocInfo::CODE_TARGET_CONTEXT);
+ Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
- __ IncrementCounter(&Counters::named_load_full, 1, r1, r2);
+ __ IncrementCounter(counters->named_load_full(), 1, r1, r2);
break;
case Code::KEYED_LOAD_IC:
- __ IncrementCounter(&Counters::keyed_load_full, 1, r1, r2);
+ __ IncrementCounter(counters->keyed_load_full(), 1, r1, r2);
break;
case Code::STORE_IC:
- __ IncrementCounter(&Counters::named_store_full, 1, r1, r2);
+ __ IncrementCounter(counters->named_store_full(), 1, r1, r2);
break;
case Code::KEYED_STORE_IC:
- __ IncrementCounter(&Counters::keyed_store_full, 1, r1, r2);
+ __ IncrementCounter(counters->keyed_store_full(), 1, r1, r2);
default:
break;
}
@@ -4215,18 +4243,19 @@ void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
+ Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
- __ IncrementCounter(&Counters::named_load_full, 1, r1, r2);
+ __ IncrementCounter(counters->named_load_full(), 1, r1, r2);
break;
case Code::KEYED_LOAD_IC:
- __ IncrementCounter(&Counters::keyed_load_full, 1, r1, r2);
+ __ IncrementCounter(counters->keyed_load_full(), 1, r1, r2);
break;
case Code::STORE_IC:
- __ IncrementCounter(&Counters::named_store_full, 1, r1, r2);
+ __ IncrementCounter(counters->named_store_full(), 1, r1, r2);
break;
case Code::KEYED_STORE_IC:
- __ IncrementCounter(&Counters::keyed_store_full, 1, r1, r2);
+ __ IncrementCounter(counters->keyed_store_full(), 1, r1, r2);
default:
break;
}
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 0fc68187..dc4f761d 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -552,7 +552,8 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
Code::kNoExtraICState,
NORMAL,
argc);
- StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
+ Isolate::Current()->stub_cache()->GenerateProbe(
+ masm, flags, r1, r2, r3, r4, r5);
// If the stub cache probing failed, the receiver might be a value.
// For value objects, we use the map of the prototype objects for
@@ -591,7 +592,8 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Probe the stub cache for the value object.
__ bind(&probe);
- StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
+ Isolate::Current()->stub_cache()->GenerateProbe(
+ masm, flags, r1, r2, r3, r4, r5);
__ bind(&miss);
}
@@ -644,11 +646,12 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
// -- r2 : name
// -- lr : return address
// -----------------------------------
+ Isolate* isolate = masm->isolate();
if (id == IC::kCallIC_Miss) {
- __ IncrementCounter(&Counters::call_miss, 1, r3, r4);
+ __ IncrementCounter(isolate->counters()->call_miss(), 1, r3, r4);
} else {
- __ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
+ __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, r3, r4);
}
// Get the receiver of the function from the stack.
@@ -661,7 +664,7 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
// Call the entry.
__ mov(r0, Operand(2));
- __ mov(r1, Operand(ExternalReference(IC_Utility(id))));
+ __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate)));
CEntryStub stub(1);
__ CallStub(&stub);
@@ -763,7 +766,8 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
GenerateFastArrayLoad(
masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
- __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, r0, r3);
__ bind(&do_call);
// receiver in r1 is not used after this point.
@@ -782,13 +786,13 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
__ mov(r0, Operand(r2, ASR, kSmiTagSize));
// r0: untagged index
GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5);
- __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1, r0, r3);
+ __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3);
__ jmp(&do_call);
__ bind(&slow_load);
// This branch is taken when calling KeyedCallIC_Miss is neither required
// nor beneficial.
- __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1, r0, r3);
+ __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3);
__ EnterInternalFrame();
__ push(r2); // save the key
__ Push(r1, r2); // pass the receiver and the key
@@ -815,11 +819,11 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
__ b(ne, &lookup_monomorphic_cache);
GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
- __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
+ __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, r0, r3);
__ jmp(&do_call);
__ bind(&lookup_monomorphic_cache);
- __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3);
+ __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, r0, r3);
GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
// Fall through on miss.
@@ -830,7 +834,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// - the value loaded is not a function,
// - there is hope that the runtime will create a monomorphic call stub
// that will get fetched next time.
- __ IncrementCounter(&Counters::keyed_call_generic_slow, 1, r0, r3);
+ __ IncrementCounter(counters->keyed_call_generic_slow(), 1, r0, r3);
GenerateMiss(masm, argc);
__ bind(&index_string);
@@ -873,7 +877,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
NOT_IN_LOOP,
MONOMORPHIC);
- StubCache::GenerateProbe(masm, flags, r0, r2, r3, r4, r5);
+ Isolate::Current()->stub_cache()->GenerateProbe(
+ masm, flags, r0, r2, r3, r4, r5);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -908,14 +913,16 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
// -- r0 : receiver
// -- sp[0] : receiver
// -----------------------------------
+ Isolate* isolate = masm->isolate();
- __ IncrementCounter(&Counters::load_miss, 1, r3, r4);
+ __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
__ mov(r3, r0);
__ Push(r3, r2);
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
__ TailCallExternalReference(ref, 2, 1);
}
@@ -961,7 +968,7 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
// Find the end of the inlined code for handling the load if this is an
// inlined IC call site.
- Address inline_end_address;
+ Address inline_end_address = 0;
if (InlinedICSiteMarker(address, &inline_end_address)
!= Assembler::PROPERTY_ACCESS_INLINED) {
return false;
@@ -1001,7 +1008,7 @@ bool LoadIC::PatchInlinedContextualLoad(Address address,
bool is_dont_delete) {
// Find the end of the inlined code for handling the contextual load if
// this is inlined IC call site.
- Address inline_end_address;
+ Address inline_end_address = 0;
int marker = InlinedICSiteMarker(address, &inline_end_address);
if (!((marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT) ||
(marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE))) {
@@ -1042,7 +1049,7 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
// Find the end of the inlined code for the store if there is an
// inlined version of the store.
- Address inline_end_address;
+ Address inline_end_address = 0;
if (InlinedICSiteMarker(address, &inline_end_address)
!= Assembler::PROPERTY_ACCESS_INLINED) {
return false;
@@ -1057,7 +1064,7 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
// Update the offsets if initializing the inlined store. No reason
// to update the offsets when clearing the inlined version because
// it will bail out in the map check.
- if (map != Heap::null_value()) {
+ if (map != HEAP->null_value()) {
// Patch the offset in the actual store instruction.
Address str_property_instr_address =
ldr_map_instr_address + 3 * Assembler::kInstrSize;
@@ -1092,7 +1099,7 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
if (V8::UseCrankshaft()) return false;
- Address inline_end_address;
+ Address inline_end_address = 0;
if (InlinedICSiteMarker(address, &inline_end_address)
!= Assembler::PROPERTY_ACCESS_INLINED) {
return false;
@@ -1114,7 +1121,7 @@ bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
// Find the end of the inlined code for handling the store if this is an
// inlined IC call site.
- Address inline_end_address;
+ Address inline_end_address = 0;
if (InlinedICSiteMarker(address, &inline_end_address)
!= Assembler::PROPERTY_ACCESS_INLINED) {
return false;
@@ -1140,12 +1147,14 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
+ Isolate* isolate = masm->isolate();
- __ IncrementCounter(&Counters::keyed_load_miss, 1, r3, r4);
+ __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
__ Push(r1, r0);
- ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
__ TailCallExternalReference(ref, 2, 1);
}
@@ -1170,11 +1179,13 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// -- r1 : receiver
// -----------------------------------
Label slow, check_string, index_smi, index_string, property_array_property;
- Label check_pixel_array, probe_dictionary, check_number_dictionary;
+ Label probe_dictionary, check_number_dictionary;
Register key = r0;
Register receiver = r1;
+ Isolate* isolate = masm->isolate();
+
// Check that the key is a smi.
__ JumpIfNotSmi(key, &check_string);
__ bind(&index_smi);
@@ -1188,31 +1199,17 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// now in r2.
__ ldrb(r3, FieldMemOperand(r2, Map::kBitField2Offset));
__ tst(r3, Operand(1 << Map::kHasFastElements));
- __ b(eq, &check_pixel_array);
+ __ b(eq, &check_number_dictionary);
GenerateFastArrayLoad(
masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
- __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
+ __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r2, r3);
__ Ret();
- // Check whether the elements is a pixel array.
- // r0: key
- // r1: receiver
- __ bind(&check_pixel_array);
-
- GenerateFastPixelArrayLoad(masm,
- r1,
- r0,
- r3,
- r4,
- r2,
- r5,
- r0,
- &check_number_dictionary,
- NULL,
- &slow);
-
__ bind(&check_number_dictionary);
+ __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
+ __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset));
+
// Check whether the elements is a number dictionary.
// r0: key
// r3: elements map
@@ -1226,7 +1223,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Slow case, key and receiver still in r0 and r1.
__ bind(&slow);
- __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
+ __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
+ 1, r2, r3);
GenerateRuntimeGetProperty(masm);
__ bind(&check_string);
@@ -1253,7 +1251,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Load the key (consisting of map and symbol) from the cache and
// check for match.
- ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys();
+ ExternalReference cache_keys =
+ ExternalReference::keyed_lookup_cache_keys(isolate);
__ mov(r4, Operand(cache_keys));
__ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
__ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol.
@@ -1268,8 +1267,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// r1 : receiver
// r2 : receiver's map
// r3 : lookup cache index
- ExternalReference cache_field_offsets
- = ExternalReference::keyed_lookup_cache_field_offsets();
+ ExternalReference cache_field_offsets =
+ ExternalReference::keyed_lookup_cache_field_offsets(isolate);
__ mov(r4, Operand(cache_field_offsets));
__ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
__ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
@@ -1281,7 +1280,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ add(r6, r6, r5); // Index from start of object.
__ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
__ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
- __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
+ __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
+ 1, r2, r3);
__ Ret();
// Load property array property.
@@ -1289,7 +1289,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
__ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
- __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
+ __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
+ 1, r2, r3);
__ Ret();
// Do a quick inline probe of the receiver's dictionary, if it
@@ -1303,7 +1304,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
// Load the property to r0.
GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
- __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
+ __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
+ 1, r2, r3);
__ Ret();
__ bind(&index_string);
@@ -1376,8 +1378,11 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
__ Push(r1, r0); // Receiver, key.
// Perform tail call to the entry.
- __ TailCallExternalReference(ExternalReference(
- IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
+ __ TailCallExternalReference(
+ ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
+ masm->isolate()),
+ 2,
+ 1);
__ bind(&slow);
GenerateMiss(masm);
@@ -1395,7 +1400,8 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// Push receiver, key and value for runtime call.
__ Push(r2, r1, r0);
- ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
@@ -1428,7 +1434,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// -- r2 : receiver
// -- lr : return address
// -----------------------------------
- Label slow, fast, array, extra, check_pixel_array;
+ Label slow, fast, array, extra;
// Register usage.
Register value = r0;
@@ -1464,7 +1470,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
__ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
__ cmp(r4, ip);
- __ b(ne, &check_pixel_array);
+ __ b(ne, &slow);
// Check array bounds. Both the key and the length of FixedArray are smis.
__ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
__ cmp(key, Operand(ip));
@@ -1478,24 +1484,6 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// r2: receiver.
GenerateRuntimeSetProperty(masm, strict_mode);
- // Check whether the elements is a pixel array.
- // r4: elements map.
- __ bind(&check_pixel_array);
- GenerateFastPixelArrayStore(masm,
- r2,
- r1,
- r0,
- elements,
- r4,
- r5,
- r6,
- false,
- false,
- NULL,
- &slow,
- &slow,
- &slow);
-
// Extra capacity case: Check if there is extra capacity to
// perform the store and update the length. Used for adding one
// element to the array by writing to array[array.length].
@@ -1559,7 +1547,9 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
NOT_IN_LOOP,
MONOMORPHIC,
strict_mode);
- StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
+
+ Isolate::Current()->stub_cache()->GenerateProbe(
+ masm, flags, r1, r2, r3, r4, r5);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -1577,7 +1567,8 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
__ Push(r1, r2, r0);
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
@@ -1622,7 +1613,8 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
// Prepare tail call to StoreIC_ArrayLength.
__ Push(receiver, value);
- ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
__ bind(&miss);
@@ -1643,11 +1635,13 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
- __ IncrementCounter(&Counters::store_normal_hit, 1, r4, r5);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->store_normal_hit(),
+ 1, r4, r5);
__ Ret();
__ bind(&miss);
- __ IncrementCounter(&Counters::store_normal_miss, 1, r4, r5);
+ __ IncrementCounter(counters->store_normal_miss(), 1, r4, r5);
GenerateMiss(masm);
}
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index e79465cb..5d314734 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "v8.h"
+
#include "lithium-allocator-inl.h"
#include "arm/lithium-arm.h"
#include "arm/lithium-codegen-arm.h"
@@ -1230,8 +1232,7 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
case kMathRound:
return AssignEnvironment(DefineAsRegister(result));
case kMathPowHalf:
- Abort("MathPowHalf LUnaryMathOperation not implemented");
- return NULL;
+ return DefineSameAsFirst(result);
default:
UNREACHABLE();
return NULL;
@@ -1344,18 +1345,25 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsInteger32()) {
- // TODO(1042) The fixed register allocation
- // is needed because we call GenericBinaryOpStub from
- // the generated code, which requires registers r0
- // and r1 to be used. We should remove that
- // when we provide a native implementation.
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
- LOperand* value = UseFixed(instr->left(), r0);
- LOperand* divisor = UseFixed(instr->right(), r1);
- LInstruction* result = DefineFixed(new LModI(value, divisor), r0);
- result = AssignEnvironment(AssignPointerMap(result));
- return result;
+
+ LModI* mod;
+ if (instr->HasPowerOf2Divisor()) {
+ ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
+ LOperand* value = UseRegisterAtStart(instr->left());
+ mod = new LModI(value, UseOrConstant(instr->right()));
+ } else {
+ LOperand* dividend = UseRegister(instr->left());
+ LOperand* divisor = UseRegisterAtStart(instr->right());
+ mod = new LModI(dividend,
+ divisor,
+ TempRegister(),
+ FixedTemp(d1),
+ FixedTemp(d2));
+ }
+
+ return AssignEnvironment(DefineSameAsFirst(mod));
} else if (instr->representation().IsTagged()) {
return DoArithmeticT(Token::MOD, instr);
} else {
@@ -1548,9 +1556,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
-LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) {
+LInstruction* LChunkBuilder::DoExternalArrayLength(
+ HExternalArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LPixelArrayLength(array));
+ return DefineAsRegister(new LExternalArrayLength(array));
}
@@ -1599,12 +1608,15 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
LOperand* value = UseRegister(instr->value());
bool needs_check = !instr->value()->type().IsSmi();
LInstruction* res = NULL;
- if (needs_check) {
- res = DefineSameAsFirst(new LTaggedToI(value, FixedTemp(d1)));
- } else {
+ if (!needs_check) {
res = DefineSameAsFirst(new LSmiUntag(value, needs_check));
- }
- if (needs_check) {
+ } else {
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
+ : NULL;
+ LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d3)
+ : NULL;
+ res = DefineSameAsFirst(new LTaggedToI(value, temp1, temp2, temp3));
res = AssignEnvironment(res);
}
return res;
@@ -1624,7 +1636,10 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} else {
ASSERT(to.IsInteger32());
LOperand* value = UseRegister(instr->value());
- LDoubleToI* res = new LDoubleToI(value, TempRegister());
+ LDoubleToI* res =
+ new LDoubleToI(value,
+ TempRegister(),
+ instr->CanTruncateToInt32() ? TempRegister() : NULL);
return AssignEnvironment(DefineAsRegister(res));
}
} else if (from.IsInteger32()) {
@@ -1650,7 +1665,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
- return AssignEnvironment(new LCheckSmi(value, eq));
+ return AssignEnvironment(new LCheckNonSmi(value));
}
@@ -1671,7 +1686,7 @@ LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
- return AssignEnvironment(new LCheckSmi(value, ne));
+ return AssignEnvironment(new LCheckSmi(value));
}
@@ -1754,6 +1769,21 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
}
+LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
+ HLoadNamedFieldPolymorphic* instr) {
+ ASSERT(instr->representation().IsTagged());
+ if (instr->need_generic()) {
+ LOperand* obj = UseFixed(instr->object(), r0);
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return MarkAsCall(DefineFixed(result, r0), instr);
+ } else {
+ LOperand* obj = UseRegisterAtStart(instr->object());
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return AssignEnvironment(DefineAsRegister(result));
+ }
+}
+
+
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
LOperand* object = UseFixed(instr->object(), r0);
LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), r0);
@@ -1774,10 +1804,10 @@ LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
}
-LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer(
- HLoadPixelArrayExternalPointer* instr) {
+LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
+ HLoadExternalArrayPointer* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LLoadPixelArrayExternalPointer(input));
+ return DefineAsRegister(new LLoadExternalArrayPointer(input));
}
@@ -1792,15 +1822,22 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
}
-LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
- HLoadPixelArrayElement* instr) {
+LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
+ HLoadKeyedSpecializedArrayElement* instr) {
+ // TODO(danno): Add support for other external array types.
+ if (instr->array_type() != kExternalPixelArray) {
+ Abort("unsupported load for external array type.");
+ return NULL;
+ }
+
ASSERT(instr->representation().IsInteger32());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer =
UseRegisterAtStart(instr->external_pointer());
LOperand* key = UseRegisterAtStart(instr->key());
- LLoadPixelArrayElement* result =
- new LLoadPixelArrayElement(external_pointer, key);
+ LLoadKeyedSpecializedArrayElement* result =
+ new LLoadKeyedSpecializedArrayElement(external_pointer,
+ key);
return DefineAsRegister(result);
}
@@ -1834,10 +1871,25 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
}
-LInstruction* LChunkBuilder::DoStorePixelArrayElement(
- HStorePixelArrayElement* instr) {
- Abort("DoStorePixelArrayElement not implemented");
- return NULL;
+LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
+ HStoreKeyedSpecializedArrayElement* instr) {
+ // TODO(danno): Add support for other external array types.
+ if (instr->array_type() != kExternalPixelArray) {
+ Abort("unsupported store for external array type.");
+ return NULL;
+ }
+
+ ASSERT(instr->value()->representation().IsInteger32());
+ ASSERT(instr->external_pointer()->representation().IsExternal());
+ ASSERT(instr->key()->representation().IsInteger32());
+
+ LOperand* external_pointer = UseRegister(instr->external_pointer());
+ LOperand* value = UseTempRegister(instr->value()); // changed by clamp.
+ LOperand* key = UseRegister(instr->key());
+
+ return new LStoreKeyedSpecializedArrayElement(external_pointer,
+ key,
+ value);
}
@@ -1886,6 +1938,13 @@ LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
}
+LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
+ LOperand* char_code = UseRegister(instr->value());
+ LStringCharFromCode* result = new LStringCharFromCode(char_code);
+ return AssignPointerMap(DefineAsRegister(result));
+}
+
+
LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
LOperand* string = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LStringLength(string));
@@ -1963,6 +2022,13 @@ LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
}
+LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
+ LOperand* object = UseFixed(instr->value(), r0);
+ LToFastProperties* result = new LToFastProperties(object);
+ return MarkAsCall(DefineFixed(result, r0), instr);
+}
+
+
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
LTypeof* result = new LTypeof(UseFixed(instr->value(), r0));
return MarkAsCall(DefineFixed(result, r0), instr);
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 9cbcc3b9..77aabaf7 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -69,6 +69,7 @@ class LCodeGen;
V(CallStub) \
V(CheckFunction) \
V(CheckInstanceType) \
+ V(CheckNonSmi) \
V(CheckMap) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
@@ -89,6 +90,7 @@ class LCodeGen;
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
+ V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \
V(Gap) \
@@ -115,14 +117,15 @@ class LCodeGen;
V(LazyBailout) \
V(LoadContextSlot) \
V(LoadElements) \
+ V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
+ V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
+ V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
- V(LoadPixelArrayElement) \
- V(LoadPixelArrayExternalPointer) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@@ -132,7 +135,6 @@ class LCodeGen;
V(OsrEntry) \
V(OuterContext) \
V(Parameter) \
- V(PixelArrayLength) \
V(Power) \
V(PushArgument) \
V(RegExpLiteral) \
@@ -145,13 +147,16 @@ class LCodeGen;
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
+ V(StoreKeyedSpecializedArrayElement) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(StringCharCodeAt) \
+ V(StringCharFromCode) \
V(StringLength) \
V(SubI) \
V(TaggedToI) \
V(Throw) \
+ V(ToFastProperties) \
V(Typeof) \
V(TypeofIs) \
V(TypeofIsAndBranch) \
@@ -519,11 +524,29 @@ class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
};
-class LModI: public LTemplateInstruction<1, 2, 0> {
+class LModI: public LTemplateInstruction<1, 2, 3> {
public:
- LModI(LOperand* left, LOperand* right) {
+ // Used when the right hand is a constant power of 2.
+ LModI(LOperand* left,
+ LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
+ temps_[0] = NULL;
+ temps_[1] = NULL;
+ temps_[2] = NULL;
+ }
+
+ // Used for the standard case.
+ LModI(LOperand* left,
+ LOperand* right,
+ LOperand* temp1,
+ LOperand* temp2,
+ LOperand* temp3) {
+ inputs_[0] = left;
+ inputs_[1] = right;
+ temps_[0] = temp1;
+ temps_[1] = temp2;
+ temps_[2] = temp3;
}
DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i")
@@ -991,14 +1014,14 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
};
-class LPixelArrayLength: public LTemplateInstruction<1, 1, 0> {
+class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LPixelArrayLength(LOperand* value) {
+ explicit LExternalArrayLength(LOperand* value) {
inputs_[0] = value;
}
- DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel-array-length")
- DECLARE_HYDROGEN_ACCESSOR(PixelArrayLength)
+ DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
+ DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
};
@@ -1126,6 +1149,19 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> {
};
+class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LLoadNamedFieldPolymorphic(LOperand* object) {
+ inputs_[0] = object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic")
+ DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic)
+
+ LOperand* object() { return inputs_[0]; }
+};
+
+
class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadNamedGeneric(LOperand* object) {
@@ -1163,14 +1199,14 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> {
};
-class LLoadPixelArrayExternalPointer: public LTemplateInstruction<1, 1, 0> {
+class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LLoadPixelArrayExternalPointer(LOperand* object) {
+ explicit LLoadExternalArrayPointer(LOperand* object) {
inputs_[0] = object;
}
- DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer,
- "load-pixel-array-external-pointer")
+ DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer,
+ "load-external-array-pointer")
};
@@ -1189,19 +1225,23 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
};
-class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> {
+class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
- LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) {
+ LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
+ LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
- DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
- "load-pixel-array-element")
- DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement)
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
+ "load-keyed-specialized-array-element")
+ DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+ ExternalArrayType array_type() const {
+ return hydrogen()->array_type();
+ }
};
@@ -1418,7 +1458,7 @@ class LCallRuntime: public LTemplateInstruction<1, 0, 0> {
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
- Runtime::Function* function() const { return hydrogen()->function(); }
+ const Runtime::Function* function() const { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count(); }
};
@@ -1456,11 +1496,12 @@ class LNumberTagD: public LTemplateInstruction<1, 1, 2> {
// Sometimes truncating conversion from a tagged value to an int32.
-class LDoubleToI: public LTemplateInstruction<1, 1, 1> {
+class LDoubleToI: public LTemplateInstruction<1, 1, 2> {
public:
- explicit LDoubleToI(LOperand* value, LOperand* temp1) {
+ LDoubleToI(LOperand* value, LOperand* temp1, LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp1;
+ temps_[1] = temp2;
}
DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i")
@@ -1471,11 +1512,16 @@ class LDoubleToI: public LTemplateInstruction<1, 1, 1> {
// Truncating conversion from a tagged value to an int32.
-class LTaggedToI: public LTemplateInstruction<1, 1, 1> {
+class LTaggedToI: public LTemplateInstruction<1, 1, 3> {
public:
- LTaggedToI(LOperand* value, LOperand* temp) {
+ LTaggedToI(LOperand* value,
+ LOperand* temp1,
+ LOperand* temp2,
+ LOperand* temp3) {
inputs_[0] = value;
- temps_[0] = temp;
+ temps_[0] = temp1;
+ temps_[1] = temp2;
+ temps_[2] = temp3;
}
DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i")
@@ -1591,6 +1637,7 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> {
}
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
+ DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
virtual void PrintDataTo(StringStream* stream);
@@ -1599,6 +1646,28 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> {
LOperand* value() { return inputs_[2]; }
};
+class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
+ public:
+ LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
+ LOperand* key,
+ LOperand* val) {
+ inputs_[0] = external_pointer;
+ inputs_[1] = key;
+ inputs_[2] = val;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
+ "store-keyed-specialized-array-element")
+ DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
+
+ LOperand* external_pointer() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+ ExternalArrayType array_type() const {
+ return hydrogen()->array_type();
+ }
+};
+
class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> {
public:
@@ -1615,6 +1684,19 @@ class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> {
};
+class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LStringCharFromCode(LOperand* char_code) {
+ inputs_[0] = char_code;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
+ DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
+
+ LOperand* char_code() { return inputs_[0]; }
+};
+
+
class LStringLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LStringLength(LOperand* string) {
@@ -1678,20 +1760,21 @@ class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> {
class LCheckSmi: public LTemplateInstruction<0, 1, 0> {
public:
- LCheckSmi(LOperand* value, Condition condition)
- : condition_(condition) {
+ explicit LCheckSmi(LOperand* value) {
inputs_[0] = value;
}
- Condition condition() const { return condition_; }
+ DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi")
+};
- virtual void CompileToNative(LCodeGen* generator);
- virtual const char* Mnemonic() const {
- return (condition_ == eq) ? "check-non-smi" : "check-smi";
+
+class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
+ public:
+ explicit LCheckNonSmi(LOperand* value) {
+ inputs_[0] = value;
}
- private:
- Condition condition_;
+ DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
};
@@ -1725,6 +1808,17 @@ class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> {
};
+class LToFastProperties: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LToFastProperties(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
+ DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
+};
+
+
class LTypeof: public LTemplateInstruction<1, 1, 0> {
public:
explicit LTypeof(LOperand* value) {
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index afe90159..75406cf7 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "v8.h"
+
#include "arm/lithium-codegen-arm.h"
#include "arm/lithium-gap-resolver-arm.h"
#include "code-stubs.h"
@@ -34,7 +36,7 @@ namespace v8 {
namespace internal {
-class SafepointGenerator : public PostCallGenerator {
+class SafepointGenerator : public CallWrapper {
public:
SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers,
@@ -44,7 +46,24 @@ class SafepointGenerator : public PostCallGenerator {
deoptimization_index_(deoptimization_index) { }
virtual ~SafepointGenerator() { }
- virtual void Generate() {
+ virtual void BeforeCall(int call_size) {
+ ASSERT(call_size >= 0);
+ // Ensure that we have enough space after the previous safepoint position
+ // for the generated code there.
+ int call_end = codegen_->masm()->pc_offset() + call_size;
+ int prev_jump_end =
+ codegen_->LastSafepointEnd() + Deoptimizer::patch_size();
+ if (call_end < prev_jump_end) {
+ int padding_size = prev_jump_end - call_end;
+ ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
+ while (padding_size > 0) {
+ codegen_->masm()->nop();
+ padding_size -= Assembler::kInstrSize;
+ }
+ }
+ }
+
+ virtual void AfterCall() {
codegen_->RecordSafepoint(pointers_, deoptimization_index_);
}
@@ -75,6 +94,7 @@ void LCodeGen::FinishCode(Handle<Code> code) {
code->set_stack_slots(StackSlotCount());
code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
PopulateDeoptimizationData(code);
+ Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
}
@@ -472,7 +492,7 @@ void LCodeGen::CallCode(Handle<Code> code,
}
-void LCodeGen::CallRuntime(Runtime::Function* function,
+void LCodeGen::CallRuntime(const Runtime::Function* function,
int num_arguments,
LInstruction* instr) {
ASSERT(instr != NULL);
@@ -571,14 +591,14 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
if (length == 0) return;
ASSERT(FLAG_deopt);
Handle<DeoptimizationInputData> data =
- Factory::NewDeoptimizationInputData(length, TENURED);
+ factory()->NewDeoptimizationInputData(length, TENURED);
Handle<ByteArray> translations = translations_.CreateByteArray();
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
Handle<FixedArray> literals =
- Factory::NewFixedArray(deoptimization_literals_.length(), TENURED);
+ factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
for (int i = 0; i < deoptimization_literals_.length(); i++) {
literals->set(i, *deoptimization_literals_[i]);
}
@@ -740,15 +760,6 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
break;
}
- case CodeStub::StringCharAt: {
- StringCharAtStub stub;
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- break;
- }
- case CodeStub::MathPow: {
- Abort("MathPowStub unimplemented.");
- break;
- }
case CodeStub::NumberToString: {
NumberToStringStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
@@ -783,55 +794,91 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
void LCodeGen::DoModI(LModI* instr) {
- class DeferredModI: public LDeferredCode {
- public:
- DeferredModI(LCodeGen* codegen, LModI* instr)
- : LDeferredCode(codegen), instr_(instr) { }
- virtual void Generate() {
- codegen()->DoDeferredBinaryOpStub(instr_, Token::MOD);
+ if (instr->hydrogen()->HasPowerOf2Divisor()) {
+ Register dividend = ToRegister(instr->InputAt(0));
+
+ int32_t divisor =
+ HConstant::cast(instr->hydrogen()->right())->Integer32Value();
+
+ if (divisor < 0) divisor = -divisor;
+
+ Label positive_dividend, done;
+ __ cmp(dividend, Operand(0));
+ __ b(pl, &positive_dividend);
+ __ rsb(dividend, dividend, Operand(0));
+ __ and_(dividend, dividend, Operand(divisor - 1));
+ __ rsb(dividend, dividend, Operand(0), SetCC);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ __ b(ne, &done);
+ DeoptimizeIf(al, instr->environment());
}
- private:
- LModI* instr_;
- };
+ __ bind(&positive_dividend);
+ __ and_(dividend, dividend, Operand(divisor - 1));
+ __ bind(&done);
+ return;
+ }
+
// These registers hold untagged 32 bit values.
Register left = ToRegister(instr->InputAt(0));
Register right = ToRegister(instr->InputAt(1));
Register result = ToRegister(instr->result());
+
Register scratch = scratch0();
+ Register scratch2 = ToRegister(instr->TempAt(0));
+ DwVfpRegister dividend = ToDoubleRegister(instr->TempAt(1));
+ DwVfpRegister divisor = ToDoubleRegister(instr->TempAt(2));
+ DwVfpRegister quotient = double_scratch0();
+
+ ASSERT(result.is(left));
+
+ ASSERT(!dividend.is(divisor));
+ ASSERT(!dividend.is(quotient));
+ ASSERT(!divisor.is(quotient));
+ ASSERT(!scratch.is(left));
+ ASSERT(!scratch.is(right));
+ ASSERT(!scratch.is(result));
+
+ Label done, vfp_modulo, both_positive, right_negative;
- Label deoptimize, done;
// Check for x % 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ tst(right, Operand(right));
- __ b(eq, &deoptimize);
+ __ cmp(right, Operand(0));
+ DeoptimizeIf(eq, instr->environment());
}
- // Check for (0 % -x) that will produce negative zero.
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- Label ok;
- __ tst(left, Operand(left));
- __ b(ne, &ok);
- __ tst(right, Operand(right));
- __ b(pl, &ok);
- __ b(al, &deoptimize);
- __ bind(&ok);
- }
+ // (0 % x) must yield 0 (if x is finite, which is the case here).
+ __ cmp(left, Operand(0));
+ __ b(eq, &done);
+ // Preload right in a vfp register.
+ __ vmov(divisor.low(), right);
+ __ b(lt, &vfp_modulo);
+
+ __ cmp(left, Operand(right));
+ __ b(lt, &done);
+
+ // Check for (positive) power of two on the right hand side.
+ __ JumpIfNotPowerOfTwoOrZeroAndNeg(right,
+ scratch,
+ &right_negative,
+ &both_positive);
+ // Perform modulo operation (scratch contains right - 1).
+ __ and_(result, scratch, Operand(left));
+ __ b(&done);
+
+ __ bind(&right_negative);
+ // Negate right. The sign of the divisor does not matter.
+ __ rsb(right, right, Operand(0));
- // Try a few common cases before using the stub.
- Label call_stub;
+ __ bind(&both_positive);
const int kUnfolds = 3;
- // Skip if either side is negative.
- __ cmp(left, Operand(0));
- __ cmp(right, Operand(0), NegateCondition(mi));
- __ b(mi, &call_stub);
// If the right hand side is smaller than the (nonnegative)
- // left hand side, it is the result. Else try a few subtractions
- // of the left hand side.
+ // left hand side, the left hand side is the result.
+ // Else try a few subtractions of the left hand side.
__ mov(scratch, left);
for (int i = 0; i < kUnfolds; i++) {
// Check if the left hand side is less or equal than the
// the right hand side.
- __ cmp(scratch, right);
+ __ cmp(scratch, Operand(right));
__ mov(result, scratch, LeaveCC, lt);
__ b(lt, &done);
// If not, reduce the left hand side by the right hand
@@ -839,28 +886,45 @@ void LCodeGen::DoModI(LModI* instr) {
if (i < kUnfolds - 1) __ sub(scratch, scratch, right);
}
- // Check for power of two on the right hand side.
- __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
- // Perform modulo operation (scratch contains right - 1).
- __ and_(result, scratch, Operand(left));
-
- __ bind(&call_stub);
- // Call the stub. The numbers in r0 and r1 have
- // to be tagged to Smis. If that is not possible, deoptimize.
- DeferredModI* deferred = new DeferredModI(this, instr);
- __ TrySmiTag(left, &deoptimize, scratch);
- __ TrySmiTag(right, &deoptimize, scratch);
-
- __ b(al, deferred->entry());
- __ bind(deferred->exit());
-
- // If the result in r0 is a Smi, untag it, else deoptimize.
- __ JumpIfNotSmi(result, &deoptimize);
- __ SmiUntag(result);
+ __ bind(&vfp_modulo);
+ // Load the arguments in VFP registers.
+ // The divisor value is preloaded before. Be careful that 'right' is only live
+ // on entry.
+ __ vmov(dividend.low(), left);
+ // From here on don't use right as it may have been reallocated (for example
+ // to scratch2).
+ right = no_reg;
+
+ __ vcvt_f64_s32(dividend, dividend.low());
+ __ vcvt_f64_s32(divisor, divisor.low());
+
+ // We do not care about the sign of the divisor.
+ __ vabs(divisor, divisor);
+ // Compute the quotient and round it to a 32bit integer.
+ __ vdiv(quotient, dividend, divisor);
+ __ vcvt_s32_f64(quotient.low(), quotient);
+ __ vcvt_f64_s32(quotient, quotient.low());
+
+ // Compute the remainder in result.
+ DwVfpRegister double_scratch = dividend;
+ __ vmul(double_scratch, divisor, quotient);
+ __ vcvt_s32_f64(double_scratch.low(), double_scratch);
+ __ vmov(scratch, double_scratch.low());
+
+ if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ __ sub(result, left, scratch);
+ } else {
+ Label ok;
+ // Check for -0.
+ __ sub(scratch2, left, scratch, SetCC);
+ __ b(ne, &ok);
+ __ cmp(left, Operand(0));
+ DeoptimizeIf(mi, instr->environment());
+ __ bind(&ok);
+ // Load the result and we are done.
+ __ mov(result, scratch2);
+ }
- __ b(al, &done);
- __ bind(&deoptimize);
- DeoptimizeIf(al, instr->environment());
__ bind(&done);
}
@@ -884,16 +948,16 @@ void LCodeGen::DoDivI(LDivI* instr) {
// Check for x / 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ tst(right, right);
+ __ cmp(right, Operand(0));
DeoptimizeIf(eq, instr->environment());
}
// Check for (0 / -x) that will produce negative zero.
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
Label left_not_zero;
- __ tst(left, Operand(left));
+ __ cmp(left, Operand(0));
__ b(ne, &left_not_zero);
- __ tst(right, Operand(right));
+ __ cmp(right, Operand(0));
DeoptimizeIf(mi, instr->environment());
__ bind(&left_not_zero);
}
@@ -1000,7 +1064,7 @@ void LCodeGen::DoMulI(LMulI* instr) {
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Bail out if the result is supposed to be negative zero.
Label done;
- __ tst(left, Operand(left));
+ __ cmp(left, Operand(0));
__ b(ne, &done);
if (instr->InputAt(1)->IsConstantOperand()) {
if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) <= 0) {
@@ -1022,16 +1086,25 @@ void LCodeGen::DoBitI(LBitI* instr) {
ASSERT(left->Equals(instr->result()));
ASSERT(left->IsRegister());
Register result = ToRegister(left);
- Register right_reg = EmitLoadRegister(right, ip);
+ Operand right_operand(no_reg);
+
+ if (right->IsStackSlot() || right->IsArgument()) {
+ Register right_reg = EmitLoadRegister(right, ip);
+ right_operand = Operand(right_reg);
+ } else {
+ ASSERT(right->IsRegister() || right->IsConstantOperand());
+ right_operand = ToOperand(right);
+ }
+
switch (instr->op()) {
case Token::BIT_AND:
- __ and_(result, ToRegister(left), Operand(right_reg));
+ __ and_(result, ToRegister(left), right_operand);
break;
case Token::BIT_OR:
- __ orr(result, ToRegister(left), Operand(right_reg));
+ __ orr(result, ToRegister(left), right_operand);
break;
case Token::BIT_XOR:
- __ eor(result, ToRegister(left), Operand(right_reg));
+ __ eor(result, ToRegister(left), right_operand);
break;
default:
UNREACHABLE();
@@ -1100,11 +1173,21 @@ void LCodeGen::DoShiftI(LShiftI* instr) {
void LCodeGen::DoSubI(LSubI* instr) {
- Register left = ToRegister(instr->InputAt(0));
- Register right = EmitLoadRegister(instr->InputAt(1), ip);
- ASSERT(instr->InputAt(0)->Equals(instr->result()));
- __ sub(left, left, right, SetCC);
- if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
+ LOperand* left = instr->InputAt(0);
+ LOperand* right = instr->InputAt(1);
+ ASSERT(left->Equals(instr->result()));
+ bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+ SBit set_cond = can_overflow ? SetCC : LeaveCC;
+
+ if (right->IsStackSlot() || right->IsArgument()) {
+ Register right_reg = EmitLoadRegister(right, ip);
+ __ sub(ToRegister(left), ToRegister(left), Operand(right_reg), set_cond);
+ } else {
+ ASSERT(right->IsRegister() || right->IsConstantOperand());
+ __ sub(ToRegister(left), ToRegister(left), ToOperand(right), set_cond);
+ }
+
+ if (can_overflow) {
DeoptimizeIf(vs, instr->environment());
}
}
@@ -1137,10 +1220,10 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
}
-void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
+void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
- __ ldr(result, FieldMemOperand(array, PixelArray::kLengthOffset));
+ __ ldr(result, FieldMemOperand(array, ExternalArray::kLengthOffset));
}
@@ -1193,11 +1276,18 @@ void LCodeGen::DoAddI(LAddI* instr) {
LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1);
ASSERT(left->Equals(instr->result()));
+ bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+ SBit set_cond = can_overflow ? SetCC : LeaveCC;
- Register right_reg = EmitLoadRegister(right, ip);
- __ add(ToRegister(left), ToRegister(left), Operand(right_reg), SetCC);
+ if (right->IsStackSlot() || right->IsArgument()) {
+ Register right_reg = EmitLoadRegister(right, ip);
+ __ add(ToRegister(left), ToRegister(left), Operand(right_reg), set_cond);
+ } else {
+ ASSERT(right->IsRegister() || right->IsConstantOperand());
+ __ add(ToRegister(left), ToRegister(left), ToOperand(right), set_cond);
+ }
- if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
+ if (can_overflow) {
DeoptimizeIf(vs, instr->environment());
}
}
@@ -1226,7 +1316,8 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
__ PrepareCallCFunction(4, scratch0());
__ vmov(r0, r1, left);
__ vmov(r2, r3, right);
- __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4);
+ __ CallCFunction(
+ ExternalReference::double_fp_operation(Token::MOD, isolate()), 4);
// Move the result in the double result register.
__ GetCFunctionDoubleResult(ToDoubleRegister(instr->result()));
@@ -1865,10 +1956,9 @@ void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- Label true_value, done;
- __ tst(r0, r0);
- __ mov(r0, Operand(Factory::false_value()), LeaveCC, ne);
- __ mov(r0, Operand(Factory::true_value()), LeaveCC, eq);
+ __ cmp(r0, Operand(0));
+ __ mov(r0, Operand(factory()->false_value()), LeaveCC, ne);
+ __ mov(r0, Operand(factory()->true_value()), LeaveCC, eq);
}
@@ -1881,7 +1971,7 @@ void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
InstanceofStub stub(InstanceofStub::kArgsInRegisters);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- __ tst(r0, Operand(r0));
+ __ cmp(r0, Operand(0));
EmitBranch(true_block, false_block, eq);
}
@@ -1927,13 +2017,13 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
// We use Factory::the_hole_value() on purpose instead of loading from the
// root array to force relocation to be able to later patch with
// the cached map.
- __ mov(ip, Operand(Factory::the_hole_value()));
+ __ mov(ip, Operand(factory()->the_hole_value()));
__ cmp(map, Operand(ip));
__ b(ne, &cache_miss);
// We use Factory::the_hole_value() on purpose instead of loading from the
// root array to force relocation to be able to later patch
// with true or false.
- __ mov(result, Operand(Factory::the_hole_value()));
+ __ mov(result, Operand(factory()->the_hole_value()));
__ b(&done);
// The inlined call site cache did not match. Check null and string before
@@ -2140,13 +2230,77 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
}
+void LCodeGen::EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name) {
+ LookupResult lookup;
+ type->LookupInDescriptors(NULL, *name, &lookup);
+ ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
+ int index = lookup.GetLocalFieldIndexFromMap(*type);
+ int offset = index * kPointerSize;
+ if (index < 0) {
+ // Negative property indices are in-object properties, indexed
+ // from the end of the fixed part of the object.
+ __ ldr(result, FieldMemOperand(object, offset + type->instance_size()));
+ } else {
+ // Non-negative property indices are in the properties array.
+ __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
+ __ ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize));
+ }
+}
+
+
+void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
+ Register object = ToRegister(instr->object());
+ Register result = ToRegister(instr->result());
+ Register scratch = scratch0();
+ int map_count = instr->hydrogen()->types()->length();
+ Handle<String> name = instr->hydrogen()->name();
+ if (map_count == 0) {
+ ASSERT(instr->hydrogen()->need_generic());
+ __ mov(r2, Operand(name));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ Label done;
+ __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+ for (int i = 0; i < map_count - 1; ++i) {
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ Label next;
+ __ cmp(scratch, Operand(map));
+ __ b(ne, &next);
+ EmitLoadField(result, object, map, name);
+ __ b(&done);
+ __ bind(&next);
+ }
+ Handle<Map> map = instr->hydrogen()->types()->last();
+ __ cmp(scratch, Operand(map));
+ if (instr->hydrogen()->need_generic()) {
+ Label generic;
+ __ b(ne, &generic);
+ EmitLoadField(result, object, map, name);
+ __ b(&done);
+ __ bind(&generic);
+ __ mov(r2, Operand(name));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ DeoptimizeIf(ne, instr->environment());
+ EmitLoadField(result, object, map, name);
+ }
+ __ bind(&done);
+ }
+}
+
+
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(r0));
ASSERT(ToRegister(instr->result()).is(r0));
// Name is always in r2.
__ mov(r2, Operand(instr->name()));
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2207,7 +2361,7 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
__ cmp(scratch, ip);
__ b(eq, &done);
- __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
+ __ LoadRoot(ip, Heap::kExternalPixelArrayMapRootIndex);
__ cmp(scratch, ip);
__ b(eq, &done);
__ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
@@ -2218,11 +2372,12 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
}
-void LCodeGen::DoLoadPixelArrayExternalPointer(
- LLoadPixelArrayExternalPointer* instr) {
+void LCodeGen::DoLoadExternalArrayPointer(
+ LLoadExternalArrayPointer* instr) {
Register to_reg = ToRegister(instr->result());
Register from_reg = ToRegister(instr->InputAt(0));
- __ ldr(to_reg, FieldMemOperand(from_reg, PixelArray::kExternalPointerOffset));
+ __ ldr(to_reg, FieldMemOperand(from_reg,
+ ExternalArray::kExternalPointerOffset));
}
@@ -2262,13 +2417,16 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
}
-void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
- Register external_elements = ToRegister(instr->external_pointer());
+void LCodeGen::DoLoadKeyedSpecializedArrayElement(
+ LLoadKeyedSpecializedArrayElement* instr) {
+ ASSERT(instr->array_type() == kExternalPixelArray);
+
+ Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
Register result = ToRegister(instr->result());
// Load the result.
- __ ldrb(result, MemOperand(external_elements, key));
+ __ ldrb(result, MemOperand(external_pointer, key));
}
@@ -2276,7 +2434,7 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(r1));
ASSERT(ToRegister(instr->key()).is(r0));
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2368,7 +2526,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
// stack.
Label invoke, loop;
// length is a small non-negative integer, due to the test above.
- __ tst(length, Operand(length));
+ __ cmp(length, Operand(0));
__ b(eq, &invoke);
__ bind(&loop);
__ ldr(scratch, MemOperand(elements, length, LSL, 2));
@@ -2604,14 +2762,16 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
// Move the result back to general purpose register r0.
__ vmov(result, single_scratch);
- // Test for -0.
- Label done;
- __ cmp(result, Operand(0));
- __ b(ne, &done);
- __ vmov(scratch1, input.high());
- __ tst(scratch1, Operand(HeapNumber::kSignMask));
- DeoptimizeIf(ne, instr->environment());
- __ bind(&done);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ // Test for -0.
+ Label done;
+ __ cmp(result, Operand(0));
+ __ b(ne, &done);
+ __ vmov(scratch1, input.high());
+ __ tst(scratch1, Operand(HeapNumber::kSignMask));
+ DeoptimizeIf(ne, instr->environment());
+ __ bind(&done);
+ }
}
@@ -2628,14 +2788,16 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
DeoptimizeIf(ne, instr->environment());
__ vmov(result, double_scratch0().low());
- // Test for -0.
- Label done;
- __ cmp(result, Operand(0));
- __ b(ne, &done);
- __ vmov(scratch1, input.high());
- __ tst(scratch1, Operand(HeapNumber::kSignMask));
- DeoptimizeIf(ne, instr->environment());
- __ bind(&done);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ // Test for -0.
+ Label done;
+ __ cmp(result, Operand(0));
+ __ b(ne, &done);
+ __ vmov(scratch1, input.high());
+ __ tst(scratch1, Operand(HeapNumber::kSignMask));
+ DeoptimizeIf(ne, instr->environment());
+ __ bind(&done);
+ }
}
@@ -2646,6 +2808,22 @@ void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
}
+void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
+ DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
+ Register scratch = scratch0();
+ SwVfpRegister single_scratch = double_scratch0().low();
+ DoubleRegister double_scratch = double_scratch0();
+ ASSERT(ToDoubleRegister(instr->result()).is(input));
+
+ // Add +0 to convert -0 to +0.
+ __ mov(scratch, Operand(0));
+ __ vmov(single_scratch, scratch);
+ __ vcvt_f64_s32(double_scratch, single_scratch);
+ __ vadd(input, input, double_scratch);
+ __ vsqrt(input, input);
+}
+
+
void LCodeGen::DoPower(LPower* instr) {
LOperand* left = instr->InputAt(0);
LOperand* right = instr->InputAt(1);
@@ -2657,14 +2835,16 @@ void LCodeGen::DoPower(LPower* instr) {
__ PrepareCallCFunction(4, scratch);
__ vmov(r0, r1, ToDoubleRegister(left));
__ vmov(r2, r3, ToDoubleRegister(right));
- __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+ __ CallCFunction(
+ ExternalReference::power_double_double_function(isolate()), 4);
} else if (exponent_type.IsInteger32()) {
ASSERT(ToRegister(right).is(r0));
// Prepare arguments and call C function.
__ PrepareCallCFunction(4, scratch);
__ mov(r2, ToRegister(right));
__ vmov(r0, r1, ToDoubleRegister(left));
- __ CallCFunction(ExternalReference::power_double_int_function(), 4);
+ __ CallCFunction(
+ ExternalReference::power_double_int_function(isolate()), 4);
} else {
ASSERT(exponent_type.IsTagged());
ASSERT(instr->hydrogen()->left()->representation().IsDouble());
@@ -2697,7 +2877,8 @@ void LCodeGen::DoPower(LPower* instr) {
__ PrepareCallCFunction(4, scratch);
__ vmov(r0, r1, ToDoubleRegister(left));
__ vmov(r2, r3, result_reg);
- __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+ __ CallCFunction(
+ ExternalReference::power_double_double_function(isolate()), 4);
}
// Store the result in the result register.
__ GetCFunctionDoubleResult(result_reg);
@@ -2742,6 +2923,9 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
case kMathSqrt:
DoMathSqrt(instr);
break;
+ case kMathPowHalf:
+ DoMathPowHalf(instr);
+ break;
case kMathCos:
DoMathCos(instr);
break;
@@ -2762,7 +2946,8 @@ void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
@@ -2772,7 +2957,8 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
+ arity, NOT_IN_LOOP);
__ mov(r2, Operand(instr->name()));
CallCode(ic, RelocInfo::CODE_TARGET, instr);
// Restore context register.
@@ -2795,7 +2981,8 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP);
__ mov(r2, Operand(instr->name()));
CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -2813,7 +3000,7 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
ASSERT(ToRegister(instr->InputAt(0)).is(r1));
ASSERT(ToRegister(instr->result()).is(r0));
- Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
__ mov(r0, Operand(instr->arity()));
CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
}
@@ -2862,9 +3049,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
// Name is always in r2.
__ mov(r2, Operand(instr->name()));
- Handle<Code> ic(Builtins::builtin(
- info_->is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = info_->is_strict()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2901,14 +3088,28 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
}
+void LCodeGen::DoStoreKeyedSpecializedArrayElement(
+ LStoreKeyedSpecializedArrayElement* instr) {
+ ASSERT(instr->array_type() == kExternalPixelArray);
+
+ Register external_pointer = ToRegister(instr->external_pointer());
+ Register key = ToRegister(instr->key());
+ Register value = ToRegister(instr->value());
+
+ // Clamp the value to [0..255].
+ __ Usat(value, 8, Operand(value));
+ __ strb(value, MemOperand(external_pointer, key, LSL, 0));
+}
+
+
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(r2));
ASSERT(ToRegister(instr->key()).is(r1));
ASSERT(ToRegister(instr->value()).is(r0));
- Handle<Code> ic(Builtins::builtin(
- info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = info_->is_strict()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -3054,6 +3255,56 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
}
+void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
+ class DeferredStringCharFromCode: public LDeferredCode {
+ public:
+ DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
+ private:
+ LStringCharFromCode* instr_;
+ };
+
+ DeferredStringCharFromCode* deferred =
+ new DeferredStringCharFromCode(this, instr);
+
+ ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+ ASSERT(!char_code.is(result));
+
+ __ cmp(char_code, Operand(String::kMaxAsciiCharCode));
+ __ b(hi, deferred->entry());
+ __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
+ __ add(result, result, Operand(char_code, LSL, kPointerSizeLog2));
+ __ ldr(result, FieldMemOperand(result, FixedArray::kHeaderSize));
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ __ cmp(result, ip);
+ __ b(eq, deferred->entry());
+ __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+
+ // TODO(3095996): Get rid of this. For now, we need to make the
+ // result register contain a valid pointer because it is already
+ // contained in the register pointer map.
+ __ mov(result, Operand(0));
+
+ __ PushSafepointRegisters();
+ __ SmiTag(char_code);
+ __ push(char_code);
+ __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
+ __ StoreToSafepointRegisterSlot(r0, result);
+ __ PopSafepointRegisters();
+}
+
+
void LCodeGen::DoStringLength(LStringLength* instr) {
Register string = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
@@ -3266,19 +3517,30 @@ class DeferredTaggedToI: public LDeferredCode {
void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
- Label done;
Register input_reg = ToRegister(instr->InputAt(0));
- Register scratch = scratch0();
- DoubleRegister dbl_scratch = d0;
- SwVfpRegister flt_scratch = s0;
- DoubleRegister dbl_tmp = ToDoubleRegister(instr->TempAt(0));
+ Register scratch1 = scratch0();
+ Register scratch2 = ToRegister(instr->TempAt(0));
+ DwVfpRegister double_scratch = double_scratch0();
+ SwVfpRegister single_scratch = double_scratch.low();
+
+ ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
+ ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
+
+ Label done;
// Heap number map check.
- __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
+ __ ldr(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
- __ cmp(scratch, Operand(ip));
+ __ cmp(scratch1, Operand(ip));
if (instr->truncating()) {
+ Register scratch3 = ToRegister(instr->TempAt(1));
+ DwVfpRegister double_scratch2 = ToDoubleRegister(instr->TempAt(2));
+ ASSERT(!scratch3.is(input_reg) &&
+ !scratch3.is(scratch1) &&
+ !scratch3.is(scratch2));
+ // Performs a truncating conversion of a floating point number as used by
+ // the JS bitwise operations.
Label heap_number;
__ b(eq, &heap_number);
// Check for undefined. Undefined is converted to zero for truncating
@@ -3290,36 +3552,38 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
__ b(&done);
__ bind(&heap_number);
- __ sub(ip, input_reg, Operand(kHeapObjectTag));
- __ vldr(dbl_tmp, ip, HeapNumber::kValueOffset);
- __ vcmp(dbl_tmp, 0.0); // Sets overflow bit in FPSCR flags if NaN.
- __ vcvt_s32_f64(flt_scratch, dbl_tmp);
- __ vmov(input_reg, flt_scratch); // 32-bit result of conversion.
- __ vmrs(pc); // Move vector status bits to normal status bits.
- // Overflow bit is set if dbl_tmp is Nan.
- __ cmn(input_reg, Operand(1), vc); // 0x7fffffff + 1 -> overflow.
- __ cmp(input_reg, Operand(1), vc); // 0x80000000 - 1 -> overflow.
- DeoptimizeIf(vs, instr->environment()); // Saturation may have occured.
+ __ sub(scratch1, input_reg, Operand(kHeapObjectTag));
+ __ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset);
+
+ __ EmitECMATruncate(input_reg,
+ double_scratch2,
+ single_scratch,
+ scratch1,
+ scratch2,
+ scratch3);
} else {
+ CpuFeatures::Scope scope(VFP3);
// Deoptimize if we don't have a heap number.
DeoptimizeIf(ne, instr->environment());
__ sub(ip, input_reg, Operand(kHeapObjectTag));
- __ vldr(dbl_tmp, ip, HeapNumber::kValueOffset);
- __ vcvt_s32_f64(flt_scratch, dbl_tmp);
- __ vmov(input_reg, flt_scratch); // 32-bit result of conversion.
- // Non-truncating conversion means that we cannot lose bits, so we convert
- // back to check; note that using non-overlapping s and d regs would be
- // slightly faster.
- __ vcvt_f64_s32(dbl_scratch, flt_scratch);
- __ VFPCompareAndSetFlags(dbl_scratch, dbl_tmp);
- DeoptimizeIf(ne, instr->environment()); // Not equal or unordered.
+ __ vldr(double_scratch, ip, HeapNumber::kValueOffset);
+ __ EmitVFPTruncate(kRoundToZero,
+ single_scratch,
+ double_scratch,
+ scratch1,
+ scratch2,
+ kCheckForInexactConversion);
+ DeoptimizeIf(ne, instr->environment());
+ // Load the result.
+ __ vmov(input_reg, single_scratch);
+
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- __ tst(input_reg, Operand(input_reg));
+ __ cmp(input_reg, Operand(0));
__ b(ne, &done);
- __ vmov(lr, ip, dbl_tmp);
- __ tst(ip, Operand(1 << 31)); // Test sign bit.
+ __ vmov(scratch1, double_scratch.high());
+ __ tst(scratch1, Operand(HeapNumber::kSignMask));
DeoptimizeIf(ne, instr->environment());
}
}
@@ -3361,56 +3625,52 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
- LOperand* input = instr->InputAt(0);
- ASSERT(input->IsDoubleRegister());
- LOperand* result = instr->result();
- ASSERT(result->IsRegister());
-
- DoubleRegister double_input = ToDoubleRegister(input);
- Register result_reg = ToRegister(result);
- SwVfpRegister single_scratch = double_scratch0().low();
+ Register result_reg = ToRegister(instr->result());
Register scratch1 = scratch0();
Register scratch2 = ToRegister(instr->TempAt(0));
+ DwVfpRegister double_input = ToDoubleRegister(instr->InputAt(0));
+ DwVfpRegister double_scratch = double_scratch0();
+ SwVfpRegister single_scratch = double_scratch0().low();
- __ EmitVFPTruncate(kRoundToZero,
- single_scratch,
- double_input,
- scratch1,
- scratch2);
-
- // Deoptimize if we had a vfp invalid exception.
- DeoptimizeIf(ne, instr->environment());
-
- // Retrieve the result.
- __ vmov(result_reg, single_scratch);
+ Label done;
- if (!instr->truncating()) {
- // Convert result back to double and compare with input
- // to check if the conversion was exact.
- __ vmov(single_scratch, result_reg);
- __ vcvt_f64_s32(double_scratch0(), single_scratch);
- __ VFPCompareAndSetFlags(double_scratch0(), double_input);
+ if (instr->truncating()) {
+ Register scratch3 = ToRegister(instr->TempAt(1));
+ __ EmitECMATruncate(result_reg,
+ double_input,
+ single_scratch,
+ scratch1,
+ scratch2,
+ scratch3);
+ } else {
+ VFPRoundingMode rounding_mode = kRoundToMinusInf;
+ __ EmitVFPTruncate(rounding_mode,
+ single_scratch,
+ double_input,
+ scratch1,
+ scratch2,
+ kCheckForInexactConversion);
+ // Deoptimize if we had a vfp invalid exception,
+ // including inexact operation.
DeoptimizeIf(ne, instr->environment());
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- Label done;
- __ cmp(result_reg, Operand(0));
- __ b(ne, &done);
- // Check for -0.
- __ vmov(scratch1, double_input.high());
- __ tst(scratch1, Operand(HeapNumber::kSignMask));
- DeoptimizeIf(ne, instr->environment());
-
- __ bind(&done);
- }
+ // Retrieve the result.
+ __ vmov(result_reg, single_scratch);
}
+ __ bind(&done);
}
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
LOperand* input = instr->InputAt(0);
- ASSERT(input->IsRegister());
__ tst(ToRegister(input), Operand(kSmiTagMask));
- DeoptimizeIf(instr->condition(), instr->environment());
+ DeoptimizeIf(ne, instr->environment());
+}
+
+
+void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
+ LOperand* input = instr->InputAt(0);
+ __ tst(ToRegister(input), Operand(kSmiTagMask));
+ DeoptimizeIf(eq, instr->environment());
}
@@ -3459,9 +3719,9 @@ void LCodeGen::DoCheckMap(LCheckMap* instr) {
void LCodeGen::LoadHeapObject(Register result,
Handle<HeapObject> object) {
- if (Heap::InNewSpace(*object)) {
+ if (heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
- Factory::NewJSGlobalPropertyCell(object);
+ factory()->NewJSGlobalPropertyCell(object);
__ mov(result, Operand(cell));
__ ldr(result, FieldMemOperand(result, JSGlobalPropertyCell::kValueOffset));
} else {
@@ -3543,6 +3803,13 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
}
+void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
+ ASSERT(ToRegister(instr->InputAt(0)).is(r0));
+ __ push(r0);
+ CallRuntime(Runtime::kToFastProperties, 1, instr);
+}
+
+
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
Label materialized;
// Registers will be used as follows:
@@ -3603,16 +3870,17 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
// space for nested functions that don't need literals cloning.
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (shared_info->num_literals() == 0 && !pretenure) {
- FastNewClosureStub stub;
+ if (!pretenure && shared_info->num_literals() == 0) {
+ FastNewClosureStub stub(
+ shared_info->strict_mode() ? kStrictMode : kNonStrictMode);
__ mov(r1, Operand(shared_info));
__ push(r1);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
} else {
__ mov(r2, Operand(shared_info));
__ mov(r1, Operand(pretenure
- ? Factory::true_value()
- : Factory::false_value()));
+ ? factory()->true_value()
+ : factory()->false_value()));
__ Push(cp, r2, r1);
CallRuntime(Runtime::kNewClosure, 3, instr);
}
@@ -3671,14 +3939,14 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
Handle<String> type_name) {
Condition final_branch_condition = kNoCondition;
Register scratch = scratch0();
- if (type_name->Equals(Heap::number_symbol())) {
+ if (type_name->Equals(heap()->number_symbol())) {
__ JumpIfSmi(input, true_label);
__ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
__ cmp(input, Operand(ip));
final_branch_condition = eq;
- } else if (type_name->Equals(Heap::string_symbol())) {
+ } else if (type_name->Equals(heap()->string_symbol())) {
__ JumpIfSmi(input, false_label);
__ CompareObjectType(input, input, scratch, FIRST_NONSTRING_TYPE);
__ b(ge, false_label);
@@ -3686,13 +3954,13 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
__ tst(ip, Operand(1 << Map::kIsUndetectable));
final_branch_condition = eq;
- } else if (type_name->Equals(Heap::boolean_symbol())) {
+ } else if (type_name->Equals(heap()->boolean_symbol())) {
__ CompareRoot(input, Heap::kTrueValueRootIndex);
__ b(eq, true_label);
__ CompareRoot(input, Heap::kFalseValueRootIndex);
final_branch_condition = eq;
- } else if (type_name->Equals(Heap::undefined_symbol())) {
+ } else if (type_name->Equals(heap()->undefined_symbol())) {
__ CompareRoot(input, Heap::kUndefinedValueRootIndex);
__ b(eq, true_label);
__ JumpIfSmi(input, false_label);
@@ -3702,12 +3970,12 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
__ tst(ip, Operand(1 << Map::kIsUndetectable));
final_branch_condition = ne;
- } else if (type_name->Equals(Heap::function_symbol())) {
+ } else if (type_name->Equals(heap()->function_symbol())) {
__ JumpIfSmi(input, false_label);
__ CompareObjectType(input, input, scratch, FIRST_FUNCTION_CLASS_TYPE);
final_branch_condition = ge;
- } else if (type_name->Equals(Heap::object_symbol())) {
+ } else if (type_name->Equals(heap()->object_symbol())) {
__ JumpIfSmi(input, false_label);
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ b(eq, true_label);
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 23e0c44b..caa85d27 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -65,6 +65,9 @@ class LCodeGen BASE_EMBEDDED {
// Simple accessors.
MacroAssembler* masm() const { return masm_; }
CompilationInfo* info() const { return info_; }
+ Isolate* isolate() const { return info_->isolate(); }
+ Factory* factory() const { return isolate()->factory(); }
+ Heap* heap() const { return isolate()->heap(); }
// Support for converting LOperands to assembler types.
// LOperand must be a register.
@@ -105,6 +108,7 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
+ void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
@@ -171,13 +175,13 @@ class LCodeGen BASE_EMBEDDED {
void CallCode(Handle<Code> code,
RelocInfo::Mode mode,
LInstruction* instr);
- void CallRuntime(Runtime::Function* function,
+ void CallRuntime(const Runtime::Function* function,
int num_arguments,
LInstruction* instr);
void CallRuntime(Runtime::FunctionId id,
int num_arguments,
LInstruction* instr) {
- Runtime::Function* function = Runtime::FunctionForId(id);
+ const Runtime::Function* function = Runtime::FunctionForId(id);
CallRuntime(function, num_arguments, instr);
}
@@ -210,6 +214,7 @@ class LCodeGen BASE_EMBEDDED {
void DoMathFloor(LUnaryMathOperation* instr);
void DoMathRound(LUnaryMathOperation* instr);
void DoMathSqrt(LUnaryMathOperation* instr);
+ void DoMathPowHalf(LUnaryMathOperation* instr);
void DoMathLog(LUnaryMathOperation* instr);
void DoMathCos(LUnaryMathOperation* instr);
void DoMathSin(LUnaryMathOperation* instr);
@@ -228,6 +233,9 @@ class LCodeGen BASE_EMBEDDED {
int arguments,
int deoptimization_index);
void RecordPosition(int position);
+ int LastSafepointEnd() {
+ return static_cast<int>(safepoints_.GetPcAfterGap());
+ }
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
@@ -256,6 +264,11 @@ class LCodeGen BASE_EMBEDDED {
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp1, Register temp2);
+ void EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name);
+
LChunk* const chunk_;
MacroAssembler* const masm_;
CompilationInfo* const info_;
diff --git a/src/arm/lithium-gap-resolver-arm.cc b/src/arm/lithium-gap-resolver-arm.cc
index 1a2326b7..02608a69 100644
--- a/src/arm/lithium-gap-resolver-arm.cc
+++ b/src/arm/lithium-gap-resolver-arm.cc
@@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "v8.h"
+
#include "arm/lithium-gap-resolver-arm.h"
#include "arm/lithium-codegen-arm.h"
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index d431f6a9..3a1a8b6a 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -43,7 +43,7 @@ MacroAssembler::MacroAssembler(void* buffer, int size)
: Assembler(buffer, size),
generating_stub_(false),
allow_stub_calls_(true),
- code_object_(Heap::undefined_value()) {
+ code_object_(HEAP->undefined_value()) {
}
@@ -103,7 +103,22 @@ void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
}
+int MacroAssembler::CallSize(Register target, Condition cond) {
+#if USE_BLX
+ return kInstrSize;
+#else
+ return 2 * kInstrSize;
+#endif
+}
+
+
void MacroAssembler::Call(Register target, Condition cond) {
+ // Block constant pool for the call instruction sequence.
+ BlockConstPoolScope block_const_pool(this);
+#ifdef DEBUG
+ int pre_position = pc_offset();
+#endif
+
#if USE_BLX
blx(target, cond);
#else
@@ -111,29 +126,46 @@ void MacroAssembler::Call(Register target, Condition cond) {
mov(lr, Operand(pc), LeaveCC, cond);
mov(pc, Operand(target), LeaveCC, cond);
#endif
+
+#ifdef DEBUG
+ int post_position = pc_offset();
+ CHECK_EQ(pre_position + CallSize(target, cond), post_position);
+#endif
}
-void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
- Condition cond) {
+int MacroAssembler::CallSize(
+ intptr_t target, RelocInfo::Mode rmode, Condition cond) {
+ int size = 2 * kInstrSize;
+ Instr mov_instr = cond | MOV | LeaveCC;
+ if (!Operand(target, rmode).is_single_instruction(mov_instr)) {
+ size += kInstrSize;
+ }
+ return size;
+}
+
+
+void MacroAssembler::Call(
+ intptr_t target, RelocInfo::Mode rmode, Condition cond) {
+ // Block constant pool for the call instruction sequence.
+ BlockConstPoolScope block_const_pool(this);
+#ifdef DEBUG
+ int pre_position = pc_offset();
+#endif
+
#if USE_BLX
// On ARMv5 and after the recommended call sequence is:
// ldr ip, [pc, #...]
// blx ip
- // The two instructions (ldr and blx) could be separated by a constant
- // pool and the code would still work. The issue comes from the
- // patching code which expect the ldr to be just above the blx.
- { BlockConstPoolScope block_const_pool(this);
- // Statement positions are expected to be recorded when the target
- // address is loaded. The mov method will automatically record
- // positions when pc is the target, since this is not the case here
- // we have to do it explicitly.
- positions_recorder()->WriteRecordedPositions();
+ // Statement positions are expected to be recorded when the target
+ // address is loaded. The mov method will automatically record
+ // positions when pc is the target, since this is not the case here
+ // we have to do it explicitly.
+ positions_recorder()->WriteRecordedPositions();
- mov(ip, Operand(target, rmode), LeaveCC, cond);
- blx(ip, cond);
- }
+ mov(ip, Operand(target, rmode), LeaveCC, cond);
+ blx(ip, cond);
ASSERT(kCallTargetAddressOffset == 2 * kInstrSize);
#else
@@ -141,24 +173,58 @@ void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
mov(lr, Operand(pc), LeaveCC, cond);
// Emit a ldr<cond> pc, [pc + offset of target in constant pool].
mov(pc, Operand(target, rmode), LeaveCC, cond);
-
ASSERT(kCallTargetAddressOffset == kInstrSize);
#endif
+
+#ifdef DEBUG
+ int post_position = pc_offset();
+ CHECK_EQ(pre_position + CallSize(target, rmode, cond), post_position);
+#endif
}
-void MacroAssembler::Call(byte* target, RelocInfo::Mode rmode,
- Condition cond) {
+int MacroAssembler::CallSize(
+ byte* target, RelocInfo::Mode rmode, Condition cond) {
+ return CallSize(reinterpret_cast<intptr_t>(target), rmode);
+}
+
+
+void MacroAssembler::Call(
+ byte* target, RelocInfo::Mode rmode, Condition cond) {
+#ifdef DEBUG
+ int pre_position = pc_offset();
+#endif
+
ASSERT(!RelocInfo::IsCodeTarget(rmode));
Call(reinterpret_cast<intptr_t>(target), rmode, cond);
+
+#ifdef DEBUG
+ int post_position = pc_offset();
+ CHECK_EQ(pre_position + CallSize(target, rmode, cond), post_position);
+#endif
}
-void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
- Condition cond) {
+int MacroAssembler::CallSize(
+ Handle<Code> code, RelocInfo::Mode rmode, Condition cond) {
+ return CallSize(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
+}
+
+
+void MacroAssembler::Call(
+ Handle<Code> code, RelocInfo::Mode rmode, Condition cond) {
+#ifdef DEBUG
+ int pre_position = pc_offset();
+#endif
+
ASSERT(RelocInfo::IsCodeTarget(rmode));
// 'code' is always generated ARM code, never THUMB code
Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
+
+#ifdef DEBUG
+ int post_position = pc_offset();
+ CHECK_EQ(pre_position + CallSize(code, rmode, cond), post_position);
+#endif
}
@@ -226,7 +292,7 @@ void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
} else if (!src2.is_single_instruction() &&
!src2.must_use_constant_pool() &&
- CpuFeatures::IsSupported(ARMv7) &&
+ Isolate::Current()->cpu_features()->IsSupported(ARMv7) &&
IsPowerOf2(src2.immediate() + 1)) {
ubfx(dst, src1, 0, WhichPowerOf2(src2.immediate() + 1), cond);
@@ -239,7 +305,7 @@ void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
void MacroAssembler::Ubfx(Register dst, Register src1, int lsb, int width,
Condition cond) {
ASSERT(lsb < 32);
- if (!CpuFeatures::IsSupported(ARMv7)) {
+ if (!Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
and_(dst, src1, Operand(mask), LeaveCC, cond);
if (lsb != 0) {
@@ -254,7 +320,7 @@ void MacroAssembler::Ubfx(Register dst, Register src1, int lsb, int width,
void MacroAssembler::Sbfx(Register dst, Register src1, int lsb, int width,
Condition cond) {
ASSERT(lsb < 32);
- if (!CpuFeatures::IsSupported(ARMv7)) {
+ if (!Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
and_(dst, src1, Operand(mask), LeaveCC, cond);
int shift_up = 32 - lsb - width;
@@ -282,7 +348,7 @@ void MacroAssembler::Bfi(Register dst,
ASSERT(lsb + width < 32);
ASSERT(!scratch.is(dst));
if (width == 0) return;
- if (!CpuFeatures::IsSupported(ARMv7)) {
+ if (!Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
bic(dst, dst, Operand(mask));
and_(scratch, src, Operand((1 << width) - 1));
@@ -296,7 +362,7 @@ void MacroAssembler::Bfi(Register dst,
void MacroAssembler::Bfc(Register dst, int lsb, int width, Condition cond) {
ASSERT(lsb < 32);
- if (!CpuFeatures::IsSupported(ARMv7)) {
+ if (!Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
bic(dst, dst, Operand(mask));
} else {
@@ -307,7 +373,7 @@ void MacroAssembler::Bfc(Register dst, int lsb, int width, Condition cond) {
void MacroAssembler::Usat(Register dst, int satpos, const Operand& src,
Condition cond) {
- if (!CpuFeatures::IsSupported(ARMv7)) {
+ if (!Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
ASSERT(!dst.is(pc) && !src.rm().is(pc));
ASSERT((satpos >= 0) && (satpos <= 31));
@@ -367,7 +433,7 @@ void MacroAssembler::StoreRoot(Register source,
void MacroAssembler::RecordWriteHelper(Register object,
Register address,
Register scratch) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Check that the object is not in new space.
Label not_in_new_space;
InNewSpace(object, scratch, ne, &not_in_new_space);
@@ -395,8 +461,8 @@ void MacroAssembler::InNewSpace(Register object,
Condition cond,
Label* branch) {
ASSERT(cond == eq || cond == ne);
- and_(scratch, object, Operand(ExternalReference::new_space_mask()));
- cmp(scratch, Operand(ExternalReference::new_space_start()));
+ and_(scratch, object, Operand(ExternalReference::new_space_mask(isolate())));
+ cmp(scratch, Operand(ExternalReference::new_space_start(isolate())));
b(cond, branch);
}
@@ -429,7 +495,7 @@ void MacroAssembler::RecordWrite(Register object,
// Clobber all input registers when running with the debug-code flag
// turned on to provoke errors.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
mov(object, Operand(BitCast<int32_t>(kZapValue)));
mov(scratch0, Operand(BitCast<int32_t>(kZapValue)));
mov(scratch1, Operand(BitCast<int32_t>(kZapValue)));
@@ -461,7 +527,7 @@ void MacroAssembler::RecordWrite(Register object,
// Clobber all input registers when running with the debug-code flag
// turned on to provoke errors.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
mov(object, Operand(BitCast<int32_t>(kZapValue)));
mov(address, Operand(BitCast<int32_t>(kZapValue)));
mov(scratch, Operand(BitCast<int32_t>(kZapValue)));
@@ -553,7 +619,7 @@ void MacroAssembler::Ldrd(Register dst1, Register dst2,
ASSERT_EQ(dst1.code() + 1, dst2.code());
// Generate two ldr instructions if ldrd is not available.
- if (CpuFeatures::IsSupported(ARMv7)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
CpuFeatures::Scope scope(ARMv7);
ldrd(dst1, dst2, src, cond);
} else {
@@ -578,7 +644,7 @@ void MacroAssembler::Strd(Register src1, Register src2,
ASSERT_EQ(src1.code() + 1, src2.code());
// Generate two str instructions if strd is not available.
- if (CpuFeatures::IsSupported(ARMv7)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
CpuFeatures::Scope scope(ARMv7);
strd(src1, src2, dst, cond);
} else {
@@ -665,7 +731,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
mov(fp, Operand(sp)); // Setup new frame pointer.
// Reserve room for saved entry sp and code object.
sub(sp, sp, Operand(2 * kPointerSize));
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
mov(ip, Operand(0));
str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
}
@@ -673,9 +739,9 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset));
// Save the frame pointer and the context in top.
- mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+ mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
str(fp, MemOperand(ip));
- mov(ip, Operand(ExternalReference(Top::k_context_address)));
+ mov(ip, Operand(ExternalReference(Isolate::k_context_address, isolate())));
str(cp, MemOperand(ip));
// Optionally save all double registers.
@@ -751,11 +817,11 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles,
// Clear top frame.
mov(r3, Operand(0, RelocInfo::NONE));
- mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+ mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
str(r3, MemOperand(ip));
// Restore current context from top and clear it in debug mode.
- mov(ip, Operand(ExternalReference(Top::k_context_address)));
+ mov(ip, Operand(ExternalReference(Isolate::k_context_address, isolate())));
ldr(cp, MemOperand(ip));
#ifdef DEBUG
str(r3, MemOperand(ip));
@@ -784,7 +850,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Register code_reg,
Label* done,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
bool definitely_matches = false;
Label regular_invoke;
@@ -837,10 +903,13 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
}
Handle<Code> adaptor =
- Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
+ isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (flag == CALL_FUNCTION) {
+ if (call_wrapper != NULL) {
+ call_wrapper->BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET));
+ }
Call(adaptor, RelocInfo::CODE_TARGET);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ if (call_wrapper != NULL) call_wrapper->AfterCall();
b(done);
} else {
Jump(adaptor, RelocInfo::CODE_TARGET);
@@ -854,14 +923,15 @@ void MacroAssembler::InvokeCode(Register code,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
Label done;
InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag,
- post_call_generator);
+ call_wrapper);
if (flag == CALL_FUNCTION) {
+ if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(code));
Call(code);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ if (call_wrapper != NULL) call_wrapper->AfterCall();
} else {
ASSERT(flag == JUMP_FUNCTION);
Jump(code);
@@ -896,7 +966,7 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
void MacroAssembler::InvokeFunction(Register fun,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
// Contract with called JS functions requires that function is passed in r1.
ASSERT(fun.is(r1));
@@ -913,7 +983,7 @@ void MacroAssembler::InvokeFunction(Register fun,
FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
ParameterCount expected(expected_reg);
- InvokeCode(code_reg, expected, actual, flag, post_call_generator);
+ InvokeCode(code_reg, expected, actual, flag, call_wrapper);
}
@@ -977,7 +1047,7 @@ void MacroAssembler::IsObjectJSStringType(Register object,
void MacroAssembler::DebugBreak() {
ASSERT(allow_stub_calls());
mov(r0, Operand(0, RelocInfo::NONE));
- mov(r1, Operand(ExternalReference(Runtime::kDebugBreak)));
+ mov(r1, Operand(ExternalReference(Runtime::kDebugBreak, isolate())));
CEntryStub ces(1);
Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
}
@@ -1000,7 +1070,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
&& StackHandlerConstants::kPCOffset == 3 * kPointerSize);
stm(db_w, sp, r3.bit() | fp.bit() | lr.bit());
// Save the current handler as the next handler.
- mov(r3, Operand(ExternalReference(Top::k_handler_address)));
+ mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(r1, MemOperand(r3));
ASSERT(StackHandlerConstants::kNextOffset == 0);
push(r1);
@@ -1019,7 +1089,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
&& StackHandlerConstants::kPCOffset == 3 * kPointerSize);
stm(db_w, sp, r6.bit() | ip.bit() | lr.bit());
// Save the current handler as the next handler.
- mov(r7, Operand(ExternalReference(Top::k_handler_address)));
+ mov(r7, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(r6, MemOperand(r7));
ASSERT(StackHandlerConstants::kNextOffset == 0);
push(r6);
@@ -1032,7 +1102,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() {
ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
pop(r1);
- mov(ip, Operand(ExternalReference(Top::k_handler_address)));
+ mov(ip, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
str(r1, MemOperand(ip));
}
@@ -1048,7 +1118,7 @@ void MacroAssembler::Throw(Register value) {
STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
// Drop the sp to the top of the handler.
- mov(r3, Operand(ExternalReference(Top::k_handler_address)));
+ mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(sp, MemOperand(r3));
// Restore the next handler and frame pointer, discard handler state.
@@ -1067,7 +1137,7 @@ void MacroAssembler::Throw(Register value) {
// Restore cp otherwise.
ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
#ifdef DEBUG
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
mov(lr, Operand(pc));
}
#endif
@@ -1087,7 +1157,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
}
// Drop sp to the top stack handler.
- mov(r3, Operand(ExternalReference(Top::k_handler_address)));
+ mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
ldr(sp, MemOperand(r3));
// Unwind the handlers until the ENTRY handler is found.
@@ -1111,7 +1181,8 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
- ExternalReference external_caught(Top::k_external_caught_exception_address);
+ ExternalReference external_caught(
+ Isolate::k_external_caught_exception_address, isolate());
mov(r0, Operand(false, RelocInfo::NONE));
mov(r2, Operand(external_caught));
str(r0, MemOperand(r2));
@@ -1119,7 +1190,8 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
// Set pending exception and r0 to out of memory exception.
Failure* out_of_memory = Failure::OutOfMemoryException();
mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
- mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
+ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ isolate())));
str(r0, MemOperand(r2));
}
@@ -1140,7 +1212,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
// Restore cp otherwise.
ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
#ifdef DEBUG
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
mov(lr, Operand(pc));
}
#endif
@@ -1172,7 +1244,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
// Check the context is a global context.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// TODO(119): avoid push(holder_reg)/pop(holder_reg)
// Cannot use ip as a temporary in this verification code. Due to the fact
// that ip is clobbered as part of cmp with an object Operand.
@@ -1191,7 +1263,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
b(eq, &same_contexts);
// Check the context is a global context.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// TODO(119): avoid push(holder_reg)/pop(holder_reg)
// Cannot use ip as a temporary in this verification code. Due to the fact
// that ip is clobbered as part of cmp with an object Operand.
@@ -1233,7 +1305,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
Label* gc_required,
AllocationFlags flags) {
if (!FLAG_inline_new) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
mov(result, Operand(0x7091));
mov(scratch1, Operand(0x7191));
@@ -1260,9 +1332,9 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
// Also, assert that the registers are numbered such that the values
// are loaded in the correct order.
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
intptr_t top =
reinterpret_cast<intptr_t>(new_space_allocation_top.address());
intptr_t limit =
@@ -1282,7 +1354,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
// Load allocation top into result and allocation limit into ip.
ldm(ia, topaddr, result.bit() | ip.bit());
} else {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Assert that result actually contains top on entry. ip is used
// immediately below so this use of ip does not cause difference with
// respect to register content between debug and release mode.
@@ -1316,7 +1388,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
Label* gc_required,
AllocationFlags flags) {
if (!FLAG_inline_new) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
mov(result, Operand(0x7091));
mov(scratch1, Operand(0x7191));
@@ -1340,9 +1412,9 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
// Also, assert that the registers are numbered such that the values
// are loaded in the correct order.
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
intptr_t top =
reinterpret_cast<intptr_t>(new_space_allocation_top.address());
intptr_t limit =
@@ -1360,7 +1432,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
// Load allocation top into result and allocation limit into ip.
ldm(ia, topaddr, result.bit() | ip.bit());
} else {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Assert that result actually contains top on entry. ip is used
// immediately below so this use of ip does not cause difference with
// respect to register content between debug and release mode.
@@ -1385,7 +1457,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
b(hi, gc_required);
// Update allocation top. result temporarily holds the new top.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
tst(scratch2, Operand(kObjectAlignmentMask));
Check(eq, "Unaligned allocation in new space");
}
@@ -1401,7 +1473,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
void MacroAssembler::UndoAllocationInNewSpace(Register object,
Register scratch) {
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
// Make sure the object has no tag before resetting top.
and_(object, object, Operand(~kHeapObjectTagMask));
@@ -1689,7 +1761,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
// No more valid handles (the result handle was the last one). Restore
// previous handle scope.
str(r4, MemOperand(r7, kNextOffset));
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
ldr(r1, MemOperand(r7, kLevelOffset));
cmp(r1, r6);
Check(eq, "Unexpected level after return from api call");
@@ -1703,7 +1775,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
// Check if the function scheduled an exception.
bind(&leave_exit_frame);
LoadRoot(r4, Heap::kTheHoleValueRootIndex);
- mov(ip, Operand(ExternalReference::scheduled_exception_address()));
+ mov(ip, Operand(ExternalReference::scheduled_exception_address(isolate())));
ldr(r5, MemOperand(ip));
cmp(r4, r5);
b(ne, &promote_scheduled_exception);
@@ -1714,8 +1786,11 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
mov(pc, lr);
bind(&promote_scheduled_exception);
- MaybeObject* result = TryTailCallExternalReference(
- ExternalReference(Runtime::kPromoteScheduledException), 0, 1);
+ MaybeObject* result
+ = TryTailCallExternalReference(
+ ExternalReference(Runtime::kPromoteScheduledException, isolate()),
+ 0,
+ 1);
if (result->IsFailure()) {
return result;
}
@@ -1725,7 +1800,8 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
str(r5, MemOperand(r7, kLimitOffset));
mov(r4, r0);
PrepareCallCFunction(0, r5);
- CallCFunction(ExternalReference::delete_handle_scope_extensions(), 0);
+ CallCFunction(
+ ExternalReference::delete_handle_scope_extensions(isolate()), 0);
mov(r0, r4);
jmp(&leave_exit_frame);
@@ -1826,7 +1902,7 @@ void MacroAssembler::ConvertToInt32(Register source,
Register scratch2,
DwVfpRegister double_scratch,
Label *not_int32) {
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
sub(scratch, source, Operand(kHeapObjectTag));
vldr(double_scratch, scratch, HeapNumber::kValueOffset);
@@ -1922,7 +1998,7 @@ void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode,
Register scratch1,
Register scratch2,
CheckForInexactConversion check_inexact) {
- ASSERT(CpuFeatures::IsSupported(VFP3));
+ ASSERT(Isolate::Current()->cpu_features()->IsSupported(VFP3));
CpuFeatures::Scope scope(VFP3);
Register prev_fpscr = scratch1;
Register scratch = scratch2;
@@ -1962,10 +2038,125 @@ void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode,
}
+void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result,
+ Register input_high,
+ Register input_low,
+ Register scratch) {
+ Label done, normal_exponent, restore_sign;
+
+ // Extract the biased exponent in result.
+ Ubfx(result,
+ input_high,
+ HeapNumber::kExponentShift,
+ HeapNumber::kExponentBits);
+
+ // Check for Infinity and NaNs, which should return 0.
+ cmp(result, Operand(HeapNumber::kExponentMask));
+ mov(result, Operand(0), LeaveCC, eq);
+ b(eq, &done);
+
+ // Express exponent as delta to (number of mantissa bits + 31).
+ sub(result,
+ result,
+ Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31),
+ SetCC);
+
+ // If the delta is strictly positive, all bits would be shifted away,
+ // which means that we can return 0.
+ b(le, &normal_exponent);
+ mov(result, Operand(0));
+ b(&done);
+
+ bind(&normal_exponent);
+ const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1;
+ // Calculate shift.
+ add(scratch, result, Operand(kShiftBase + HeapNumber::kMantissaBits), SetCC);
+
+ // Save the sign.
+ Register sign = result;
+ result = no_reg;
+ and_(sign, input_high, Operand(HeapNumber::kSignMask));
+
+ // Set the implicit 1 before the mantissa part in input_high.
+ orr(input_high,
+ input_high,
+ Operand(1 << HeapNumber::kMantissaBitsInTopWord));
+ // Shift the mantissa bits to the correct position.
+ // We don't need to clear non-mantissa bits as they will be shifted away.
+ // If they weren't, it would mean that the answer is in the 32bit range.
+ mov(input_high, Operand(input_high, LSL, scratch));
+
+ // Replace the shifted bits with bits from the lower mantissa word.
+ Label pos_shift, shift_done;
+ rsb(scratch, scratch, Operand(32), SetCC);
+ b(&pos_shift, ge);
+
+ // Negate scratch.
+ rsb(scratch, scratch, Operand(0));
+ mov(input_low, Operand(input_low, LSL, scratch));
+ b(&shift_done);
+
+ bind(&pos_shift);
+ mov(input_low, Operand(input_low, LSR, scratch));
+
+ bind(&shift_done);
+ orr(input_high, input_high, Operand(input_low));
+ // Restore sign if necessary.
+ cmp(sign, Operand(0));
+ result = sign;
+ sign = no_reg;
+ rsb(result, input_high, Operand(0), LeaveCC, ne);
+ mov(result, input_high, LeaveCC, eq);
+ bind(&done);
+}
+
+
+void MacroAssembler::EmitECMATruncate(Register result,
+ DwVfpRegister double_input,
+ SwVfpRegister single_scratch,
+ Register scratch,
+ Register input_high,
+ Register input_low) {
+ CpuFeatures::Scope scope(VFP3);
+ ASSERT(!input_high.is(result));
+ ASSERT(!input_low.is(result));
+ ASSERT(!input_low.is(input_high));
+ ASSERT(!scratch.is(result) &&
+ !scratch.is(input_high) &&
+ !scratch.is(input_low));
+ ASSERT(!single_scratch.is(double_input.low()) &&
+ !single_scratch.is(double_input.high()));
+
+ Label done;
+
+ // Clear cumulative exception flags.
+ ClearFPSCRBits(kVFPExceptionMask, scratch);
+ // Try a conversion to a signed integer.
+ vcvt_s32_f64(single_scratch, double_input);
+ vmov(result, single_scratch);
+ // Retrieve he FPSCR.
+ vmrs(scratch);
+ // Check for overflow and NaNs.
+ tst(scratch, Operand(kVFPOverflowExceptionBit |
+ kVFPUnderflowExceptionBit |
+ kVFPInvalidOpExceptionBit));
+ // If we had no exceptions we are done.
+ b(eq, &done);
+
+ // Load the double value and perform a manual truncation.
+ vmov(input_low, input_high, double_input);
+ EmitOutOfInt32RangeTruncate(result,
+ input_high,
+ input_low,
+ scratch);
+ bind(&done);
+}
+
+
void MacroAssembler::GetLeastBitsFromSmi(Register dst,
Register src,
int num_least_bits) {
- if (CpuFeatures::IsSupported(ARMv7)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
ubfx(dst, src, kSmiTagSize, num_least_bits);
} else {
mov(dst, Operand(src, ASR, kSmiTagSize));
@@ -1981,7 +2172,8 @@ void MacroAssembler::GetLeastBitsFromInt32(Register dst,
}
-void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
+void MacroAssembler::CallRuntime(const Runtime::Function* f,
+ int num_arguments) {
// All parameters are on the stack. r0 has the return value after call.
// If the expected number of arguments of the runtime function is
@@ -1997,7 +2189,7 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
// should remove this need and make the runtime routine entry code
// smarter.
mov(r0, Operand(num_arguments));
- mov(r1, Operand(ExternalReference(f)));
+ mov(r1, Operand(ExternalReference(f, isolate())));
CEntryStub stub(1);
CallStub(&stub);
}
@@ -2009,9 +2201,9 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId fid, int num_arguments) {
void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
- Runtime::Function* function = Runtime::FunctionForId(id);
+ const Runtime::Function* function = Runtime::FunctionForId(id);
mov(r0, Operand(function->nargs));
- mov(r1, Operand(ExternalReference(function)));
+ mov(r1, Operand(ExternalReference(function, isolate())));
CEntryStub stub(1);
stub.SaveDoubles();
CallStub(&stub);
@@ -2054,7 +2246,9 @@ MaybeObject* MacroAssembler::TryTailCallExternalReference(
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size) {
- TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
+ TailCallExternalReference(ExternalReference(fid, isolate()),
+ num_arguments,
+ result_size);
}
@@ -2083,11 +2277,12 @@ MaybeObject* MacroAssembler::TryJumpToExternalReference(
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flags,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
GetBuiltinEntry(r2, id);
if (flags == CALL_JS) {
+ if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(r2));
Call(r2);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ if (call_wrapper != NULL) call_wrapper->AfterCall();
} else {
ASSERT(flags == JUMP_JS);
Jump(r2);
@@ -2149,14 +2344,14 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
void MacroAssembler::Assert(Condition cond, const char* msg) {
- if (FLAG_debug_code)
+ if (emit_debug_code())
Check(cond, msg);
}
void MacroAssembler::AssertRegisterIsRoot(Register reg,
Heap::RootListIndex index) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
LoadRoot(ip, index);
cmp(reg, ip);
Check(eq, "Register did not match expected root");
@@ -2165,7 +2360,7 @@ void MacroAssembler::AssertRegisterIsRoot(Register reg,
void MacroAssembler::AssertFastElements(Register elements) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
ASSERT(!elements.is(ip));
Label ok;
push(elements);
@@ -2253,7 +2448,7 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
// (i.e., the static scope chain and runtime context chain do not agree).
// A variable occurring in such a scope should have slot type LOOKUP and
// not CONTEXT.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
ldr(ip, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
cmp(dst, ip);
Check(eq, "Yo dawg, I heard you liked function contexts "
@@ -2278,7 +2473,7 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
Register scratch) {
// Load the initial map. The global functions all have initial maps.
ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
Label ok, fail;
CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false);
b(&ok);
@@ -2300,6 +2495,18 @@ void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
}
+void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(
+ Register reg,
+ Register scratch,
+ Label* zero_and_neg,
+ Label* not_power_of_two) {
+ sub(scratch, reg, Operand(1), SetCC);
+ b(mi, zero_and_neg);
+ tst(scratch, reg);
+ b(ne, not_power_of_two);
+}
+
+
void MacroAssembler::JumpIfNotBothSmi(Register reg1,
Register reg2,
Label* on_not_both_smi) {
@@ -2486,7 +2693,7 @@ void MacroAssembler::CopyBytes(Register src,
// Copy bytes in word size chunks.
bind(&word_loop);
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
tst(src, Operand(kPointerSize - 1));
Assert(eq, "Expecting alignment for CopyBytes");
}
@@ -2585,11 +2792,17 @@ void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(Register type,
b(ne, failure);
}
+static const int kRegisterPassedArguments = 4;
void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
int frame_alignment = ActivationFrameAlignment();
+
+ // Reserve space for Isolate address which is always passed as last parameter
+ num_arguments += 1;
+
// Up to four simple arguments are passed in registers r0..r3.
- int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4;
+ int stack_passed_arguments = (num_arguments <= kRegisterPassedArguments) ?
+ 0 : num_arguments - kRegisterPassedArguments;
if (frame_alignment > kPointerSize) {
// Make stack end at alignment and make room for num_arguments - 4 words
// and the original value of sp.
@@ -2606,17 +2819,41 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
void MacroAssembler::CallCFunction(ExternalReference function,
int num_arguments) {
- mov(ip, Operand(function));
- CallCFunction(ip, num_arguments);
+ CallCFunctionHelper(no_reg, function, ip, num_arguments);
}
+void MacroAssembler::CallCFunction(Register function,
+ Register scratch,
+ int num_arguments) {
+ CallCFunctionHelper(function,
+ ExternalReference::the_hole_value_location(isolate()),
+ scratch,
+ num_arguments);
+}
+
+
+void MacroAssembler::CallCFunctionHelper(Register function,
+ ExternalReference function_reference,
+ Register scratch,
+ int num_arguments) {
+ // Push Isolate address as the last argument.
+ if (num_arguments < kRegisterPassedArguments) {
+ Register arg_to_reg[] = {r0, r1, r2, r3};
+ Register r = arg_to_reg[num_arguments];
+ mov(r, Operand(ExternalReference::isolate_address()));
+ } else {
+ int stack_passed_arguments = num_arguments - kRegisterPassedArguments;
+ // Push Isolate address on the stack after the arguments.
+ mov(scratch, Operand(ExternalReference::isolate_address()));
+ str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
+ }
+ num_arguments += 1;
-void MacroAssembler::CallCFunction(Register function, int num_arguments) {
// Make sure that the stack is aligned before calling a C function unless
// running in the simulator. The simulator has its own alignment check which
// provides more information.
#if defined(V8_HOST_ARCH_ARM)
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
int frame_alignment = OS::ActivationFrameAlignment();
int frame_alignment_mask = frame_alignment - 1;
if (frame_alignment > kPointerSize) {
@@ -2635,8 +2872,13 @@ void MacroAssembler::CallCFunction(Register function, int num_arguments) {
// Just call directly. The function called cannot cause a GC, or
// allow preemption, so the return address in the link register
// stays correct.
+ if (function.is(no_reg)) {
+ mov(scratch, Operand(function_reference));
+ function = scratch;
+ }
Call(function);
- int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4;
+ int stack_passed_arguments = (num_arguments <= kRegisterPassedArguments) ?
+ 0 : num_arguments - kRegisterPassedArguments;
if (OS::ActivationFrameAlignment() > kPointerSize) {
ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
@@ -2650,7 +2892,7 @@ void MacroAssembler::GetRelocatedValueLocation(Register ldr_location,
const uint32_t kLdrOffsetMask = (1 << 12) - 1;
const int32_t kPCRegOffset = 2 * kPointerSize;
ldr(result, MemOperand(ldr_location));
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Check that the instruction is a ldr reg, [pc + offset] .
and_(result, result, Operand(kLdrPCPattern));
cmp(result, Operand(kLdrPCPattern));
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index aaf4458e..2b81c086 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -34,7 +34,7 @@ namespace v8 {
namespace internal {
// Forward declaration.
-class PostCallGenerator;
+class CallWrapper;
// ----------------------------------------------------------------------------
// Static helper functions
@@ -96,8 +96,11 @@ class MacroAssembler: public Assembler {
void Jump(Register target, Condition cond = al);
void Jump(byte* target, RelocInfo::Mode rmode, Condition cond = al);
void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
+ int CallSize(Register target, Condition cond = al);
void Call(Register target, Condition cond = al);
+ int CallSize(byte* target, RelocInfo::Mode rmode, Condition cond = al);
void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
+ int CallSize(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
void Ret(Condition cond = al);
@@ -343,7 +346,7 @@ class MacroAssembler: public Assembler {
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
void InvokeCode(Handle<Code> code,
const ParameterCount& expected,
@@ -356,7 +359,7 @@ class MacroAssembler: public Assembler {
void InvokeFunction(Register function,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
void InvokeFunction(JSFunction* function,
const ParameterCount& actual,
@@ -646,11 +649,11 @@ class MacroAssembler: public Assembler {
DwVfpRegister double_scratch,
Label *not_int32);
-// Truncates a double using a specific rounding mode.
-// Clears the z flag (ne condition) if an overflow occurs.
-// If exact_conversion is true, the z flag is also cleared if the conversion
-// was inexact, ie. if the double value could not be converted exactly
-// to a 32bit integer.
+ // Truncates a double using a specific rounding mode.
+ // Clears the z flag (ne condition) if an overflow occurs.
+ // If exact_conversion is true, the z flag is also cleared if the conversion
+ // was inexact, ie. if the double value could not be converted exactly
+ // to a 32bit integer.
void EmitVFPTruncate(VFPRoundingMode rounding_mode,
SwVfpRegister result,
DwVfpRegister double_input,
@@ -659,6 +662,27 @@ class MacroAssembler: public Assembler {
CheckForInexactConversion check
= kDontCheckForInexactConversion);
+ // Helper for EmitECMATruncate.
+ // This will truncate a floating-point value outside of the singed 32bit
+ // integer range to a 32bit signed integer.
+ // Expects the double value loaded in input_high and input_low.
+ // Exits with the answer in 'result'.
+ // Note that this code does not work for values in the 32bit range!
+ void EmitOutOfInt32RangeTruncate(Register result,
+ Register input_high,
+ Register input_low,
+ Register scratch);
+
+ // Performs a truncating conversion of a floating point number as used by
+ // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
+ // Exits with 'result' holding the answer and all other registers clobbered.
+ void EmitECMATruncate(Register result,
+ DwVfpRegister double_input,
+ SwVfpRegister single_scratch,
+ Register scratch,
+ Register scratch2,
+ Register scratch3);
+
// Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz
// instruction. On pre-ARM5 hardware this routine gives the wrong answer
// for 0 (31 instead of 32). Source and scratch can be the same in which case
@@ -684,7 +708,7 @@ class MacroAssembler: public Assembler {
Condition cond = al);
// Call a runtime routine.
- void CallRuntime(Runtime::Function* f, int num_arguments);
+ void CallRuntime(const Runtime::Function* f, int num_arguments);
void CallRuntimeSaveDoubles(Runtime::FunctionId id);
// Convenience function: Same as above, but takes the fid instead.
@@ -728,7 +752,7 @@ class MacroAssembler: public Assembler {
// return address (unless this is somehow accounted for by the called
// function).
void CallCFunction(ExternalReference function, int num_arguments);
- void CallCFunction(Register function, int num_arguments);
+ void CallCFunction(Register function, Register scratch, int num_arguments);
void GetCFunctionDoubleResult(const DoubleRegister dst);
@@ -748,7 +772,7 @@ class MacroAssembler: public Assembler {
// the unresolved list if the name does not resolve.
void InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flags,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
// Store the code object for the given builtin in the target register and
// setup the function in r1.
@@ -802,6 +826,16 @@ class MacroAssembler: public Assembler {
void JumpIfNotPowerOfTwoOrZero(Register reg,
Register scratch,
Label* not_power_of_two_or_zero);
+ // Check whether the value of reg is a power of two and not zero.
+ // Control falls through if it is, with scratch containing the mask
+ // value (reg - 1).
+ // Otherwise control jumps to the 'zero_and_neg' label if the value of reg is
+ // zero or negative, or jumps to the 'not_power_of_two' label if the value is
+ // strictly positive but not a power of two.
+ void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
+ Register scratch,
+ Label* zero_and_neg,
+ Label* not_power_of_two);
// ---------------------------------------------------------------------------
// Smi utilities
@@ -910,7 +944,13 @@ class MacroAssembler: public Assembler {
private:
+ void CallCFunctionHelper(Register function,
+ ExternalReference function_reference,
+ Register scratch,
+ int num_arguments);
+
void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
+ int CallSize(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
// Helper functions for generating invokes.
@@ -920,7 +960,7 @@ class MacroAssembler: public Assembler {
Register code_reg,
Label* done,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
// Activation support.
void EnterFrame(StackFrame::Type type);
@@ -984,11 +1024,15 @@ class CodePatcher {
// Helper class for generating code or data associated with the code
// right after a call instruction. As an example this can be used to
// generate safepoint data after calls for crankshaft.
-class PostCallGenerator {
+class CallWrapper {
public:
- PostCallGenerator() { }
- virtual ~PostCallGenerator() { }
- virtual void Generate() = 0;
+ CallWrapper() { }
+ virtual ~CallWrapper() { }
+ // Called just before emitting a call. Argument is the size of the generated
+ // call code.
+ virtual void BeforeCall(int call_size) = 0;
+ // Called just after emitting a call, i.e., at the return site for the call.
+ virtual void AfterCall() = 0;
};
diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc
index 1f6ed671..8d540d42 100644
--- a/src/arm/regexp-macro-assembler-arm.cc
+++ b/src/arm/regexp-macro-assembler-arm.cc
@@ -60,6 +60,7 @@ namespace internal {
* Each call to a public method should retain this convention.
*
* The stack will have the following structure:
+ * - fp[52] Isolate* isolate (Address of the current isolate)
* - fp[48] direct_call (if 1, direct call from JavaScript code,
* if 0, call through the runtime system).
* - fp[44] stack_area_base (High end of the memory area to use as
@@ -368,7 +369,7 @@ void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
__ add(r1, current_input_offset(), Operand(end_of_input_address()));
ExternalReference function =
- ExternalReference::re_case_insensitive_compare_uc16();
+ ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
__ CallCFunction(function, argument_count);
// Check if function returned non-zero for success or zero for failure.
@@ -626,7 +627,7 @@ Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(masm_->isolate());
__ mov(r0, Operand(stack_limit));
__ ldr(r0, MemOperand(r0));
__ sub(r0, sp, r0, SetCC);
@@ -782,7 +783,7 @@ Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
__ mov(r0, backtrack_stackpointer());
__ add(r1, frame_pointer(), Operand(kStackHighEnd));
ExternalReference grow_stack =
- ExternalReference::re_grow_stack();
+ ExternalReference::re_grow_stack(masm_->isolate());
__ CallCFunction(grow_stack, num_arguments);
// If return NULL, we have failed to grow the stack, and
// must exit with a stack-overflow exception.
@@ -804,10 +805,10 @@ Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
CodeDesc code_desc;
masm_->GetCode(&code_desc);
- Handle<Code> code = Factory::NewCode(code_desc,
+ Handle<Code> code = FACTORY->NewCode(code_desc,
Code::ComputeFlags(Code::REGEXP),
masm_->CodeObject());
- PROFILE(RegExpCodeCreateEvent(*code, *source));
+ PROFILE(Isolate::Current(), RegExpCodeCreateEvent(*code, *source));
return Handle<Object>::cast(code);
}
@@ -998,7 +999,7 @@ void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) {
__ mov(r1, Operand(masm_->CodeObject()));
// r0 becomes return address pointer.
ExternalReference stack_guard_check =
- ExternalReference::re_check_stack_guard_state();
+ ExternalReference::re_check_stack_guard_state(masm_->isolate());
CallCFunctionUsingStub(stack_guard_check, num_arguments);
}
@@ -1013,8 +1014,10 @@ static T& frame_entry(Address re_frame, int frame_offset) {
int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame) {
- if (StackGuard::IsStackOverflow()) {
- Top::StackOverflow();
+ Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
+ ASSERT(isolate == Isolate::Current());
+ if (isolate->stack_guard()->IsStackOverflow()) {
+ isolate->StackOverflow();
return EXCEPTION;
}
@@ -1158,7 +1161,7 @@ void RegExpMacroAssemblerARM::Pop(Register target) {
void RegExpMacroAssemblerARM::CheckPreemption() {
// Check for preemption.
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(masm_->isolate());
__ mov(r0, Operand(stack_limit));
__ ldr(r0, MemOperand(r0));
__ cmp(sp, r0);
@@ -1168,7 +1171,7 @@ void RegExpMacroAssemblerARM::CheckPreemption() {
void RegExpMacroAssemblerARM::CheckStackLimit() {
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit();
+ ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
__ mov(r0, Operand(stack_limit));
__ ldr(r0, MemOperand(r0));
__ cmp(backtrack_stackpointer(), Operand(r0));
diff --git a/src/arm/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h
index d9d0b356..b57d0ebb 100644
--- a/src/arm/regexp-macro-assembler-arm.h
+++ b/src/arm/regexp-macro-assembler-arm.h
@@ -127,6 +127,7 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler {
static const int kRegisterOutput = kSecondaryReturnAddress + kPointerSize;
static const int kStackHighEnd = kRegisterOutput + kPointerSize;
static const int kDirectCall = kStackHighEnd + kPointerSize;
+ static const int kIsolate = kDirectCall + kPointerSize;
// Below the frame pointer.
// Register parameters stored by setup code.
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index f475a18b..46797d95 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -49,12 +49,12 @@ namespace internal {
// Windows C Run-Time Library does not provide vsscanf.
#define SScanF sscanf // NOLINT
-// The Debugger class is used by the simulator while debugging simulated ARM
+// The ArmDebugger class is used by the simulator while debugging simulated ARM
// code.
-class Debugger {
+class ArmDebugger {
public:
- explicit Debugger(Simulator* sim);
- ~Debugger();
+ explicit ArmDebugger(Simulator* sim);
+ ~ArmDebugger();
void Stop(Instruction* instr);
void Debug();
@@ -83,12 +83,12 @@ class Debugger {
};
-Debugger::Debugger(Simulator* sim) {
+ArmDebugger::ArmDebugger(Simulator* sim) {
sim_ = sim;
}
-Debugger::~Debugger() {
+ArmDebugger::~ArmDebugger() {
}
@@ -105,7 +105,7 @@ static void InitializeCoverage() {
}
-void Debugger::Stop(Instruction* instr) {
+void ArmDebugger::Stop(Instruction* instr) {
// Get the stop code.
uint32_t code = instr->SvcValue() & kStopCodeMask;
// Retrieve the encoded address, which comes just after this stop.
@@ -137,7 +137,7 @@ static void InitializeCoverage() {
}
-void Debugger::Stop(Instruction* instr) {
+void ArmDebugger::Stop(Instruction* instr) {
// Get the stop code.
uint32_t code = instr->SvcValue() & kStopCodeMask;
// Retrieve the encoded address, which comes just after this stop.
@@ -159,7 +159,7 @@ void Debugger::Stop(Instruction* instr) {
#endif
-int32_t Debugger::GetRegisterValue(int regnum) {
+int32_t ArmDebugger::GetRegisterValue(int regnum) {
if (regnum == kPCRegister) {
return sim_->get_pc();
} else {
@@ -168,12 +168,12 @@ int32_t Debugger::GetRegisterValue(int regnum) {
}
-double Debugger::GetVFPDoubleRegisterValue(int regnum) {
+double ArmDebugger::GetVFPDoubleRegisterValue(int regnum) {
return sim_->get_double_from_d_register(regnum);
}
-bool Debugger::GetValue(const char* desc, int32_t* value) {
+bool ArmDebugger::GetValue(const char* desc, int32_t* value) {
int regnum = Registers::Number(desc);
if (regnum != kNoRegister) {
*value = GetRegisterValue(regnum);
@@ -189,7 +189,7 @@ bool Debugger::GetValue(const char* desc, int32_t* value) {
}
-bool Debugger::GetVFPSingleValue(const char* desc, float* value) {
+bool ArmDebugger::GetVFPSingleValue(const char* desc, float* value) {
bool is_double;
int regnum = VFPRegisters::Number(desc, &is_double);
if (regnum != kNoRegister && !is_double) {
@@ -200,7 +200,7 @@ bool Debugger::GetVFPSingleValue(const char* desc, float* value) {
}
-bool Debugger::GetVFPDoubleValue(const char* desc, double* value) {
+bool ArmDebugger::GetVFPDoubleValue(const char* desc, double* value) {
bool is_double;
int regnum = VFPRegisters::Number(desc, &is_double);
if (regnum != kNoRegister && is_double) {
@@ -211,7 +211,7 @@ bool Debugger::GetVFPDoubleValue(const char* desc, double* value) {
}
-bool Debugger::SetBreakpoint(Instruction* breakpc) {
+bool ArmDebugger::SetBreakpoint(Instruction* breakpc) {
// Check if a breakpoint can be set. If not return without any side-effects.
if (sim_->break_pc_ != NULL) {
return false;
@@ -226,7 +226,7 @@ bool Debugger::SetBreakpoint(Instruction* breakpc) {
}
-bool Debugger::DeleteBreakpoint(Instruction* breakpc) {
+bool ArmDebugger::DeleteBreakpoint(Instruction* breakpc) {
if (sim_->break_pc_ != NULL) {
sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
}
@@ -237,21 +237,21 @@ bool Debugger::DeleteBreakpoint(Instruction* breakpc) {
}
-void Debugger::UndoBreakpoints() {
+void ArmDebugger::UndoBreakpoints() {
if (sim_->break_pc_ != NULL) {
sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
}
}
-void Debugger::RedoBreakpoints() {
+void ArmDebugger::RedoBreakpoints() {
if (sim_->break_pc_ != NULL) {
sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
}
}
-void Debugger::Debug() {
+void ArmDebugger::Debug() {
intptr_t last_pc = -1;
bool done = false;
@@ -316,16 +316,26 @@ void Debugger::Debug() {
}
for (int i = 0; i < kNumVFPDoubleRegisters; i++) {
dvalue = GetVFPDoubleRegisterValue(i);
- PrintF("%3s: %f\n",
- VFPRegisters::Name(i, true), dvalue);
+ uint64_t as_words = BitCast<uint64_t>(dvalue);
+ PrintF("%3s: %f 0x%08x %08x\n",
+ VFPRegisters::Name(i, true),
+ dvalue,
+ static_cast<uint32_t>(as_words >> 32),
+ static_cast<uint32_t>(as_words & 0xffffffff));
}
} else {
if (GetValue(arg1, &value)) {
PrintF("%s: 0x%08x %d \n", arg1, value, value);
} else if (GetVFPSingleValue(arg1, &svalue)) {
- PrintF("%s: %f \n", arg1, svalue);
+ uint32_t as_word = BitCast<uint32_t>(svalue);
+ PrintF("%s: %f 0x%08x\n", arg1, svalue, as_word);
} else if (GetVFPDoubleValue(arg1, &dvalue)) {
- PrintF("%s: %f \n", arg1, dvalue);
+ uint64_t as_words = BitCast<uint64_t>(dvalue);
+ PrintF("%s: %f 0x%08x %08x\n",
+ arg1,
+ dvalue,
+ static_cast<uint32_t>(as_words >> 32),
+ static_cast<uint32_t>(as_words & 0xffffffff));
} else {
PrintF("%s unrecognized\n", arg1);
}
@@ -380,11 +390,24 @@ void Debugger::Debug() {
end = cur + words;
while (cur < end) {
- PrintF(" 0x%08x: 0x%08x %10d\n",
+ PrintF(" 0x%08x: 0x%08x %10d",
reinterpret_cast<intptr_t>(cur), *cur, *cur);
+ HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
+ int value = *cur;
+ Heap* current_heap = v8::internal::Isolate::Current()->heap();
+ if (current_heap->Contains(obj) || ((value & 1) == 0)) {
+ PrintF(" (");
+ if ((value & 1) == 0) {
+ PrintF("smi %d", value / 2);
+ } else {
+ obj->ShortPrint();
+ }
+ PrintF(")");
+ }
+ PrintF("\n");
cur++;
}
- } else if (strcmp(cmd, "disasm") == 0) {
+ } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
disasm::NameConverter converter;
disasm::Disassembler dasm(converter);
// use a reasonably large buffer
@@ -398,11 +421,23 @@ void Debugger::Debug() {
cur = reinterpret_cast<byte*>(sim_->get_pc());
end = cur + (10 * Instruction::kInstrSize);
} else if (argc == 2) {
- int32_t value;
- if (GetValue(arg1, &value)) {
- cur = reinterpret_cast<byte*>(sim_->get_pc());
- // Disassemble <arg1> instructions.
- end = cur + (value * Instruction::kInstrSize);
+ int regnum = Registers::Number(arg1);
+ if (regnum != kNoRegister || strncmp(arg1, "0x", 2) == 0) {
+ // The argument is an address or a register name.
+ int32_t value;
+ if (GetValue(arg1, &value)) {
+ cur = reinterpret_cast<byte*>(value);
+ // Disassemble 10 instructions at <arg1>.
+ end = cur + (10 * Instruction::kInstrSize);
+ }
+ } else {
+ // The argument is the number of instructions.
+ int32_t value;
+ if (GetValue(arg1, &value)) {
+ cur = reinterpret_cast<byte*>(sim_->get_pc());
+ // Disassemble <arg1> instructions.
+ end = cur + (value * Instruction::kInstrSize);
+ }
}
} else {
int32_t value1;
@@ -524,8 +559,10 @@ void Debugger::Debug() {
PrintF("mem <address> [<words>]\n");
PrintF(" dump memory content, default dump 10 words)\n");
PrintF("disasm [<instructions>]\n");
- PrintF("disasm [[<address>] <instructions>]\n");
- PrintF(" disassemble code, default is 10 instructions from pc\n");
+ PrintF("disasm [<address/register>]\n");
+ PrintF("disasm [[<address/register>] <instructions>]\n");
+ PrintF(" disassemble code, default is 10 instructions\n");
+ PrintF(" from pc (alias 'di')\n");
PrintF("gdb\n");
PrintF(" enter gdb\n");
PrintF("break <address>\n");
@@ -539,11 +576,11 @@ void Debugger::Debug() {
PrintF(" Stops are debug instructions inserted by\n");
PrintF(" the Assembler::stop() function.\n");
PrintF(" When hitting a stop, the Simulator will\n");
- PrintF(" stop and and give control to the Debugger.\n");
+ PrintF(" stop and and give control to the ArmDebugger.\n");
PrintF(" The first %d stop codes are watched:\n",
Simulator::kNumOfWatchedStops);
PrintF(" - They can be enabled / disabled: the Simulator\n");
- PrintF(" will / won't stop when hitting them.\n");
+ PrintF(" will / won't stop when hitting them.\n");
PrintF(" - The Simulator keeps track of how many times they \n");
PrintF(" are met. (See the info command.) Going over a\n");
PrintF(" disabled stop still increases its counter. \n");
@@ -593,7 +630,9 @@ static bool AllOnOnePage(uintptr_t start, int size) {
}
-void Simulator::FlushICache(void* start_addr, size_t size) {
+void Simulator::FlushICache(v8::internal::HashMap* i_cache,
+ void* start_addr,
+ size_t size) {
intptr_t start = reinterpret_cast<intptr_t>(start_addr);
int intra_line = (start & CachePage::kLineMask);
start -= intra_line;
@@ -602,22 +641,22 @@ void Simulator::FlushICache(void* start_addr, size_t size) {
int offset = (start & CachePage::kPageMask);
while (!AllOnOnePage(start, size - 1)) {
int bytes_to_flush = CachePage::kPageSize - offset;
- FlushOnePage(start, bytes_to_flush);
+ FlushOnePage(i_cache, start, bytes_to_flush);
start += bytes_to_flush;
size -= bytes_to_flush;
ASSERT_EQ(0, start & CachePage::kPageMask);
offset = 0;
}
if (size != 0) {
- FlushOnePage(start, size);
+ FlushOnePage(i_cache, start, size);
}
}
-CachePage* Simulator::GetCachePage(void* page) {
- v8::internal::HashMap::Entry* entry = i_cache_->Lookup(page,
- ICacheHash(page),
- true);
+CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
+ v8::internal::HashMap::Entry* entry = i_cache->Lookup(page,
+ ICacheHash(page),
+ true);
if (entry->value == NULL) {
CachePage* new_page = new CachePage();
entry->value = new_page;
@@ -627,25 +666,28 @@ CachePage* Simulator::GetCachePage(void* page) {
// Flush from start up to and not including start + size.
-void Simulator::FlushOnePage(intptr_t start, int size) {
+void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
+ intptr_t start,
+ int size) {
ASSERT(size <= CachePage::kPageSize);
ASSERT(AllOnOnePage(start, size - 1));
ASSERT((start & CachePage::kLineMask) == 0);
ASSERT((size & CachePage::kLineMask) == 0);
void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
int offset = (start & CachePage::kPageMask);
- CachePage* cache_page = GetCachePage(page);
+ CachePage* cache_page = GetCachePage(i_cache, page);
char* valid_bytemap = cache_page->ValidityByte(offset);
memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
}
-void Simulator::CheckICache(Instruction* instr) {
+void Simulator::CheckICache(v8::internal::HashMap* i_cache,
+ Instruction* instr) {
intptr_t address = reinterpret_cast<intptr_t>(instr);
void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
int offset = (address & CachePage::kPageMask);
- CachePage* cache_page = GetCachePage(page);
+ CachePage* cache_page = GetCachePage(i_cache, page);
char* cache_valid_byte = cache_page->ValidityByte(offset);
bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
@@ -662,27 +704,18 @@ void Simulator::CheckICache(Instruction* instr) {
}
-// Create one simulator per thread and keep it in thread local storage.
-static v8::internal::Thread::LocalStorageKey simulator_key;
-
-
-bool Simulator::initialized_ = false;
-
-
void Simulator::Initialize() {
- if (initialized_) return;
- simulator_key = v8::internal::Thread::CreateThreadLocalKey();
- initialized_ = true;
+ if (Isolate::Current()->simulator_initialized()) return;
+ Isolate::Current()->set_simulator_initialized(true);
::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference);
}
-v8::internal::HashMap* Simulator::i_cache_ = NULL;
-
-
-Simulator::Simulator() {
+Simulator::Simulator() : isolate_(Isolate::Current()) {
+ i_cache_ = isolate_->simulator_i_cache();
if (i_cache_ == NULL) {
i_cache_ = new v8::internal::HashMap(&ICacheMatch);
+ isolate_->set_simulator_i_cache(i_cache_);
}
Initialize();
// Setup simulator support first. Some of this information is needed to
@@ -748,11 +781,14 @@ class Redirection {
: external_function_(external_function),
swi_instruction_(al | (0xf*B24) | kCallRtRedirected),
type_(type),
- next_(list_) {
- Simulator::current()->
- FlushICache(reinterpret_cast<void*>(&swi_instruction_),
- Instruction::kInstrSize);
- list_ = this;
+ next_(NULL) {
+ Isolate* isolate = Isolate::Current();
+ next_ = isolate->simulator_redirection();
+ Simulator::current(isolate)->
+ FlushICache(isolate->simulator_i_cache(),
+ reinterpret_cast<void*>(&swi_instruction_),
+ Instruction::kInstrSize);
+ isolate->set_simulator_redirection(this);
}
void* address_of_swi_instruction() {
@@ -764,8 +800,9 @@ class Redirection {
static Redirection* Get(void* external_function,
ExternalReference::Type type) {
- Redirection* current;
- for (current = list_; current != NULL; current = current->next_) {
+ Isolate* isolate = Isolate::Current();
+ Redirection* current = isolate->simulator_redirection();
+ for (; current != NULL; current = current->next_) {
if (current->external_function_ == external_function) return current;
}
return new Redirection(external_function, type);
@@ -783,13 +820,9 @@ class Redirection {
uint32_t swi_instruction_;
ExternalReference::Type type_;
Redirection* next_;
- static Redirection* list_;
};
-Redirection* Redirection::list_ = NULL;
-
-
void* Simulator::RedirectExternalReference(void* external_function,
ExternalReference::Type type) {
Redirection* redirection = Redirection::Get(external_function, type);
@@ -798,14 +831,20 @@ void* Simulator::RedirectExternalReference(void* external_function,
// Get the active Simulator for the current thread.
-Simulator* Simulator::current() {
- Initialize();
- Simulator* sim = reinterpret_cast<Simulator*>(
- v8::internal::Thread::GetThreadLocal(simulator_key));
+Simulator* Simulator::current(Isolate* isolate) {
+ v8::internal::Isolate::PerIsolateThreadData* isolate_data =
+ Isolate::CurrentPerIsolateThreadData();
+ if (isolate_data == NULL) {
+ Isolate::EnterDefaultIsolate();
+ isolate_data = Isolate::CurrentPerIsolateThreadData();
+ }
+ ASSERT(isolate_data != NULL);
+
+ Simulator* sim = isolate_data->simulator();
if (sim == NULL) {
- // TODO(146): delete the simulator object when a thread goes away.
+ // TODO(146): delete the simulator object when a thread/isolate goes away.
sim = new Simulator();
- v8::internal::Thread::SetThreadLocal(simulator_key, sim);
+ isolate_data->set_simulator(sim);
}
return sim;
}
@@ -1533,7 +1572,8 @@ typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
int32_t arg1,
int32_t arg2,
int32_t arg3,
- int32_t arg4);
+ int32_t arg4,
+ int32_t arg5);
typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
int32_t arg1,
int32_t arg2,
@@ -1564,7 +1604,8 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
int32_t arg2 = get_register(r2);
int32_t arg3 = get_register(r3);
int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
- int32_t arg4 = *stack_pointer;
+ int32_t arg4 = stack_pointer[0];
+ int32_t arg5 = stack_pointer[1];
// This is dodgy but it works because the C entry stubs are never moved.
// See comment in codegen-arm.cc and bug 1242173.
int32_t saved_lr = get_register(lr);
@@ -1627,20 +1668,22 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
reinterpret_cast<SimulatorRuntimeCall>(external);
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
PrintF(
- "Call to host function at %p args %08x, %08x, %08x, %08x, %0xc",
+ "Call to host function at %p"
+ "args %08x, %08x, %08x, %08x, %08x, %08x",
FUNCTION_ADDR(target),
arg0,
arg1,
arg2,
arg3,
- arg4);
+ arg4,
+ arg5);
if (!stack_aligned) {
PrintF(" with unaligned stack %08x\n", get_register(sp));
}
PrintF("\n");
}
CHECK(stack_aligned);
- int64_t result = target(arg0, arg1, arg2, arg3, arg4);
+ int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
int32_t lo_res = static_cast<int32_t>(result);
int32_t hi_res = static_cast<int32_t>(result >> 32);
if (::v8::internal::FLAG_trace_sim) {
@@ -1654,7 +1697,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
break;
}
case kBreakpoint: {
- Debugger dbg(this);
+ ArmDebugger dbg(this);
dbg.Debug();
break;
}
@@ -1668,7 +1711,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
// Stop if it is enabled, otherwise go on jumping over the stop
// and the message address.
if (isEnabledStop(code)) {
- Debugger dbg(this);
+ ArmDebugger dbg(this);
dbg.Stop(instr);
} else {
set_pc(get_pc() + 2 * Instruction::kInstrSize);
@@ -1976,7 +2019,7 @@ void Simulator::DecodeType01(Instruction* instr) {
break;
}
case BKPT: {
- Debugger dbg(this);
+ ArmDebugger dbg(this);
PrintF("Simulator hit BKPT.\n");
dbg.Debug();
break;
@@ -2467,6 +2510,8 @@ void Simulator::DecodeType7(Instruction* instr) {
// vmov :Rt = Sn
// vcvt: Dd = Sm
// vcvt: Sd = Dm
+// Dd = vabs(Dm)
+// Dd = vneg(Dm)
// Dd = vadd(Dn, Dm)
// Dd = vsub(Dn, Dm)
// Dd = vmul(Dn, Dm)
@@ -2502,6 +2547,11 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
double dm_value = get_double_from_d_register(vm);
double dd_value = fabs(dm_value);
set_d_register_from_double(vd, dd_value);
+ } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
+ // vneg
+ double dm_value = get_double_from_d_register(vm);
+ double dd_value = -dm_value;
+ set_d_register_from_double(vd, dd_value);
} else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
DecodeVCVTBetweenDoubleAndSingle(instr);
} else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
@@ -2957,7 +3007,7 @@ void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
// Executes the current instruction.
void Simulator::InstructionDecode(Instruction* instr) {
if (v8::internal::FLAG_check_icache) {
- CheckICache(instr);
+ CheckICache(isolate_->simulator_i_cache(), instr);
}
pc_modified_ = false;
if (::v8::internal::FLAG_trace_sim) {
@@ -3040,7 +3090,7 @@ void Simulator::Execute() {
Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
icount_++;
if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
- Debugger dbg(this);
+ ArmDebugger dbg(this);
dbg.Debug();
} else {
InstructionDecode(instr);
diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h
index bdf1f8a1..b7b1b681 100644
--- a/src/arm/simulator-arm.h
+++ b/src/arm/simulator-arm.h
@@ -49,18 +49,19 @@ namespace internal {
(entry(p0, p1, p2, p3, p4))
typedef int (*arm_regexp_matcher)(String*, int, const byte*, const byte*,
- void*, int*, Address, int);
+ void*, int*, Address, int, Isolate*);
// Call the generated regexp code directly. The code at the entry address
// should act as a function matching the type arm_regexp_matcher.
// The fifth argument is a dummy that reserves the space used for
// the return address added by the ExitFrame in native calls.
-#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
- (FUNCTION_CAST<arm_regexp_matcher>(entry)(p0, p1, p2, p3, NULL, p4, p5, p6))
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
+ (FUNCTION_CAST<arm_regexp_matcher>(entry)( \
+ p0, p1, p2, p3, NULL, p4, p5, p6, p7))
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
- (reinterpret_cast<TryCatch*>(try_catch_address))
+ reinterpret_cast<TryCatch*>(try_catch_address)
// The stack limit beyond which we will throw stack overflow errors in
// generated code. Because generated code on arm uses the C stack, we
@@ -123,7 +124,7 @@ class CachePage {
class Simulator {
public:
- friend class Debugger;
+ friend class ArmDebugger;
enum Register {
no_reg = -1,
r0 = 0, r1, r2, r3, r4, r5, r6, r7,
@@ -147,7 +148,7 @@ class Simulator {
// The currently executing Simulator instance. Potentially there can be one
// for each native thread.
- static Simulator* current();
+ static Simulator* current(v8::internal::Isolate* isolate);
// Accessors for register state. Reading the pc value adheres to the ARM
// architecture specification and is off by a 8 from the currently executing
@@ -191,7 +192,8 @@ class Simulator {
uintptr_t PopAddress();
// ICache checking.
- static void FlushICache(void* start, size_t size);
+ static void FlushICache(v8::internal::HashMap* i_cache, void* start,
+ size_t size);
// Returns true if pc register contains one of the 'special_values' defined
// below (bad_lr, end_sim_pc).
@@ -287,9 +289,10 @@ class Simulator {
void InstructionDecode(Instruction* instr);
// ICache.
- static void CheckICache(Instruction* instr);
- static void FlushOnePage(intptr_t start, int size);
- static CachePage* GetCachePage(void* page);
+ static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
+ static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
+ int size);
+ static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
// Runtime call support.
static void* RedirectExternalReference(
@@ -333,15 +336,16 @@ class Simulator {
char* stack_;
bool pc_modified_;
int icount_;
- static bool initialized_;
// Icache simulation
- static v8::internal::HashMap* i_cache_;
+ v8::internal::HashMap* i_cache_;
// Registered breakpoints.
Instruction* break_pc_;
Instr break_instr_;
+ v8::internal::Isolate* isolate_;
+
// A stop is watched if its code is less than kNumOfWatchedStops.
// Only watched stops support enabling/disabling and the counter feature.
static const uint32_t kNumOfWatchedStops = 256;
@@ -364,15 +368,16 @@ class Simulator {
// When running with the simulator transition into simulated execution at this
// point.
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
- reinterpret_cast<Object*>(Simulator::current()->Call( \
+ reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
-#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
- Simulator::current()->Call(entry, 8, p0, p1, p2, p3, NULL, p4, p5, p6)
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
+ Simulator::current(Isolate::Current())->Call( \
+ entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7)
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
- try_catch_address == \
- NULL ? NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
+#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
+ try_catch_address == NULL ? \
+ NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
// The simulator has its own stack. Thus it has a different stack limit from
@@ -383,16 +388,16 @@ class Simulator {
class SimulatorStack : public v8::internal::AllStatic {
public:
static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
- return Simulator::current()->StackLimit();
+ return Simulator::current(Isolate::Current())->StackLimit();
}
static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
- Simulator* sim = Simulator::current();
+ Simulator* sim = Simulator::current(Isolate::Current());
return sim->PushAddress(try_catch_address);
}
static inline void UnregisterCTryCatch() {
- Simulator::current()->PopAddress();
+ Simulator::current(Isolate::Current())->PopAddress();
}
};
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 60a11f3c..9936ac03 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -39,15 +39,16 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-static void ProbeTable(MacroAssembler* masm,
+static void ProbeTable(Isolate* isolate,
+ MacroAssembler* masm,
Code::Flags flags,
StubCache::Table table,
Register name,
Register offset,
Register scratch,
Register scratch2) {
- ExternalReference key_offset(SCTableReference::keyReference(table));
- ExternalReference value_offset(SCTableReference::valueReference(table));
+ ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
+ ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
@@ -101,8 +102,9 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Register scratch0,
Register scratch1) {
ASSERT(name->IsSymbol());
- __ IncrementCounter(&Counters::negative_lookups, 1, scratch0, scratch1);
- __ IncrementCounter(&Counters::negative_lookups_miss, 1, scratch0, scratch1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
+ __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
Label done;
@@ -198,7 +200,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
}
}
__ bind(&done);
- __ DecrementCounter(&Counters::negative_lookups_miss, 1, scratch0, scratch1);
+ __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
}
@@ -209,6 +211,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
Register scratch,
Register extra,
Register extra2) {
+ Isolate* isolate = masm->isolate();
Label miss;
// Make sure that code is valid. The shifting code relies on the
@@ -248,7 +251,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
// Probe the primary table.
- ProbeTable(masm, flags, kPrimary, name, scratch, extra, extra2);
+ ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra, extra2);
// Primary miss: Compute hash for secondary probe.
__ sub(scratch, scratch, Operand(name));
@@ -258,7 +261,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
// Probe the secondary table.
- ProbeTable(masm, flags, kSecondary, name, scratch, extra, extra2);
+ ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra, extra2);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
@@ -286,13 +289,15 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
MacroAssembler* masm, int index, Register prototype, Label* miss) {
+ Isolate* isolate = masm->isolate();
// Check we're still in the same context.
__ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
- __ Move(ip, Top::global());
+ __ Move(ip, isolate->global());
__ cmp(prototype, ip);
__ b(ne, miss);
// Get the global function with the given index.
- JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
+ JSFunction* function =
+ JSFunction::cast(isolate->global_context()->get(index));
// Load its initial map. The global functions all have initial maps.
__ Move(prototype, Handle<Map>(function->initial_map()));
// Load the prototype from the initial map.
@@ -450,8 +455,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
__ mov(r2, Operand(Handle<Map>(transition)));
__ Push(r2, r0);
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)),
- 3, 1);
+ ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
+ masm->isolate()),
+ 3,
+ 1);
return;
}
@@ -505,9 +512,9 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
Code* code = NULL;
if (kind == Code::LOAD_IC) {
- code = Builtins::builtin(Builtins::LoadIC_Miss);
+ code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss);
} else {
- code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
+ code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss);
}
Handle<Code> ic(code);
@@ -548,7 +555,7 @@ static void PushInterceptorArguments(MacroAssembler* masm,
JSObject* holder_obj) {
__ push(name);
InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
- ASSERT(!Heap::InNewSpace(interceptor));
+ ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
Register scratch = name;
__ mov(scratch, Operand(Handle<Object>(interceptor)));
__ push(scratch);
@@ -567,7 +574,8 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
ExternalReference ref =
- ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
+ masm->isolate());
__ mov(r0, Operand(5));
__ mov(r1, Operand(ref));
@@ -616,7 +624,7 @@ static MaybeObject* GenerateFastApiDirectCall(MacroAssembler* masm,
// Pass the additional arguments FastHandleApiCall expects.
Object* call_data = optimization.api_call_info()->data();
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
- if (Heap::InNewSpace(call_data)) {
+ if (masm->isolate()->heap()->InNewSpace(call_data)) {
__ Move(r0, api_call_info_handle);
__ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
} else {
@@ -656,8 +664,9 @@ static MaybeObject* GenerateFastApiDirectCall(MacroAssembler* masm,
// garbage collection but instead return the allocation failure
// object.
const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
- ExternalReference ref =
- ExternalReference(&fun, ExternalReference::DIRECT_API_CALL);
+ ExternalReference ref = ExternalReference(&fun,
+ ExternalReference::DIRECT_API_CALL,
+ masm->isolate());
return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace);
}
@@ -710,7 +719,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
name,
holder,
miss);
- return Heap::undefined_value();
+ return masm->isolate()->heap()->undefined_value();
}
}
@@ -729,6 +738,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
ASSERT(optimization.is_constant_call());
ASSERT(!lookup->holder()->IsGlobalObject());
+ Counters* counters = masm->isolate()->counters();
+
int depth1 = kInvalidProtoDepth;
int depth2 = kInvalidProtoDepth;
bool can_do_fast_api_call = false;
@@ -746,11 +757,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
(depth2 != kInvalidProtoDepth);
}
- __ IncrementCounter(&Counters::call_const_interceptor, 1,
+ __ IncrementCounter(counters->call_const_interceptor(), 1,
scratch1, scratch2);
if (can_do_fast_api_call) {
- __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1,
+ __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
scratch1, scratch2);
ReserveSpaceForFastApiCall(masm, scratch1);
}
@@ -811,7 +822,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
FreeSpaceForFastApiCall(masm);
}
- return Heap::undefined_value();
+ return masm->isolate()->heap()->undefined_value();
}
void CompileRegular(MacroAssembler* masm,
@@ -840,9 +851,9 @@ class CallInterceptorCompiler BASE_EMBEDDED {
interceptor_holder);
__ CallExternalReference(
- ExternalReference(
- IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
- 5);
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
+ masm->isolate()),
+ 5);
// Restore the name_ register.
__ pop(name_);
@@ -942,7 +953,7 @@ static void StoreIntAsFloat(MacroAssembler* masm,
Register fval,
Register scratch1,
Register scratch2) {
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (masm->isolate()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ vmov(s0, ival);
__ add(scratch1, dst, Operand(wordoffset, LSL, 2));
@@ -1080,7 +1091,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
!current->IsJSGlobalObject() &&
!current->IsJSGlobalProxy()) {
if (!name->IsSymbol()) {
- MaybeObject* maybe_lookup_result = Heap::LookupSymbol(name);
+ MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name);
Object* lookup_result = NULL; // Initialization to please compiler.
if (!maybe_lookup_result->ToObject(&lookup_result)) {
set_failure(Failure::cast(maybe_lookup_result));
@@ -1100,7 +1111,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
__ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
reg = holder_reg; // from now the object is in holder_reg
__ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
- } else if (Heap::InNewSpace(prototype)) {
+ } else if (heap()->InNewSpace(prototype)) {
// Get the map of the current object.
__ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
__ cmp(scratch1, Operand(Handle<Map>(current->map())));
@@ -1154,7 +1165,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
__ b(ne, miss);
// Log the check depth.
- LOG(IntEvent("check-maps-depth", depth + 1));
+ LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
// Perform security check for access to the global object.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
@@ -1248,7 +1259,7 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
__ push(receiver);
__ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
Handle<AccessorInfo> callback_handle(callback);
- if (Heap::InNewSpace(callback_handle->data())) {
+ if (heap()->InNewSpace(callback_handle->data())) {
__ Move(scratch3, callback_handle);
__ ldr(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
} else {
@@ -1273,7 +1284,9 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
// object.
const int kStackUnwindSpace = 4;
ExternalReference ref =
- ExternalReference(&fun, ExternalReference::DIRECT_GETTER_CALL);
+ ExternalReference(&fun,
+ ExternalReference::DIRECT_GETTER_CALL,
+ masm()->isolate());
return masm()->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace);
}
@@ -1402,7 +1415,8 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
}
ExternalReference ref =
- ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
+ masm()->isolate());
__ TailCallExternalReference(ref, 5, 1);
}
} else { // !compile_followup_inline
@@ -1414,8 +1428,9 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
PushInterceptorArguments(masm(), receiver, holder_reg,
name_reg, interceptor_holder);
- ExternalReference ref = ExternalReference(
- IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
+ masm()->isolate());
__ TailCallExternalReference(ref, 5, 1);
}
}
@@ -1462,7 +1477,7 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
__ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function.
- if (Heap::InNewSpace(function)) {
+ if (heap()->InNewSpace(function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
@@ -1486,8 +1501,8 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
MaybeObject* CallStubCompiler::GenerateMissBranch() {
- MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(),
- kind_);
+ MaybeObject* maybe_obj = masm()->isolate()->stub_cache()->ComputeCallMiss(
+ arguments().immediate(), kind_);
Object* obj;
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
__ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
@@ -1523,10 +1538,8 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
// Handle call cache miss.
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(FIELD, name);
@@ -1547,7 +1560,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// -----------------------------------
// If object is not an array, bail out to regular call.
- if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
Label miss;
@@ -1633,10 +1646,11 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
__ b(&call_builtin);
}
+ Isolate* isolate = masm()->isolate();
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate);
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate);
const int kAllocationDelta = 4;
// Load top and check if it is the end of elements.
@@ -1676,17 +1690,16 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
__ Ret();
}
__ bind(&call_builtin);
- __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
+ __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
+ masm()->isolate()),
argc + 1,
1);
}
// Handle call cache miss.
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1707,7 +1720,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
// -----------------------------------
// If object is not an array, bail out to regular call.
- if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
Label miss, return_undefined, call_builtin;
@@ -1763,16 +1776,15 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
__ Ret();
__ bind(&call_builtin);
- __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
+ __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
+ masm()->isolate()),
argc + 1,
1);
// Handle call cache miss.
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1794,7 +1806,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// -----------------------------------
// If object is not a string, bail out to regular call.
- if (!object->IsString() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsString() || cell != NULL) return heap()->undefined_value();
const int argc = arguments().immediate();
@@ -1855,10 +1867,8 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// Restore function name in r2.
__ Move(r2, Handle<String>(name));
__ bind(&name_miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1880,7 +1890,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// -----------------------------------
// If object is not a string, bail out to regular call.
- if (!object->IsString() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsString() || cell != NULL) return heap()->undefined_value();
const int argc = arguments().immediate();
@@ -1943,10 +1953,8 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// Restore function name in r2.
__ Move(r2, Handle<String>(name));
__ bind(&name_miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1971,7 +1979,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
- if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
+ if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss;
GenerateNameCheck(name, &miss);
@@ -2019,10 +2027,8 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
__ bind(&miss);
// r2: function name.
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
@@ -2042,14 +2048,17 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
// -- sp[argc * 4] : receiver
// -----------------------------------
- if (!CpuFeatures::IsSupported(VFP3)) return Heap::undefined_value();
+ if (!masm()->isolate()->cpu_features()->IsSupported(VFP3)) {
+ return heap()->undefined_value();
+ }
+
CpuFeatures::Scope scope_vfp3(VFP3);
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
- if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
+ if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss, slow;
GenerateNameCheck(name, &miss);
@@ -2166,8 +2175,8 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
__ bind(&miss);
// r2: function name.
- MaybeObject* obj = GenerateMissBranch();
- if (obj->IsFailure()) return obj;
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
@@ -2191,7 +2200,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
- if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
+ if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss;
GenerateNameCheck(name, &miss);
@@ -2268,16 +2277,68 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
__ bind(&miss);
// r2: function name.
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
}
+MaybeObject* CallStubCompiler::CompileFastApiCall(
+ const CallOptimization& optimization,
+ Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
+ Counters* counters = isolate()->counters();
+
+ ASSERT(optimization.is_simple_api_call());
+ // Bail out if object is a global object as we don't want to
+ // repatch it to global receiver.
+ if (object->IsGlobalObject()) return heap()->undefined_value();
+ if (cell != NULL) return heap()->undefined_value();
+ int depth = optimization.GetPrototypeDepthOfExpectedType(
+ JSObject::cast(object), holder);
+ if (depth == kInvalidProtoDepth) return heap()->undefined_value();
+
+ Label miss, miss_before_stack_reserved;
+
+ GenerateNameCheck(name, &miss_before_stack_reserved);
+
+ // Get the receiver from the stack.
+ const int argc = arguments().immediate();
+ __ ldr(r1, MemOperand(sp, argc * kPointerSize));
+
+ // Check that the receiver isn't a smi.
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(eq, &miss_before_stack_reserved);
+
+ __ IncrementCounter(counters->call_const(), 1, r0, r3);
+ __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r3);
+
+ ReserveSpaceForFastApiCall(masm(), r0);
+
+ // Check that the maps haven't changed and find a Holder as a side effect.
+ CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
+ depth, &miss);
+
+ MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
+ if (result->IsFailure()) return result;
+
+ __ bind(&miss);
+ FreeSpaceForFastApiCall(masm());
+
+ __ bind(&miss_before_stack_reserved);
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
+
+ // Return the generated code.
+ return GetCode(function);
+}
+
+
MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
@@ -2287,22 +2348,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// -- r2 : name
// -- lr : return address
// -----------------------------------
- SharedFunctionInfo* function_info = function->shared();
- if (function_info->HasBuiltinFunctionId()) {
- BuiltinFunctionId id = function_info->builtin_function_id();
+ if (HasCustomCallGenerator(function)) {
MaybeObject* maybe_result = CompileCustomCall(
- id, object, holder, NULL, function, name);
+ object, holder, NULL, function, name);
Object* result;
if (!maybe_result->ToObject(&result)) return maybe_result;
// undefined means bail out to regular compiler.
- if (!result->IsUndefined()) {
- return result;
- }
+ if (!result->IsUndefined()) return result;
}
- Label miss_in_smi_check;
+ Label miss;
- GenerateNameCheck(name, &miss_in_smi_check);
+ GenerateNameCheck(name, &miss);
// Get the receiver from the stack
const int argc = arguments().immediate();
@@ -2311,39 +2368,26 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// Check that the receiver isn't a smi.
if (check != NUMBER_CHECK) {
__ tst(r1, Operand(kSmiTagMask));
- __ b(eq, &miss_in_smi_check);
+ __ b(eq, &miss);
}
// Make sure that it's okay not to patch the on stack receiver
// unless we're doing a receiver map check.
ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
- CallOptimization optimization(function);
- int depth = kInvalidProtoDepth;
- Label miss;
-
+ SharedFunctionInfo* function_info = function->shared();
switch (check) {
case RECEIVER_MAP_CHECK:
- __ IncrementCounter(&Counters::call_const, 1, r0, r3);
-
- if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
- depth = optimization.GetPrototypeDepthOfExpectedType(
- JSObject::cast(object), holder);
- }
-
- if (depth != kInvalidProtoDepth) {
- __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3);
- ReserveSpaceForFastApiCall(masm(), r0);
- }
+ __ IncrementCounter(masm()->isolate()->counters()->call_const(),
+ 1, r0, r3);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
- depth, &miss);
+ &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
if (object->IsGlobalObject()) {
- ASSERT(depth == kInvalidProtoDepth);
__ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
__ str(r3, MemOperand(sp, argc * kPointerSize));
}
@@ -2416,24 +2460,12 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
UNREACHABLE();
}
- if (depth != kInvalidProtoDepth) {
- MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
- if (result->IsFailure()) return result;
- } else {
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
- }
+ __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
// Handle call cache miss.
__ bind(&miss);
- if (depth != kInvalidProtoDepth) {
- FreeSpaceForFastApiCall(masm());
- }
-
- __ bind(&miss_in_smi_check);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -2485,10 +2517,8 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// Handle call cache miss.
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(INTERCEPTOR, name);
@@ -2505,11 +2535,9 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// -- lr : return address
// -----------------------------------
- SharedFunctionInfo* function_info = function->shared();
- if (function_info->HasBuiltinFunctionId()) {
- BuiltinFunctionId id = function_info->builtin_function_id();
+ if (HasCustomCallGenerator(function)) {
MaybeObject* maybe_result = CompileCustomCall(
- id, object, holder, cell, function, name);
+ object, holder, cell, function, name);
Object* result;
if (!maybe_result->ToObject(&result)) return maybe_result;
// undefined means bail out to regular compiler.
@@ -2538,7 +2566,8 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// Jump to the cached code (tail call).
- __ IncrementCounter(&Counters::call_global_inline, 1, r3, r4);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->call_global_inline(), 1, r3, r4);
ASSERT(function->is_compiled());
Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count());
@@ -2555,11 +2584,9 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// Handle call cache miss.
__ bind(&miss);
- __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ __ IncrementCounter(counters->call_global_inline_miss(), 1, r1, r3);
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(NORMAL, name);
@@ -2585,7 +2612,7 @@ MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
r1, r2, r3,
&miss);
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2628,12 +2655,13 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
// Do tail-call to the runtime system.
ExternalReference store_callback_property =
- ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
+ ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
+ masm()->isolate());
__ TailCallExternalReference(store_callback_property, 4, 1);
// Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2676,12 +2704,13 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
// Do tail-call to the runtime system.
ExternalReference store_ic_property =
- ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
+ ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
+ masm()->isolate());
__ TailCallExternalReference(store_ic_property, 4, 1);
// Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2718,13 +2747,14 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
// Store the value in the cell.
__ str(r0, FieldMemOperand(r4, JSGlobalPropertyCell::kValueOffset));
- __ IncrementCounter(&Counters::named_store_global_inline, 1, r4, r3);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->named_store_global_inline(), 1, r4, r3);
__ Ret();
// Handle store cache miss.
__ bind(&miss);
- __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r4, r3);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ __ IncrementCounter(counters->named_store_global_inline_miss(), 1, r4, r3);
+ Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2771,7 +2801,7 @@ MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
- return GetCode(NONEXISTENT, Heap::empty_string());
+ return GetCode(NONEXISTENT, heap()->empty_string());
}
@@ -2906,11 +2936,12 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
}
__ mov(r0, r4);
- __ IncrementCounter(&Counters::named_load_global_stub, 1, r1, r3);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
__ Ret();
__ bind(&miss);
- __ IncrementCounter(&Counters::named_load_global_stub_miss, 1, r1, r3);
+ __ IncrementCounter(counters->named_load_global_stub_miss(), 1, r1, r3);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
@@ -3055,7 +3086,9 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
// -- r1 : receiver
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_string_length, 1, r2, r3);
+
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_string_length(), 1, r2, r3);
// Check the key is the cached one.
__ cmp(r0, Operand(Handle<String>(name)));
@@ -3063,7 +3096,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
GenerateLoadStringLength(masm(), r1, r2, r3, &miss, true);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_string_length, 1, r2, r3);
+ __ DecrementCounter(counters->keyed_load_string_length(), 1, r2, r3);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -3079,7 +3112,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_function_prototype, 1, r2, r3);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3);
// Check the name hasn't changed.
__ cmp(r0, Operand(Handle<String>(name)));
@@ -3087,7 +3121,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
GenerateLoadFunctionPrototype(masm(), r1, r2, r3, &miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_function_prototype, 1, r2, r3);
+ __ DecrementCounter(counters->keyed_load_function_prototype(), 1, r2, r3);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
return GetCode(CALLBACKS, name);
@@ -3143,38 +3177,6 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) {
- // ----------- S t a t e -------------
- // -- lr : return address
- // -- r0 : key
- // -- r1 : receiver
- // -----------------------------------
- Label miss;
-
- // Check that the map matches.
- __ CheckMap(r1, r2, Handle<Map>(receiver->map()), &miss, false);
-
- GenerateFastPixelArrayLoad(masm(),
- r1,
- r0,
- r2,
- r3,
- r4,
- r5,
- r0,
- &miss,
- &miss,
- &miss);
-
- __ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Miss));
- __ Jump(ic, RelocInfo::CODE_TARGET);
-
- // Return the generated code.
- return GetCode(NORMAL, NULL);
-}
-
-
MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
int index,
Map* transition,
@@ -3187,7 +3189,8 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_store_field, 1, r3, r4);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->keyed_store_field(), 1, r3, r4);
// Check that the name has not changed.
__ cmp(r1, Operand(Handle<String>(name)));
@@ -3203,9 +3206,8 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
&miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_store_field, 1, r3, r4);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
-
+ __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4);
+ Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -3248,7 +3250,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
__ ldr(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
__ ldr(scratch, FieldMemOperand(elements_reg, HeapObject::kMapOffset));
- __ cmp(scratch, Operand(Handle<Map>(Factory::fixed_array_map())));
+ __ cmp(scratch, Operand(Handle<Map>(factory()->fixed_array_map())));
__ b(ne, &miss);
// Check that the key is within bounds.
@@ -3275,48 +3277,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
__ Ret();
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
- __ Jump(ic, RelocInfo::CODE_TARGET);
-
- // Return the generated code.
- return GetCode(NORMAL, NULL);
-}
-
-
-MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray(
- JSObject* receiver) {
- // ----------- S t a t e -------------
- // -- r0 : value
- // -- r1 : key
- // -- r2 : receiver
- // -- r3 : scratch
- // -- r4 : scratch
- // -- r5 : scratch
- // -- r6 : scratch
- // -- lr : return address
- // -----------------------------------
- Label miss;
-
- // Check that the map matches.
- __ CheckMap(r2, r6, Handle<Map>(receiver->map()), &miss, false);
-
- GenerateFastPixelArrayStore(masm(),
- r2,
- r1,
- r0,
- r3,
- r4,
- r5,
- r6,
- true,
- true,
- &miss,
- &miss,
- NULL,
- &miss);
-
- __ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
+ Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -3452,16 +3413,16 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// Remove caller arguments and receiver from the stack and return.
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
__ add(sp, sp, Operand(kPointerSize));
- __ IncrementCounter(&Counters::constructed_objects, 1, r1, r2);
- __ IncrementCounter(&Counters::constructed_objects_stub, 1, r1, r2);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->constructed_objects(), 1, r1, r2);
+ __ IncrementCounter(counters->constructed_objects_stub(), 1, r1, r2);
__ Jump(lr);
// Jump to the generic stub in case the specialized code cannot handle the
// construction.
__ bind(&generic_stub_call);
- Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
- Handle<Code> generic_construct_stub(code);
- __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
+ Handle<Code> code = masm()->isolate()->builtins()->JSConstructStubGeneric();
+ __ Jump(code, RelocInfo::CODE_TARGET);
// Return the generated code.
return GetCode();
@@ -3488,7 +3449,9 @@ static bool IsElementTypeSigned(ExternalArrayType array_type) {
MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
- ExternalArrayType array_type, Code::Flags flags) {
+ JSObject* receiver_object,
+ ExternalArrayType array_type,
+ Code::Flags flags) {
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
@@ -3505,24 +3468,13 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// Check that the key is a smi.
__ JumpIfNotSmi(key, &slow);
- // Check that the object is a JS object. Load map into r2.
- __ CompareObjectType(receiver, r2, r3, FIRST_JS_OBJECT_TYPE);
- __ b(lt, &slow);
-
- // Check that the receiver does not require access checks. We need
- // to check this explicitly since this generic stub does not perform
- // map checks.
- __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
- __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
+ // Make sure that we've got the right map.
+ __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ cmp(r2, Operand(Handle<Map>(receiver_object->map())));
__ b(ne, &slow);
- // Check that the elements array is the appropriate type of
- // ExternalArray.
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
- __ LoadRoot(ip, Heap::RootIndexForExternalArrayType(array_type));
- __ cmp(r2, ip);
- __ b(ne, &slow);
+ // r3: elements array
// Check that the index is in range.
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
@@ -3530,7 +3482,6 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// Unsigned comparison catches both negative and too-large values.
__ b(lo, &slow);
- // r3: elements array
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage
@@ -3543,6 +3494,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
case kExternalByteArray:
__ ldrsb(value, MemOperand(r3, key, LSR, 1));
break;
+ case kExternalPixelArray:
case kExternalUnsignedByteArray:
__ ldrb(value, MemOperand(r3, key, LSR, 1));
break;
@@ -3557,7 +3509,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
__ ldr(value, MemOperand(r3, key, LSL, 1));
break;
case kExternalFloatArray:
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (masm()->isolate()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ add(r2, r3, Operand(key, LSL, 1));
__ vldr(s0, r2, 0);
@@ -3596,7 +3548,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// Now we can use r0 for the result as key is not needed any more.
__ mov(r0, r5);
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (masm()->isolate()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ vmov(s0, value);
__ vcvt_f64_s32(d0, s0);
@@ -3611,7 +3563,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// The test is different for unsigned int values. Since we need
// the value to be in the range of a positive smi, we can't
// handle either of the top two bits being set in the value.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (masm()->isolate()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
Label box_int, done;
__ tst(value, Operand(0xC0000000));
@@ -3675,7 +3627,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
} else if (array_type == kExternalFloatArray) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (masm()->isolate()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Allocate a HeapNumber for the result. Don't use r0 and r1 as
// AllocateHeapNumber clobbers all registers - also when jumping due to
@@ -3751,7 +3703,9 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// Slow case, key and receiver still in r0 and r1.
__ bind(&slow);
- __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1, r2, r3);
+ __ IncrementCounter(
+ masm()->isolate()->counters()->keyed_load_external_array_slow(),
+ 1, r2, r3);
// ---------- S t a t e --------------
// -- lr : return address
@@ -3768,7 +3722,9 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
- ExternalArrayType array_type, Code::Flags flags) {
+ JSObject* receiver_object,
+ ExternalArrayType array_type,
+ Code::Flags flags) {
// ---------- S t a t e --------------
// -- r0 : value
// -- r1 : key
@@ -3786,28 +3742,18 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
// Check that the object isn't a smi.
__ JumpIfSmi(receiver, &slow);
- // Check that the object is a JS object. Load map into r3.
- __ CompareObjectType(receiver, r3, r4, FIRST_JS_OBJECT_TYPE);
- __ b(le, &slow);
-
- // Check that the receiver does not require access checks. We need
- // to do this because this generic stub does not perform map checks.
- __ ldrb(ip, FieldMemOperand(r3, Map::kBitFieldOffset));
- __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
+ // Make sure that we've got the right map.
+ __ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ cmp(r3, Operand(Handle<Map>(receiver_object->map())));
__ b(ne, &slow);
+ __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
+
// Check that the key is a smi.
__ JumpIfNotSmi(key, &slow);
- // Check that the elements array is the appropriate type of ExternalArray.
- __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
- __ LoadRoot(ip, Heap::RootIndexForExternalArrayType(array_type));
- __ cmp(r4, ip);
- __ b(ne, &slow);
-
- // Check that the index is in range.
- __ mov(r4, Operand(key, ASR, kSmiTagSize)); // Untag the index.
+ // Check that the index is in range
+ __ SmiUntag(r4, key);
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
__ cmp(r4, ip);
// Unsigned comparison catches both negative and too-large values.
@@ -3817,14 +3763,24 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
// runtime for all other kinds of values.
// r3: external array.
// r4: key (integer).
- __ JumpIfNotSmi(value, &check_heap_number);
- __ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value.
+ if (array_type == kExternalPixelArray) {
+ // Double to pixel conversion is only implemented in the runtime for now.
+ __ JumpIfNotSmi(value, &slow);
+ } else {
+ __ JumpIfNotSmi(value, &check_heap_number);
+ }
+ __ SmiUntag(r5, value);
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage.
// r4: key (integer).
// r5: value (integer).
switch (array_type) {
+ case kExternalPixelArray:
+ // Clamp the value to [0..255].
+ __ Usat(r5, 8, Operand(r5));
+ __ strb(r5, MemOperand(r3, r4, LSL, 0));
+ break;
case kExternalByteArray:
case kExternalUnsignedByteArray:
__ strb(r5, MemOperand(r3, r4, LSL, 0));
@@ -3849,198 +3805,199 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
// Entry registers are intact, r0 holds the value which is the return value.
__ Ret();
+ if (array_type != kExternalPixelArray) {
+ // r3: external array.
+ // r4: index (integer).
+ __ bind(&check_heap_number);
+ __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
+ __ b(ne, &slow);
- // r3: external array.
- // r4: index (integer).
- __ bind(&check_heap_number);
- __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
- __ b(ne, &slow);
-
- __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
+ __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
- // r3: base pointer of external storage.
- // r4: key (integer).
-
- // The WebGL specification leaves the behavior of storing NaN and
- // +/-Infinity into integer arrays basically undefined. For more
- // reproducible behavior, convert these to zero.
- if (CpuFeatures::IsSupported(VFP3)) {
- CpuFeatures::Scope scope(VFP3);
+ // r3: base pointer of external storage.
+ // r4: key (integer).
+ // The WebGL specification leaves the behavior of storing NaN and
+ // +/-Infinity into integer arrays basically undefined. For more
+ // reproducible behavior, convert these to zero.
+ if (masm()->isolate()->cpu_features()->IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
- if (array_type == kExternalFloatArray) {
- // vldr requires offset to be a multiple of 4 so we can not
- // include -kHeapObjectTag into it.
- __ sub(r5, r0, Operand(kHeapObjectTag));
- __ vldr(d0, r5, HeapNumber::kValueOffset);
- __ add(r5, r3, Operand(r4, LSL, 2));
- __ vcvt_f32_f64(s0, d0);
- __ vstr(s0, r5, 0);
- } else {
- // Need to perform float-to-int conversion.
- // Test for NaN or infinity (both give zero).
- __ ldr(r6, FieldMemOperand(value, HeapNumber::kExponentOffset));
-
- // Hoisted load. vldr requires offset to be a multiple of 4 so we can not
- // include -kHeapObjectTag into it.
- __ sub(r5, value, Operand(kHeapObjectTag));
- __ vldr(d0, r5, HeapNumber::kValueOffset);
-
- __ Sbfx(r6, r6, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
- // NaNs and Infinities have all-one exponents so they sign extend to -1.
- __ cmp(r6, Operand(-1));
- __ mov(r5, Operand(0), LeaveCC, eq);
-
- // Not infinity or NaN simply convert to int.
- if (IsElementTypeSigned(array_type)) {
- __ vcvt_s32_f64(s0, d0, kDefaultRoundToZero, ne);
+ if (array_type == kExternalFloatArray) {
+ // vldr requires offset to be a multiple of 4 so we can not
+ // include -kHeapObjectTag into it.
+ __ sub(r5, r0, Operand(kHeapObjectTag));
+ __ vldr(d0, r5, HeapNumber::kValueOffset);
+ __ add(r5, r3, Operand(r4, LSL, 2));
+ __ vcvt_f32_f64(s0, d0);
+ __ vstr(s0, r5, 0);
} else {
- __ vcvt_u32_f64(s0, d0, kDefaultRoundToZero, ne);
- }
- __ vmov(r5, s0, ne);
-
- switch (array_type) {
- case kExternalByteArray:
- case kExternalUnsignedByteArray:
- __ strb(r5, MemOperand(r3, r4, LSL, 0));
- break;
- case kExternalShortArray:
- case kExternalUnsignedShortArray:
- __ strh(r5, MemOperand(r3, r4, LSL, 1));
- break;
- case kExternalIntArray:
- case kExternalUnsignedIntArray:
- __ str(r5, MemOperand(r3, r4, LSL, 2));
- break;
- default:
- UNREACHABLE();
- break;
+ // Need to perform float-to-int conversion.
+ // Test for NaN or infinity (both give zero).
+ __ ldr(r6, FieldMemOperand(value, HeapNumber::kExponentOffset));
+
+ // Hoisted load. vldr requires offset to be a multiple of 4 so we can
+ // not include -kHeapObjectTag into it.
+ __ sub(r5, value, Operand(kHeapObjectTag));
+ __ vldr(d0, r5, HeapNumber::kValueOffset);
+
+ __ Sbfx(r6, r6, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
+ // NaNs and Infinities have all-one exponents so they sign extend to -1.
+ __ cmp(r6, Operand(-1));
+ __ mov(r5, Operand(0), LeaveCC, eq);
+
+ // Not infinity or NaN simply convert to int.
+ if (IsElementTypeSigned(array_type)) {
+ __ vcvt_s32_f64(s0, d0, kDefaultRoundToZero, ne);
+ } else {
+ __ vcvt_u32_f64(s0, d0, kDefaultRoundToZero, ne);
+ }
+ __ vmov(r5, s0, ne);
+
+ switch (array_type) {
+ case kExternalByteArray:
+ case kExternalUnsignedByteArray:
+ __ strb(r5, MemOperand(r3, r4, LSL, 0));
+ break;
+ case kExternalShortArray:
+ case kExternalUnsignedShortArray:
+ __ strh(r5, MemOperand(r3, r4, LSL, 1));
+ break;
+ case kExternalIntArray:
+ case kExternalUnsignedIntArray:
+ __ str(r5, MemOperand(r3, r4, LSL, 2));
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
}
- }
-
- // Entry registers are intact, r0 holds the value which is the return value.
- __ Ret();
- } else {
- // VFP3 is not available do manual conversions.
- __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
- __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
-
- if (array_type == kExternalFloatArray) {
- Label done, nan_or_infinity_or_zero;
- static const int kMantissaInHiWordShift =
- kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
- static const int kMantissaInLoWordShift =
- kBitsPerInt - kMantissaInHiWordShift;
-
- // Test for all special exponent values: zeros, subnormal numbers, NaNs
- // and infinities. All these should be converted to 0.
- __ mov(r7, Operand(HeapNumber::kExponentMask));
- __ and_(r9, r5, Operand(r7), SetCC);
- __ b(eq, &nan_or_infinity_or_zero);
-
- __ teq(r9, Operand(r7));
- __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq);
- __ b(eq, &nan_or_infinity_or_zero);
- // Rebias exponent.
- __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
- __ add(r9,
- r9,
- Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
-
- __ cmp(r9, Operand(kBinary32MaxExponent));
- __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt);
- __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt);
- __ b(gt, &done);
-
- __ cmp(r9, Operand(kBinary32MinExponent));
- __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt);
- __ b(lt, &done);
-
- __ and_(r7, r5, Operand(HeapNumber::kSignMask));
- __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
- __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift));
- __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift));
- __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
-
- __ bind(&done);
- __ str(r5, MemOperand(r3, r4, LSL, 2));
// Entry registers are intact, r0 holds the value which is the return
// value.
__ Ret();
-
- __ bind(&nan_or_infinity_or_zero);
- __ and_(r7, r5, Operand(HeapNumber::kSignMask));
- __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
- __ orr(r9, r9, r7);
- __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
- __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
- __ b(&done);
} else {
- bool is_signed_type = IsElementTypeSigned(array_type);
- int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
- int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
-
- Label done, sign;
-
- // Test for all special exponent values: zeros, subnormal numbers, NaNs
- // and infinities. All these should be converted to 0.
- __ mov(r7, Operand(HeapNumber::kExponentMask));
- __ and_(r9, r5, Operand(r7), SetCC);
- __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
- __ b(eq, &done);
-
- __ teq(r9, Operand(r7));
- __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
- __ b(eq, &done);
-
- // Unbias exponent.
- __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
- __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC);
- // If exponent is negative then result is 0.
- __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, mi);
- __ b(mi, &done);
-
- // If exponent is too big then result is minimal value.
- __ cmp(r9, Operand(meaningfull_bits - 1));
- __ mov(r5, Operand(min_value), LeaveCC, ge);
- __ b(ge, &done);
-
- __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC);
- __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
- __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
-
- __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
- __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
- __ b(pl, &sign);
-
- __ rsb(r9, r9, Operand(0, RelocInfo::NONE));
- __ mov(r5, Operand(r5, LSL, r9));
- __ rsb(r9, r9, Operand(meaningfull_bits));
- __ orr(r5, r5, Operand(r6, LSR, r9));
-
- __ bind(&sign);
- __ teq(r7, Operand(0, RelocInfo::NONE));
- __ rsb(r5, r5, Operand(0, RelocInfo::NONE), LeaveCC, ne);
-
- __ bind(&done);
- switch (array_type) {
- case kExternalByteArray:
- case kExternalUnsignedByteArray:
- __ strb(r5, MemOperand(r3, r4, LSL, 0));
- break;
- case kExternalShortArray:
- case kExternalUnsignedShortArray:
- __ strh(r5, MemOperand(r3, r4, LSL, 1));
- break;
- case kExternalIntArray:
- case kExternalUnsignedIntArray:
- __ str(r5, MemOperand(r3, r4, LSL, 2));
- break;
- default:
- UNREACHABLE();
- break;
+ // VFP3 is not available do manual conversions.
+ __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
+ __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
+
+ if (array_type == kExternalFloatArray) {
+ Label done, nan_or_infinity_or_zero;
+ static const int kMantissaInHiWordShift =
+ kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
+
+ static const int kMantissaInLoWordShift =
+ kBitsPerInt - kMantissaInHiWordShift;
+
+ // Test for all special exponent values: zeros, subnormal numbers, NaNs
+ // and infinities. All these should be converted to 0.
+ __ mov(r7, Operand(HeapNumber::kExponentMask));
+ __ and_(r9, r5, Operand(r7), SetCC);
+ __ b(eq, &nan_or_infinity_or_zero);
+
+ __ teq(r9, Operand(r7));
+ __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq);
+ __ b(eq, &nan_or_infinity_or_zero);
+
+ // Rebias exponent.
+ __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
+ __ add(r9,
+ r9,
+ Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
+
+ __ cmp(r9, Operand(kBinary32MaxExponent));
+ __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt);
+ __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt);
+ __ b(gt, &done);
+
+ __ cmp(r9, Operand(kBinary32MinExponent));
+ __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt);
+ __ b(lt, &done);
+
+ __ and_(r7, r5, Operand(HeapNumber::kSignMask));
+ __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
+ __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift));
+ __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift));
+ __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
+
+ __ bind(&done);
+ __ str(r5, MemOperand(r3, r4, LSL, 2));
+ // Entry registers are intact, r0 holds the value which is the return
+ // value.
+ __ Ret();
+
+ __ bind(&nan_or_infinity_or_zero);
+ __ and_(r7, r5, Operand(HeapNumber::kSignMask));
+ __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
+ __ orr(r9, r9, r7);
+ __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
+ __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
+ __ b(&done);
+ } else {
+ bool is_signed_type = IsElementTypeSigned(array_type);
+ int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
+ int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
+
+ Label done, sign;
+
+ // Test for all special exponent values: zeros, subnormal numbers, NaNs
+ // and infinities. All these should be converted to 0.
+ __ mov(r7, Operand(HeapNumber::kExponentMask));
+ __ and_(r9, r5, Operand(r7), SetCC);
+ __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
+ __ b(eq, &done);
+
+ __ teq(r9, Operand(r7));
+ __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, eq);
+ __ b(eq, &done);
+
+ // Unbias exponent.
+ __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
+ __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC);
+ // If exponent is negative then result is 0.
+ __ mov(r5, Operand(0, RelocInfo::NONE), LeaveCC, mi);
+ __ b(mi, &done);
+
+ // If exponent is too big then result is minimal value.
+ __ cmp(r9, Operand(meaningfull_bits - 1));
+ __ mov(r5, Operand(min_value), LeaveCC, ge);
+ __ b(ge, &done);
+
+ __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC);
+ __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
+ __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
+
+ __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
+ __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
+ __ b(pl, &sign);
+
+ __ rsb(r9, r9, Operand(0, RelocInfo::NONE));
+ __ mov(r5, Operand(r5, LSL, r9));
+ __ rsb(r9, r9, Operand(meaningfull_bits));
+ __ orr(r5, r5, Operand(r6, LSR, r9));
+
+ __ bind(&sign);
+ __ teq(r7, Operand(0, RelocInfo::NONE));
+ __ rsb(r5, r5, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+
+ __ bind(&done);
+ switch (array_type) {
+ case kExternalByteArray:
+ case kExternalUnsignedByteArray:
+ __ strb(r5, MemOperand(r3, r4, LSL, 0));
+ break;
+ case kExternalShortArray:
+ case kExternalUnsignedShortArray:
+ __ strh(r5, MemOperand(r3, r4, LSL, 1));
+ break;
+ case kExternalIntArray:
+ case kExternalUnsignedIntArray:
+ __ str(r5, MemOperand(r3, r4, LSL, 2));
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
}
}
}
diff --git a/src/arm/virtual-frame-arm.cc b/src/arm/virtual-frame-arm.cc
index 544e405d..a852d6ee 100644
--- a/src/arm/virtual-frame-arm.cc
+++ b/src/arm/virtual-frame-arm.cc
@@ -288,7 +288,7 @@ void VirtualFrame::CallJSFunction(int arg_count) {
}
-void VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
+void VirtualFrame::CallRuntime(const Runtime::Function* f, int arg_count) {
SpillAll();
Forget(arg_count);
ASSERT(cgen()->HasValidEntryRegisters());
@@ -321,7 +321,8 @@ void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
void VirtualFrame::CallLoadIC(Handle<String> name, RelocInfo::Mode mode) {
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kLoadIC_Initialize));
PopToR0();
SpillAll();
__ mov(r2, Operand(name));
@@ -332,9 +333,9 @@ void VirtualFrame::CallLoadIC(Handle<String> name, RelocInfo::Mode mode) {
void VirtualFrame::CallStoreIC(Handle<String> name,
bool is_contextual,
StrictModeFlag strict_mode) {
- Handle<Code> ic(Builtins::builtin(
- (strict_mode == kStrictMode) ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ (strict_mode == kStrictMode) ? Builtins::kStoreIC_Initialize_Strict
+ : Builtins::kStoreIC_Initialize));
PopToR0();
RelocInfo::Mode mode;
if (is_contextual) {
@@ -352,7 +353,8 @@ void VirtualFrame::CallStoreIC(Handle<String> name,
void VirtualFrame::CallKeyedLoadIC() {
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_Initialize));
PopToR1R0();
SpillAll();
CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
@@ -360,9 +362,9 @@ void VirtualFrame::CallKeyedLoadIC() {
void VirtualFrame::CallKeyedStoreIC(StrictModeFlag strict_mode) {
- Handle<Code> ic(Builtins::builtin(
- (strict_mode == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ (strict_mode == kStrictMode) ? Builtins::kKeyedStoreIC_Initialize_Strict
+ : Builtins::kKeyedStoreIC_Initialize));
PopToR1R0();
SpillAll();
EmitPop(r2);
@@ -385,7 +387,8 @@ void VirtualFrame::CallCodeObject(Handle<Code> code,
ASSERT(dropped_args == 0);
break;
case Code::BUILTIN:
- ASSERT(*code == Builtins::builtin(Builtins::JSConstructCall));
+ ASSERT(*code == Isolate::Current()->builtins()->builtin(
+ Builtins::kJSConstructCall));
break;
default:
UNREACHABLE();
@@ -422,9 +425,6 @@ const VirtualFrame::TopOfStack VirtualFrame::kStateAfterPush[TOS_STATES] =
{ R0_TOS, R1_R0_TOS, R0_R1_TOS, R0_R1_TOS, R1_R0_TOS };
-bool VirtualFrame::SpilledScope::is_spilled_ = false;
-
-
void VirtualFrame::Drop(int count) {
ASSERT(count >= 0);
ASSERT(height() >= count);
diff --git a/src/arm/virtual-frame-arm.h b/src/arm/virtual-frame-arm.h
index 76470bdc..6d67e70c 100644
--- a/src/arm/virtual-frame-arm.h
+++ b/src/arm/virtual-frame-arm.h
@@ -55,23 +55,26 @@ class VirtualFrame : public ZoneObject {
class SpilledScope BASE_EMBEDDED {
public:
explicit SpilledScope(VirtualFrame* frame)
- : old_is_spilled_(is_spilled_) {
+ : old_is_spilled_(
+ Isolate::Current()->is_virtual_frame_in_spilled_scope()) {
if (frame != NULL) {
- if (!is_spilled_) {
+ if (!old_is_spilled_) {
frame->SpillAll();
} else {
frame->AssertIsSpilled();
}
}
- is_spilled_ = true;
+ Isolate::Current()->set_is_virtual_frame_in_spilled_scope(true);
}
~SpilledScope() {
- is_spilled_ = old_is_spilled_;
+ Isolate::Current()->set_is_virtual_frame_in_spilled_scope(
+ old_is_spilled_);
+ }
+ static bool is_spilled() {
+ return Isolate::Current()->is_virtual_frame_in_spilled_scope();
}
- static bool is_spilled() { return is_spilled_; }
private:
- static bool is_spilled_;
int old_is_spilled_;
SpilledScope() { }
@@ -274,7 +277,7 @@ class VirtualFrame : public ZoneObject {
// Call runtime given the number of arguments expected on (and
// removed from) the stack.
- void CallRuntime(Runtime::Function* f, int arg_count);
+ void CallRuntime(const Runtime::Function* f, int arg_count);
void CallRuntime(Runtime::FunctionId id, int arg_count);
#ifdef ENABLE_DEBUGGER_SUPPORT
diff --git a/src/assembler.cc b/src/assembler.cc
index b0b44fd9..0322747c 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -55,6 +55,8 @@
#include "x64/regexp-macro-assembler-x64.h"
#elif V8_TARGET_ARCH_ARM
#include "arm/regexp-macro-assembler-arm.h"
+#elif V8_TARGET_ARCH_MIPS
+#include "mips/regexp-macro-assembler-mips.h"
#else // Unknown architecture.
#error "Unknown architecture."
#endif // Target architecture.
@@ -67,6 +69,7 @@ namespace internal {
const double DoubleConstant::min_int = kMinInt;
const double DoubleConstant::one_half = 0.5;
const double DoubleConstant::minus_zero = -0.0;
+const double DoubleConstant::nan = OS::nan_value();
const double DoubleConstant::negative_infinity = -V8_INFINITY;
const char* RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
@@ -139,6 +142,7 @@ const int kPCJumpTag = (1 << kExtraTagBits) - 1;
const int kSmallPCDeltaBits = kBitsPerByte - kTagBits;
const int kSmallPCDeltaMask = (1 << kSmallPCDeltaBits) - 1;
+const int RelocInfo::kMaxSmallPCDelta = kSmallPCDeltaMask;
const int kVariableLengthPCJumpTopTag = 1;
const int kChunkBits = 7;
@@ -216,7 +220,6 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) {
#ifdef DEBUG
byte* begin_pos = pos_;
#endif
- Counters::reloc_info_count.Increment();
ASSERT(rinfo->pc() - last_pc_ >= 0);
ASSERT(RelocInfo::NUMBER_OF_MODES <= kMaxRelocModes);
// Use unsigned delta-encoding for pc.
@@ -525,7 +528,7 @@ void RelocInfo::Verify() {
ASSERT(addr != NULL);
// Check that we can find the right code object.
Code* code = Code::GetCodeFromTargetAddress(addr);
- Object* found = Heap::FindCodeObject(addr);
+ Object* found = HEAP->FindCodeObject(addr);
ASSERT(found->IsCode());
ASSERT(code->address() == HeapObject::cast(found)->address());
break;
@@ -551,153 +554,184 @@ void RelocInfo::Verify() {
// -----------------------------------------------------------------------------
// Implementation of ExternalReference
-ExternalReference::ExternalReference(Builtins::CFunctionId id)
- : address_(Redirect(Builtins::c_function_address(id))) {}
+ExternalReference::ExternalReference(Builtins::CFunctionId id, Isolate* isolate)
+ : address_(Redirect(isolate, Builtins::c_function_address(id))) {}
ExternalReference::ExternalReference(
- ApiFunction* fun, Type type = ExternalReference::BUILTIN_CALL)
- : address_(Redirect(fun->address(), type)) {}
+ ApiFunction* fun,
+ Type type = ExternalReference::BUILTIN_CALL,
+ Isolate* isolate = NULL)
+ : address_(Redirect(isolate, fun->address(), type)) {}
-ExternalReference::ExternalReference(Builtins::Name name)
- : address_(Builtins::builtin_address(name)) {}
+ExternalReference::ExternalReference(Builtins::Name name, Isolate* isolate)
+ : address_(isolate->builtins()->builtin_address(name)) {}
-ExternalReference::ExternalReference(Runtime::FunctionId id)
- : address_(Redirect(Runtime::FunctionForId(id)->entry)) {}
+ExternalReference::ExternalReference(Runtime::FunctionId id,
+ Isolate* isolate)
+ : address_(Redirect(isolate, Runtime::FunctionForId(id)->entry)) {}
-ExternalReference::ExternalReference(Runtime::Function* f)
- : address_(Redirect(f->entry)) {}
+ExternalReference::ExternalReference(const Runtime::Function* f,
+ Isolate* isolate)
+ : address_(Redirect(isolate, f->entry)) {}
-ExternalReference::ExternalReference(const IC_Utility& ic_utility)
- : address_(Redirect(ic_utility.address())) {}
+ExternalReference ExternalReference::isolate_address() {
+ return ExternalReference(Isolate::Current());
+}
+
+
+ExternalReference::ExternalReference(const IC_Utility& ic_utility,
+ Isolate* isolate)
+ : address_(Redirect(isolate, ic_utility.address())) {}
#ifdef ENABLE_DEBUGGER_SUPPORT
-ExternalReference::ExternalReference(const Debug_Address& debug_address)
- : address_(debug_address.address()) {}
+ExternalReference::ExternalReference(const Debug_Address& debug_address,
+ Isolate* isolate)
+ : address_(debug_address.address(isolate)) {}
#endif
ExternalReference::ExternalReference(StatsCounter* counter)
: address_(reinterpret_cast<Address>(counter->GetInternalPointer())) {}
-ExternalReference::ExternalReference(Top::AddressId id)
- : address_(Top::get_address_from_id(id)) {}
+ExternalReference::ExternalReference(Isolate::AddressId id, Isolate* isolate)
+ : address_(isolate->get_address_from_id(id)) {}
ExternalReference::ExternalReference(const SCTableReference& table_ref)
: address_(table_ref.address()) {}
-ExternalReference ExternalReference::perform_gc_function() {
- return ExternalReference(Redirect(FUNCTION_ADDR(Runtime::PerformGC)));
+ExternalReference ExternalReference::perform_gc_function(Isolate* isolate) {
+ return ExternalReference(Redirect(isolate,
+ FUNCTION_ADDR(Runtime::PerformGC)));
}
-ExternalReference ExternalReference::fill_heap_number_with_random_function() {
- return
- ExternalReference(Redirect(FUNCTION_ADDR(V8::FillHeapNumberWithRandom)));
+ExternalReference ExternalReference::fill_heap_number_with_random_function(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(
+ isolate,
+ FUNCTION_ADDR(V8::FillHeapNumberWithRandom)));
}
-ExternalReference ExternalReference::delete_handle_scope_extensions() {
- return ExternalReference(Redirect(FUNCTION_ADDR(
- HandleScope::DeleteExtensions)));
+ExternalReference ExternalReference::delete_handle_scope_extensions(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(
+ isolate,
+ FUNCTION_ADDR(HandleScope::DeleteExtensions)));
}
-ExternalReference ExternalReference::random_uint32_function() {
- return ExternalReference(Redirect(FUNCTION_ADDR(V8::Random)));
+ExternalReference ExternalReference::random_uint32_function(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(isolate, FUNCTION_ADDR(V8::Random)));
}
-ExternalReference ExternalReference::transcendental_cache_array_address() {
- return ExternalReference(TranscendentalCache::cache_array_address());
+ExternalReference ExternalReference::transcendental_cache_array_address(
+ Isolate* isolate) {
+ return ExternalReference(
+ isolate->transcendental_cache()->cache_array_address());
}
-ExternalReference ExternalReference::new_deoptimizer_function() {
+ExternalReference ExternalReference::new_deoptimizer_function(
+ Isolate* isolate) {
return ExternalReference(
- Redirect(FUNCTION_ADDR(Deoptimizer::New)));
+ Redirect(isolate, FUNCTION_ADDR(Deoptimizer::New)));
}
-ExternalReference ExternalReference::compute_output_frames_function() {
+ExternalReference ExternalReference::compute_output_frames_function(
+ Isolate* isolate) {
return ExternalReference(
- Redirect(FUNCTION_ADDR(Deoptimizer::ComputeOutputFrames)));
+ Redirect(isolate, FUNCTION_ADDR(Deoptimizer::ComputeOutputFrames)));
}
-ExternalReference ExternalReference::global_contexts_list() {
- return ExternalReference(Heap::global_contexts_list_address());
+ExternalReference ExternalReference::global_contexts_list(Isolate* isolate) {
+ return ExternalReference(isolate->heap()->global_contexts_list_address());
}
-ExternalReference ExternalReference::keyed_lookup_cache_keys() {
- return ExternalReference(KeyedLookupCache::keys_address());
+ExternalReference ExternalReference::keyed_lookup_cache_keys(Isolate* isolate) {
+ return ExternalReference(isolate->keyed_lookup_cache()->keys_address());
}
-ExternalReference ExternalReference::keyed_lookup_cache_field_offsets() {
- return ExternalReference(KeyedLookupCache::field_offsets_address());
+ExternalReference ExternalReference::keyed_lookup_cache_field_offsets(
+ Isolate* isolate) {
+ return ExternalReference(
+ isolate->keyed_lookup_cache()->field_offsets_address());
}
-ExternalReference ExternalReference::the_hole_value_location() {
- return ExternalReference(Factory::the_hole_value().location());
+ExternalReference ExternalReference::the_hole_value_location(Isolate* isolate) {
+ return ExternalReference(isolate->factory()->the_hole_value().location());
}
-ExternalReference ExternalReference::arguments_marker_location() {
- return ExternalReference(Factory::arguments_marker().location());
+ExternalReference ExternalReference::arguments_marker_location(
+ Isolate* isolate) {
+ return ExternalReference(isolate->factory()->arguments_marker().location());
}
-ExternalReference ExternalReference::roots_address() {
- return ExternalReference(Heap::roots_address());
+ExternalReference ExternalReference::roots_address(Isolate* isolate) {
+ return ExternalReference(isolate->heap()->roots_address());
}
-ExternalReference ExternalReference::address_of_stack_limit() {
- return ExternalReference(StackGuard::address_of_jslimit());
+ExternalReference ExternalReference::address_of_stack_limit(Isolate* isolate) {
+ return ExternalReference(isolate->stack_guard()->address_of_jslimit());
}
-ExternalReference ExternalReference::address_of_real_stack_limit() {
- return ExternalReference(StackGuard::address_of_real_jslimit());
+ExternalReference ExternalReference::address_of_real_stack_limit(
+ Isolate* isolate) {
+ return ExternalReference(isolate->stack_guard()->address_of_real_jslimit());
}
-ExternalReference ExternalReference::address_of_regexp_stack_limit() {
- return ExternalReference(RegExpStack::limit_address());
+ExternalReference ExternalReference::address_of_regexp_stack_limit(
+ Isolate* isolate) {
+ return ExternalReference(isolate->regexp_stack()->limit_address());
}
-ExternalReference ExternalReference::new_space_start() {
- return ExternalReference(Heap::NewSpaceStart());
+ExternalReference ExternalReference::new_space_start(Isolate* isolate) {
+ return ExternalReference(isolate->heap()->NewSpaceStart());
}
-ExternalReference ExternalReference::new_space_mask() {
- return ExternalReference(reinterpret_cast<Address>(Heap::NewSpaceMask()));
+ExternalReference ExternalReference::new_space_mask(Isolate* isolate) {
+ Address mask = reinterpret_cast<Address>(isolate->heap()->NewSpaceMask());
+ return ExternalReference(mask);
}
-ExternalReference ExternalReference::new_space_allocation_top_address() {
- return ExternalReference(Heap::NewSpaceAllocationTopAddress());
+ExternalReference ExternalReference::new_space_allocation_top_address(
+ Isolate* isolate) {
+ return ExternalReference(isolate->heap()->NewSpaceAllocationTopAddress());
}
-ExternalReference ExternalReference::heap_always_allocate_scope_depth() {
- return ExternalReference(Heap::always_allocate_scope_depth_address());
+ExternalReference ExternalReference::heap_always_allocate_scope_depth(
+ Isolate* isolate) {
+ Heap* heap = isolate->heap();
+ return ExternalReference(heap->always_allocate_scope_depth_address());
}
-ExternalReference ExternalReference::new_space_allocation_limit_address() {
- return ExternalReference(Heap::NewSpaceAllocationLimitAddress());
+ExternalReference ExternalReference::new_space_allocation_limit_address(
+ Isolate* isolate) {
+ return ExternalReference(isolate->heap()->NewSpaceAllocationLimitAddress());
}
@@ -716,8 +750,9 @@ ExternalReference ExternalReference::handle_scope_limit_address() {
}
-ExternalReference ExternalReference::scheduled_exception_address() {
- return ExternalReference(Top::scheduled_exception_address());
+ExternalReference ExternalReference::scheduled_exception_address(
+ Isolate* isolate) {
+ return ExternalReference(isolate->scheduled_exception_address());
}
@@ -745,9 +780,16 @@ ExternalReference ExternalReference::address_of_negative_infinity() {
}
+ExternalReference ExternalReference::address_of_nan() {
+ return ExternalReference(reinterpret_cast<void*>(
+ const_cast<double*>(&DoubleConstant::nan)));
+}
+
+
#ifndef V8_INTERPRETED_REGEXP
-ExternalReference ExternalReference::re_check_stack_guard_state() {
+ExternalReference ExternalReference::re_check_stack_guard_state(
+ Isolate* isolate) {
Address function;
#ifdef V8_TARGET_ARCH_X64
function = FUNCTION_ADDR(RegExpMacroAssemblerX64::CheckStackGuardState);
@@ -755,19 +797,23 @@ ExternalReference ExternalReference::re_check_stack_guard_state() {
function = FUNCTION_ADDR(RegExpMacroAssemblerIA32::CheckStackGuardState);
#elif V8_TARGET_ARCH_ARM
function = FUNCTION_ADDR(RegExpMacroAssemblerARM::CheckStackGuardState);
+#elif V8_TARGET_ARCH_MIPS
+ function = FUNCTION_ADDR(RegExpMacroAssemblerMIPS::CheckStackGuardState);
#else
UNREACHABLE();
#endif
- return ExternalReference(Redirect(function));
+ return ExternalReference(Redirect(isolate, function));
}
-ExternalReference ExternalReference::re_grow_stack() {
+ExternalReference ExternalReference::re_grow_stack(Isolate* isolate) {
return ExternalReference(
- Redirect(FUNCTION_ADDR(NativeRegExpMacroAssembler::GrowStack)));
+ Redirect(isolate, FUNCTION_ADDR(NativeRegExpMacroAssembler::GrowStack)));
}
-ExternalReference ExternalReference::re_case_insensitive_compare_uc16() {
+ExternalReference ExternalReference::re_case_insensitive_compare_uc16(
+ Isolate* isolate) {
return ExternalReference(Redirect(
+ isolate,
FUNCTION_ADDR(NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16)));
}
@@ -776,16 +822,21 @@ ExternalReference ExternalReference::re_word_character_map() {
NativeRegExpMacroAssembler::word_character_map_address());
}
-ExternalReference ExternalReference::address_of_static_offsets_vector() {
- return ExternalReference(OffsetsVector::static_offsets_vector_address());
+ExternalReference ExternalReference::address_of_static_offsets_vector(
+ Isolate* isolate) {
+ return ExternalReference(
+ OffsetsVector::static_offsets_vector_address(isolate));
}
-ExternalReference ExternalReference::address_of_regexp_stack_memory_address() {
- return ExternalReference(RegExpStack::memory_address());
+ExternalReference ExternalReference::address_of_regexp_stack_memory_address(
+ Isolate* isolate) {
+ return ExternalReference(
+ isolate->regexp_stack()->memory_address());
}
-ExternalReference ExternalReference::address_of_regexp_stack_memory_size() {
- return ExternalReference(RegExpStack::memory_size_address());
+ExternalReference ExternalReference::address_of_regexp_stack_memory_size(
+ Isolate* isolate) {
+ return ExternalReference(isolate->regexp_stack()->memory_size_address());
}
#endif // V8_INTERPRETED_REGEXP
@@ -831,20 +882,26 @@ static double math_log_double(double x) {
}
-ExternalReference ExternalReference::math_sin_double_function() {
- return ExternalReference(Redirect(FUNCTION_ADDR(math_sin_double),
+ExternalReference ExternalReference::math_sin_double_function(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(isolate,
+ FUNCTION_ADDR(math_sin_double),
FP_RETURN_CALL));
}
-ExternalReference ExternalReference::math_cos_double_function() {
- return ExternalReference(Redirect(FUNCTION_ADDR(math_cos_double),
+ExternalReference ExternalReference::math_cos_double_function(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(isolate,
+ FUNCTION_ADDR(math_cos_double),
FP_RETURN_CALL));
}
-ExternalReference ExternalReference::math_log_double_function() {
- return ExternalReference(Redirect(FUNCTION_ADDR(math_log_double),
+ExternalReference ExternalReference::math_log_double_function(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(isolate,
+ FUNCTION_ADDR(math_log_double),
FP_RETURN_CALL));
}
@@ -884,14 +941,18 @@ double power_double_double(double x, double y) {
}
-ExternalReference ExternalReference::power_double_double_function() {
- return ExternalReference(Redirect(FUNCTION_ADDR(power_double_double),
+ExternalReference ExternalReference::power_double_double_function(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(isolate,
+ FUNCTION_ADDR(power_double_double),
FP_RETURN_CALL));
}
-ExternalReference ExternalReference::power_double_int_function() {
- return ExternalReference(Redirect(FUNCTION_ADDR(power_double_int),
+ExternalReference ExternalReference::power_double_int_function(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(isolate,
+ FUNCTION_ADDR(power_double_int),
FP_RETURN_CALL));
}
@@ -903,7 +964,7 @@ static int native_compare_doubles(double y, double x) {
ExternalReference ExternalReference::double_fp_operation(
- Token::Value operation) {
+ Token::Value operation, Isolate* isolate) {
typedef double BinaryFPOperation(double x, double y);
BinaryFPOperation* function = NULL;
switch (operation) {
@@ -926,28 +987,28 @@ ExternalReference ExternalReference::double_fp_operation(
UNREACHABLE();
}
// Passing true as 2nd parameter indicates that they return an fp value.
- return ExternalReference(Redirect(FUNCTION_ADDR(function), FP_RETURN_CALL));
+ return ExternalReference(Redirect(isolate,
+ FUNCTION_ADDR(function),
+ FP_RETURN_CALL));
}
-ExternalReference ExternalReference::compare_doubles() {
- return ExternalReference(Redirect(FUNCTION_ADDR(native_compare_doubles),
+ExternalReference ExternalReference::compare_doubles(Isolate* isolate) {
+ return ExternalReference(Redirect(isolate,
+ FUNCTION_ADDR(native_compare_doubles),
BUILTIN_CALL));
}
-ExternalReference::ExternalReferenceRedirector*
- ExternalReference::redirector_ = NULL;
-
-
#ifdef ENABLE_DEBUGGER_SUPPORT
-ExternalReference ExternalReference::debug_break() {
- return ExternalReference(Redirect(FUNCTION_ADDR(Debug::Break)));
+ExternalReference ExternalReference::debug_break(Isolate* isolate) {
+ return ExternalReference(Redirect(isolate, FUNCTION_ADDR(Debug::Break)));
}
-ExternalReference ExternalReference::debug_step_in_fp_address() {
- return ExternalReference(Debug::step_in_fp_addr());
+ExternalReference ExternalReference::debug_step_in_fp_address(
+ Isolate* isolate) {
+ return ExternalReference(isolate->debug()->step_in_fp_addr());
}
#endif
diff --git a/src/assembler.h b/src/assembler.h
index 8ebbfadf..62fe04d1 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -37,7 +37,6 @@
#include "gdb-jit.h"
#include "runtime.h"
-#include "top.h"
#include "token.h"
namespace v8 {
@@ -45,6 +44,19 @@ namespace internal {
// -----------------------------------------------------------------------------
+// Platform independent assembler base class.
+
+class AssemblerBase: public Malloced {
+ public:
+ explicit AssemblerBase(Isolate* isolate) : isolate_(isolate) {}
+
+ Isolate* isolate() const { return isolate_; }
+
+ private:
+ Isolate* isolate_;
+};
+
+// -----------------------------------------------------------------------------
// Common double constants.
class DoubleConstant: public AllStatic {
@@ -53,6 +65,7 @@ class DoubleConstant: public AllStatic {
static const double one_half;
static const double minus_zero;
static const double negative_infinity;
+ static const double nan;
};
@@ -192,6 +205,9 @@ class RelocInfo BASE_EMBEDDED {
// The maximum size for a call instruction including pc-jump.
static const int kMaxCallSize = 6;
+ // The maximum pc delta that will use the short encoding.
+ static const int kMaxSmallPCDelta;
+
enum Mode {
// Please note the order is important (see IsCodeTarget, IsGCRelocMode).
CONSTRUCT_CALL, // code target that is a call to a JavaScript constructor.
@@ -317,7 +333,7 @@ class RelocInfo BASE_EMBEDDED {
INLINE(void set_call_object(Object* target));
INLINE(Object** call_object_address());
- template<typename StaticVisitor> inline void Visit();
+ template<typename StaticVisitor> inline void Visit(Heap* heap);
inline void Visit(ObjectVisitor* v);
// Patch the code with some other code.
@@ -501,121 +517,129 @@ class ExternalReference BASE_EMBEDDED {
typedef void* ExternalReferenceRedirector(void* original, Type type);
- explicit ExternalReference(Builtins::CFunctionId id);
+ ExternalReference(Builtins::CFunctionId id, Isolate* isolate);
- explicit ExternalReference(ApiFunction* ptr, Type type);
+ ExternalReference(ApiFunction* ptr, Type type, Isolate* isolate);
- explicit ExternalReference(Builtins::Name name);
+ ExternalReference(Builtins::Name name, Isolate* isolate);
- explicit ExternalReference(Runtime::FunctionId id);
+ ExternalReference(Runtime::FunctionId id, Isolate* isolate);
- explicit ExternalReference(Runtime::Function* f);
+ ExternalReference(const Runtime::Function* f, Isolate* isolate);
- explicit ExternalReference(const IC_Utility& ic_utility);
+ ExternalReference(const IC_Utility& ic_utility, Isolate* isolate);
#ifdef ENABLE_DEBUGGER_SUPPORT
- explicit ExternalReference(const Debug_Address& debug_address);
+ ExternalReference(const Debug_Address& debug_address, Isolate* isolate);
#endif
explicit ExternalReference(StatsCounter* counter);
- explicit ExternalReference(Top::AddressId id);
+ ExternalReference(Isolate::AddressId id, Isolate* isolate);
explicit ExternalReference(const SCTableReference& table_ref);
+ // Isolate::Current() as an external reference.
+ static ExternalReference isolate_address();
+
// One-of-a-kind references. These references are not part of a general
// pattern. This means that they have to be added to the
// ExternalReferenceTable in serialize.cc manually.
- static ExternalReference perform_gc_function();
- static ExternalReference fill_heap_number_with_random_function();
- static ExternalReference random_uint32_function();
- static ExternalReference transcendental_cache_array_address();
- static ExternalReference delete_handle_scope_extensions();
+ static ExternalReference perform_gc_function(Isolate* isolate);
+ static ExternalReference fill_heap_number_with_random_function(
+ Isolate* isolate);
+ static ExternalReference random_uint32_function(Isolate* isolate);
+ static ExternalReference transcendental_cache_array_address(Isolate* isolate);
+ static ExternalReference delete_handle_scope_extensions(Isolate* isolate);
// Deoptimization support.
- static ExternalReference new_deoptimizer_function();
- static ExternalReference compute_output_frames_function();
- static ExternalReference global_contexts_list();
+ static ExternalReference new_deoptimizer_function(Isolate* isolate);
+ static ExternalReference compute_output_frames_function(Isolate* isolate);
+ static ExternalReference global_contexts_list(Isolate* isolate);
// Static data in the keyed lookup cache.
- static ExternalReference keyed_lookup_cache_keys();
- static ExternalReference keyed_lookup_cache_field_offsets();
+ static ExternalReference keyed_lookup_cache_keys(Isolate* isolate);
+ static ExternalReference keyed_lookup_cache_field_offsets(Isolate* isolate);
// Static variable Factory::the_hole_value.location()
- static ExternalReference the_hole_value_location();
+ static ExternalReference the_hole_value_location(Isolate* isolate);
// Static variable Factory::arguments_marker.location()
- static ExternalReference arguments_marker_location();
+ static ExternalReference arguments_marker_location(Isolate* isolate);
// Static variable Heap::roots_address()
- static ExternalReference roots_address();
+ static ExternalReference roots_address(Isolate* isolate);
// Static variable StackGuard::address_of_jslimit()
- static ExternalReference address_of_stack_limit();
+ static ExternalReference address_of_stack_limit(Isolate* isolate);
// Static variable StackGuard::address_of_real_jslimit()
- static ExternalReference address_of_real_stack_limit();
+ static ExternalReference address_of_real_stack_limit(Isolate* isolate);
// Static variable RegExpStack::limit_address()
- static ExternalReference address_of_regexp_stack_limit();
+ static ExternalReference address_of_regexp_stack_limit(Isolate* isolate);
// Static variables for RegExp.
- static ExternalReference address_of_static_offsets_vector();
- static ExternalReference address_of_regexp_stack_memory_address();
- static ExternalReference address_of_regexp_stack_memory_size();
+ static ExternalReference address_of_static_offsets_vector(Isolate* isolate);
+ static ExternalReference address_of_regexp_stack_memory_address(
+ Isolate* isolate);
+ static ExternalReference address_of_regexp_stack_memory_size(
+ Isolate* isolate);
// Static variable Heap::NewSpaceStart()
- static ExternalReference new_space_start();
- static ExternalReference new_space_mask();
- static ExternalReference heap_always_allocate_scope_depth();
+ static ExternalReference new_space_start(Isolate* isolate);
+ static ExternalReference new_space_mask(Isolate* isolate);
+ static ExternalReference heap_always_allocate_scope_depth(Isolate* isolate);
// Used for fast allocation in generated code.
- static ExternalReference new_space_allocation_top_address();
- static ExternalReference new_space_allocation_limit_address();
+ static ExternalReference new_space_allocation_top_address(Isolate* isolate);
+ static ExternalReference new_space_allocation_limit_address(Isolate* isolate);
- static ExternalReference double_fp_operation(Token::Value operation);
- static ExternalReference compare_doubles();
- static ExternalReference power_double_double_function();
- static ExternalReference power_double_int_function();
+ static ExternalReference double_fp_operation(Token::Value operation,
+ Isolate* isolate);
+ static ExternalReference compare_doubles(Isolate* isolate);
+ static ExternalReference power_double_double_function(Isolate* isolate);
+ static ExternalReference power_double_int_function(Isolate* isolate);
static ExternalReference handle_scope_next_address();
static ExternalReference handle_scope_limit_address();
static ExternalReference handle_scope_level_address();
- static ExternalReference scheduled_exception_address();
+ static ExternalReference scheduled_exception_address(Isolate* isolate);
// Static variables containing common double constants.
static ExternalReference address_of_min_int();
static ExternalReference address_of_one_half();
static ExternalReference address_of_minus_zero();
static ExternalReference address_of_negative_infinity();
+ static ExternalReference address_of_nan();
- static ExternalReference math_sin_double_function();
- static ExternalReference math_cos_double_function();
- static ExternalReference math_log_double_function();
+ static ExternalReference math_sin_double_function(Isolate* isolate);
+ static ExternalReference math_cos_double_function(Isolate* isolate);
+ static ExternalReference math_log_double_function(Isolate* isolate);
Address address() const {return reinterpret_cast<Address>(address_);}
#ifdef ENABLE_DEBUGGER_SUPPORT
// Function Debug::Break()
- static ExternalReference debug_break();
+ static ExternalReference debug_break(Isolate* isolate);
// Used to check if single stepping is enabled in generated code.
- static ExternalReference debug_step_in_fp_address();
+ static ExternalReference debug_step_in_fp_address(Isolate* isolate);
#endif
#ifndef V8_INTERPRETED_REGEXP
// C functions called from RegExp generated code.
// Function NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()
- static ExternalReference re_case_insensitive_compare_uc16();
+ static ExternalReference re_case_insensitive_compare_uc16(Isolate* isolate);
// Function RegExpMacroAssembler*::CheckStackGuardState()
- static ExternalReference re_check_stack_guard_state();
+ static ExternalReference re_check_stack_guard_state(Isolate* isolate);
// Function NativeRegExpMacroAssembler::GrowStack()
- static ExternalReference re_grow_stack();
+ static ExternalReference re_grow_stack(Isolate* isolate);
// byte NativeRegExpMacroAssembler::word_character_bitmap
static ExternalReference re_word_character_map();
@@ -625,29 +649,37 @@ class ExternalReference BASE_EMBEDDED {
// This lets you register a function that rewrites all external references.
// Used by the ARM simulator to catch calls to external references.
static void set_redirector(ExternalReferenceRedirector* redirector) {
- ASSERT(redirector_ == NULL); // We can't stack them.
- redirector_ = redirector;
+ // We can't stack them.
+ ASSERT(Isolate::Current()->external_reference_redirector() == NULL);
+ Isolate::Current()->set_external_reference_redirector(
+ reinterpret_cast<ExternalReferenceRedirectorPointer*>(redirector));
}
private:
explicit ExternalReference(void* address)
: address_(address) {}
- static ExternalReferenceRedirector* redirector_;
-
- static void* Redirect(void* address,
+ static void* Redirect(Isolate* isolate,
+ void* address,
Type type = ExternalReference::BUILTIN_CALL) {
- if (redirector_ == NULL) return address;
- void* answer = (*redirector_)(address, type);
+ ExternalReferenceRedirector* redirector =
+ reinterpret_cast<ExternalReferenceRedirector*>(
+ isolate->external_reference_redirector());
+ if (redirector == NULL) return address;
+ void* answer = (*redirector)(address, type);
return answer;
}
- static void* Redirect(Address address_arg,
+ static void* Redirect(Isolate* isolate,
+ Address address_arg,
Type type = ExternalReference::BUILTIN_CALL) {
+ ExternalReferenceRedirector* redirector =
+ reinterpret_cast<ExternalReferenceRedirector*>(
+ isolate->external_reference_redirector());
void* address = reinterpret_cast<void*>(address_arg);
- void* answer = (redirector_ == NULL) ?
+ void* answer = (redirector == NULL) ?
address :
- (*redirector_)(address, type);
+ (*redirector)(address, type);
return answer;
}
diff --git a/src/ast-inl.h b/src/ast-inl.h
index eb81c3a8..6021fd90 100644
--- a/src/ast-inl.h
+++ b/src/ast-inl.h
@@ -102,6 +102,11 @@ ForInStatement::ForInStatement(ZoneStringList* labels)
}
+bool FunctionLiteral::strict_mode() const {
+ return scope()->is_strict_mode();
+}
+
+
} } // namespace v8::internal
#endif // V8_AST_INL_H_
diff --git a/src/ast.cc b/src/ast.cc
index 772684cf..84343578 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -36,13 +36,13 @@
namespace v8 {
namespace internal {
-unsigned AstNode::current_id_ = 0;
-unsigned AstNode::count_ = 0;
-VariableProxySentinel VariableProxySentinel::this_proxy_(true);
-VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
-ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
-Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
-Call Call::sentinel_(NULL, NULL, 0);
+AstSentinels::AstSentinels()
+ : this_proxy_(true),
+ identifier_proxy_(false),
+ valid_left_hand_side_sentinel_(),
+ this_property_(&this_proxy_, NULL, 0),
+ call_sentinel_(NULL, NULL, 0) {
+}
// ----------------------------------------------------------------------------
@@ -170,7 +170,7 @@ ObjectLiteral::Property::Property(Literal* key, Expression* value) {
key_ = key;
value_ = value;
Object* k = *key->handle();
- if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) {
+ if (k->IsSymbol() && HEAP->Proto_symbol()->Equals(String::cast(k))) {
kind_ = PROTOTYPE;
} else if (value_->AsMaterializedLiteral() != NULL) {
kind_ = MATERIALIZED_LITERAL;
@@ -249,10 +249,11 @@ void ObjectLiteral::CalculateEmitStore() {
uint32_t hash;
HashMap* table;
void* key;
+ Factory* factory = Isolate::Current()->factory();
if (handle->IsSymbol()) {
Handle<String> name(String::cast(*handle));
if (name->AsArrayIndex(&hash)) {
- Handle<Object> key_handle = Factory::NewNumberFromUint(hash);
+ Handle<Object> key_handle = factory->NewNumberFromUint(hash);
key = key_handle.location();
table = &elements;
} else {
@@ -269,7 +270,7 @@ void ObjectLiteral::CalculateEmitStore() {
char arr[100];
Vector<char> buffer(arr, ARRAY_SIZE(arr));
const char* str = DoubleToCString(num, buffer);
- Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
+ Handle<String> name = factory->NewStringFromAscii(CStrVector(str));
key = name.location();
hash = name->Hash();
table = &properties;
@@ -526,12 +527,12 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
// Record type feedback from the oracle in the AST.
is_monomorphic_ = oracle->LoadIsMonomorphic(this);
if (key()->IsPropertyName()) {
- if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_ArrayLength)) {
+ if (oracle->LoadIsBuiltin(this, Builtins::kLoadIC_ArrayLength)) {
is_array_length_ = true;
- } else if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_StringLength)) {
+ } else if (oracle->LoadIsBuiltin(this, Builtins::kLoadIC_StringLength)) {
is_string_length_ = true;
} else if (oracle->LoadIsBuiltin(this,
- Builtins::LoadIC_FunctionPrototype)) {
+ Builtins::kLoadIC_FunctionPrototype)) {
is_function_prototype_ = true;
} else {
Literal* lit_key = key()->AsLiteral();
@@ -540,8 +541,13 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
ZoneMapList* types = oracle->LoadReceiverTypes(this, name);
receiver_types_ = types;
}
+ } else if (oracle->LoadIsBuiltin(this, Builtins::kKeyedLoadIC_String)) {
+ is_string_access_ = true;
} else if (is_monomorphic_) {
monomorphic_receiver_type_ = oracle->LoadMonomorphicReceiverType(this);
+ if (monomorphic_receiver_type_->has_external_array_elements()) {
+ SetExternalArrayType(oracle->GetKeyedLoadExternalArrayType(this));
+ }
}
}
@@ -559,6 +565,9 @@ void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
} else if (is_monomorphic_) {
// Record receiver type for monomorphic keyed loads.
monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this);
+ if (monomorphic_receiver_type_->has_external_array_elements()) {
+ SetExternalArrayType(oracle->GetKeyedStoreExternalArrayType(this));
+ }
}
}
@@ -626,7 +635,7 @@ bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
// If the function is in new space we assume it's more likely to
// change and thus prefer the general IC code.
- if (!Heap::InNewSpace(*candidate) &&
+ if (!HEAP->InNewSpace(*candidate) &&
CanCallWithoutIC(candidate, arguments()->length())) {
target_ = candidate;
return true;
@@ -691,7 +700,7 @@ void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
bool AstVisitor::CheckStackOverflow() {
if (stack_overflow_) return true;
- StackLimitCheck check;
+ StackLimitCheck check(isolate_);
if (!check.HasOverflowed()) return false;
return (stack_overflow_ = true);
}
@@ -1062,6 +1071,8 @@ CaseClause::CaseClause(Expression* label,
: label_(label),
statements_(statements),
position_(pos),
- compare_type_(NONE) {}
+ compare_type_(NONE),
+ entry_id_(AstNode::GetNextId()) {
+}
} } // namespace v8::internal
diff --git a/src/ast.h b/src/ast.h
index 2aee5d72..e9a06ec5 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -135,7 +135,10 @@ class AstNode: public ZoneObject {
static const int kNoNumber = -1;
- AstNode() : id_(GetNextId()) { count_++; }
+ AstNode() : id_(GetNextId()) {
+ Isolate* isolate = Isolate::Current();
+ isolate->set_ast_node_count(isolate->ast_node_count() + 1);
+ }
virtual ~AstNode() { }
@@ -159,22 +162,28 @@ class AstNode: public ZoneObject {
// True if the node is simple enough for us to inline calls containing it.
virtual bool IsInlineable() const { return false; }
- static int Count() { return count_; }
- static void ResetIds() { current_id_ = 0; }
+ static int Count() { return Isolate::Current()->ast_node_count(); }
+ static void ResetIds() { Isolate::Current()->set_ast_node_id(0); }
unsigned id() const { return id_; }
protected:
- static unsigned GetNextId() { return current_id_++; }
+ static unsigned GetNextId() {
+ Isolate* isolate = Isolate::Current();
+ unsigned tmp = isolate->ast_node_id();
+ isolate->set_ast_node_id(tmp + 1);
+ return tmp;
+ }
static unsigned ReserveIdRange(int n) {
- unsigned tmp = current_id_;
- current_id_ += n;
+ Isolate* isolate = Isolate::Current();
+ unsigned tmp = isolate->ast_node_id();
+ isolate->set_ast_node_id(tmp + n);
return tmp;
}
private:
- static unsigned current_id_;
- static unsigned count_;
unsigned id_;
+
+ friend class CaseClause; // Generates AST IDs.
};
@@ -333,10 +342,6 @@ class ValidLeftHandSideSentinel: public Expression {
public:
virtual bool IsValidLeftHandSide() { return true; }
virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
- static ValidLeftHandSideSentinel* instance() { return &instance_; }
-
- private:
- static ValidLeftHandSideSentinel instance_;
};
@@ -694,6 +699,8 @@ class CaseClause: public ZoneObject {
int position() { return position_; }
void set_position(int pos) { position_ = pos; }
+ int EntryId() { return entry_id_; }
+
// Type feedback information.
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
bool IsSmiCompare() { return compare_type_ == SMI_ONLY; }
@@ -706,6 +713,7 @@ class CaseClause: public ZoneObject {
int position_;
enum CompareTypeFeedback { NONE, SMI_ONLY, OBJECT_ONLY };
CompareTypeFeedback compare_type_;
+ int entry_id_;
};
@@ -893,10 +901,17 @@ class Literal: public Expression {
virtual bool ToBooleanIsFalse() { return handle_->ToBoolean()->IsFalse(); }
// Identity testers.
- bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
- bool IsTrue() const { return handle_.is_identical_to(Factory::true_value()); }
+ bool IsNull() const {
+ ASSERT(!handle_.is_null());
+ return handle_->IsNull();
+ }
+ bool IsTrue() const {
+ ASSERT(!handle_.is_null());
+ return handle_->IsTrue();
+ }
bool IsFalse() const {
- return handle_.is_identical_to(Factory::false_value());
+ ASSERT(!handle_.is_null());
+ return handle_->IsFalse();
}
Handle<Object> handle() const { return handle_; }
@@ -970,11 +985,13 @@ class ObjectLiteral: public MaterializedLiteral {
int literal_index,
bool is_simple,
bool fast_elements,
- int depth)
+ int depth,
+ bool has_function)
: MaterializedLiteral(literal_index, is_simple, depth),
constant_properties_(constant_properties),
properties_(properties),
- fast_elements_(fast_elements) {}
+ fast_elements_(fast_elements),
+ has_function_(has_function) {}
DECLARE_NODE_TYPE(ObjectLiteral)
@@ -985,16 +1002,24 @@ class ObjectLiteral: public MaterializedLiteral {
bool fast_elements() const { return fast_elements_; }
+ bool has_function() { return has_function_; }
// Mark all computed expressions that are bound to a key that
// is shadowed by a later occurrence of the same key. For the
// marked expressions, no store code is emitted.
void CalculateEmitStore();
+ enum Flags {
+ kNoFlags = 0,
+ kFastElements = 1,
+ kHasFunction = 1 << 1
+ };
+
private:
Handle<FixedArray> constant_properties_;
ZoneList<Property*>* properties_;
bool fast_elements_;
+ bool has_function_;
};
@@ -1133,15 +1158,11 @@ class VariableProxy: public Expression {
class VariableProxySentinel: public VariableProxy {
public:
virtual bool IsValidLeftHandSide() { return !is_this(); }
- static VariableProxySentinel* this_proxy() { return &this_proxy_; }
- static VariableProxySentinel* identifier_proxy() {
- return &identifier_proxy_;
- }
private:
explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { }
- static VariableProxySentinel this_proxy_;
- static VariableProxySentinel identifier_proxy_;
+
+ friend class AstSentinels;
};
@@ -1209,6 +1230,7 @@ class Property: public Expression {
is_monomorphic_(false),
is_array_length_(false),
is_string_length_(false),
+ is_string_access_(false),
is_function_prototype_(false),
is_arguments_access_(false) { }
@@ -1223,6 +1245,7 @@ class Property: public Expression {
bool is_synthetic() const { return type_ == SYNTHETIC; }
bool IsStringLength() const { return is_string_length_; }
+ bool IsStringAccess() const { return is_string_access_; }
bool IsFunctionPrototype() const { return is_function_prototype_; }
// Marks that this is actually an argument rewritten to a keyed property
@@ -1232,6 +1255,11 @@ class Property: public Expression {
}
bool is_arguments_access() const { return is_arguments_access_; }
+ ExternalArrayType GetExternalArrayType() const { return array_type_; }
+ void SetExternalArrayType(ExternalArrayType array_type) {
+ array_type_ = array_type;
+ }
+
// Type feedback information.
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
virtual bool IsMonomorphic() { return is_monomorphic_; }
@@ -1241,10 +1269,6 @@ class Property: public Expression {
return monomorphic_receiver_type_;
}
- // Returns a property singleton property access on 'this'. Used
- // during preparsing.
- static Property* this_property() { return &this_property_; }
-
private:
Expression* obj_;
Expression* key_;
@@ -1255,12 +1279,11 @@ class Property: public Expression {
bool is_monomorphic_ : 1;
bool is_array_length_ : 1;
bool is_string_length_ : 1;
+ bool is_string_access_ : 1;
bool is_function_prototype_ : 1;
bool is_arguments_access_ : 1;
Handle<Map> monomorphic_receiver_type_;
-
- // Dummy property used during preparsing.
- static Property this_property_;
+ ExternalArrayType array_type_;
};
@@ -1298,8 +1321,6 @@ class Call: public Expression {
// Bailout support.
int ReturnId() const { return return_id_; }
- static Call* sentinel() { return &sentinel_; }
-
#ifdef DEBUG
// Used to assert that the FullCodeGenerator records the return site.
bool return_is_recorded_;
@@ -1318,8 +1339,36 @@ class Call: public Expression {
Handle<JSGlobalPropertyCell> cell_;
int return_id_;
+};
+
+
+class AstSentinels {
+ public:
+ ~AstSentinels() { }
+
+ // Returns a property singleton property access on 'this'. Used
+ // during preparsing.
+ Property* this_property() { return &this_property_; }
+ VariableProxySentinel* this_proxy() { return &this_proxy_; }
+ VariableProxySentinel* identifier_proxy() { return &identifier_proxy_; }
+ ValidLeftHandSideSentinel* valid_left_hand_side_sentinel() {
+ return &valid_left_hand_side_sentinel_;
+ }
+ Call* call_sentinel() { return &call_sentinel_; }
+ EmptyStatement* empty_statement() { return &empty_statement_; }
+
+ private:
+ AstSentinels();
+ VariableProxySentinel this_proxy_;
+ VariableProxySentinel identifier_proxy_;
+ ValidLeftHandSideSentinel valid_left_hand_side_sentinel_;
+ Property this_property_;
+ Call call_sentinel_;
+ EmptyStatement empty_statement_;
+
+ friend class Isolate;
- static Call sentinel_;
+ DISALLOW_COPY_AND_ASSIGN(AstSentinels);
};
@@ -1350,7 +1399,7 @@ class CallNew: public Expression {
class CallRuntime: public Expression {
public:
CallRuntime(Handle<String> name,
- Runtime::Function* function,
+ const Runtime::Function* function,
ZoneList<Expression*>* arguments)
: name_(name), function_(function), arguments_(arguments) { }
@@ -1359,13 +1408,13 @@ class CallRuntime: public Expression {
virtual bool IsInlineable() const;
Handle<String> name() const { return name_; }
- Runtime::Function* function() const { return function_; }
+ const Runtime::Function* function() const { return function_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
bool is_jsruntime() const { return function_ == NULL; }
private:
Handle<String> name_;
- Runtime::Function* function_;
+ const Runtime::Function* function_;
ZoneList<Expression*>* arguments_;
};
@@ -1621,6 +1670,10 @@ class Assignment: public Expression {
virtual Handle<Map> GetMonomorphicReceiverType() {
return monomorphic_receiver_type_;
}
+ ExternalArrayType GetExternalArrayType() const { return array_type_; }
+ void SetExternalArrayType(ExternalArrayType array_type) {
+ array_type_ = array_type;
+ }
// Bailout support.
int CompoundLoadId() const { return compound_load_id_; }
@@ -1641,6 +1694,7 @@ class Assignment: public Expression {
bool is_monomorphic_;
ZoneMapList* receiver_types_;
Handle<Map> monomorphic_receiver_type_;
+ ExternalArrayType array_type_;
};
@@ -1673,8 +1727,7 @@ class FunctionLiteral: public Expression {
int start_position,
int end_position,
bool is_expression,
- bool contains_loops,
- bool strict_mode)
+ bool contains_loops)
: name_(name),
scope_(scope),
body_(body),
@@ -1688,9 +1741,8 @@ class FunctionLiteral: public Expression {
end_position_(end_position),
is_expression_(is_expression),
contains_loops_(contains_loops),
- strict_mode_(strict_mode),
function_token_position_(RelocInfo::kNoPosition),
- inferred_name_(Heap::empty_string()),
+ inferred_name_(HEAP->empty_string()),
try_full_codegen_(false),
pretenure_(false) { }
@@ -1705,7 +1757,7 @@ class FunctionLiteral: public Expression {
int end_position() const { return end_position_; }
bool is_expression() const { return is_expression_; }
bool contains_loops() const { return contains_loops_; }
- bool strict_mode() const { return strict_mode_; }
+ bool strict_mode() const;
int materialized_literal_count() { return materialized_literal_count_; }
int expected_property_count() { return expected_property_count_; }
@@ -2138,7 +2190,7 @@ class RegExpEmpty: public RegExpTree {
class AstVisitor BASE_EMBEDDED {
public:
- AstVisitor() : stack_overflow_(false) { }
+ AstVisitor() : isolate_(Isolate::Current()), stack_overflow_(false) { }
virtual ~AstVisitor() { }
// Stack overflow check and dynamic dispatch.
@@ -2168,10 +2220,15 @@ class AstVisitor BASE_EMBEDDED {
AST_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
+ protected:
+ Isolate* isolate() { return isolate_; }
+
private:
+ Isolate* isolate_;
bool stack_overflow_;
};
+
} } // namespace v8::internal
#endif // V8_AST_H_
diff --git a/src/atomicops.h b/src/atomicops.h
index 72a0d0fb..e2057ed0 100644
--- a/src/atomicops.h
+++ b/src/atomicops.h
@@ -158,6 +158,8 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
#include "atomicops_internals_x86_gcc.h"
#elif defined(__GNUC__) && defined(V8_HOST_ARCH_ARM)
#include "atomicops_internals_arm_gcc.h"
+#elif defined(__GNUC__) && defined(V8_HOST_ARCH_MIPS)
+#include "atomicops_internals_mips_gcc.h"
#else
#error "Atomic operations are not supported on your platform"
#endif
diff --git a/src/atomicops_internals_mips_gcc.h b/src/atomicops_internals_mips_gcc.h
new file mode 100644
index 00000000..5113de28
--- /dev/null
+++ b/src/atomicops_internals_mips_gcc.h
@@ -0,0 +1,169 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef V8_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+#define V8_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("sync" : : : "memory")
+
+namespace v8 {
+namespace internal {
+
+// Atomically execute:
+// result = *ptr;
+// if (*ptr == old_value)
+// *ptr = new_value;
+// return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev;
+ __asm__ __volatile__("1:\n"
+ "ll %0, %1\n" // prev = *ptr
+ "bne %0, %3, 2f\n" // if (prev != old_value) goto 2
+ "nop\n" // delay slot nop
+ "sc %2, %1\n" // *ptr = new_value (with atomic check)
+ "beqz %2, 1b\n" // start again on atomic error
+ "nop\n" // delay slot nop
+ "2:\n"
+ : "=&r" (prev), "=m" (*ptr), "+&r" (new_value)
+ : "Ir" (old_value), "r" (new_value), "m" (*ptr)
+ : "memory");
+ return prev;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr. This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 temp, old;
+ __asm__ __volatile__("1:\n"
+ "ll %1, %2\n" // old = *ptr
+ "move %0, %3\n" // temp = new_value
+ "sc %0, %2\n" // *ptr = temp (with atomic check)
+ "beqz %0, 1b\n" // start again on atomic error
+ "nop\n" // delay slot nop
+ : "=&r" (temp), "=&r" (old), "=m" (*ptr)
+ : "r" (new_value), "m" (*ptr)
+ : "memory");
+
+ return old;
+}
+
+// Atomically increment *ptr by "increment". Returns the new value of
+// *ptr with the increment applied. This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 temp, temp2;
+
+ __asm__ __volatile__("1:\n"
+ "ll %0, %2\n" // temp = *ptr
+ "addu %0, %3\n" // temp = temp + increment
+ "move %1, %0\n" // temp2 = temp
+ "sc %0, %2\n" // *ptr = temp (with atomic check)
+ "beqz %0, 1b\n" // start again on atomic error
+ "nop\n" // delay slot nop
+ : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
+ : "Ir" (increment), "m" (*ptr)
+ : "memory");
+ // temp2 now holds the final value.
+ return temp2;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
+ ATOMICOPS_COMPILER_BARRIER();
+ return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation. "Barrier" operations have both "Acquire" and "Release"
+// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ ATOMICOPS_COMPILER_BARRIER();
+ return x;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ ATOMICOPS_COMPILER_BARRIER();
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void MemoryBarrier() {
+ ATOMICOPS_COMPILER_BARRIER();
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+} } // namespace v8::internal
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif // V8_ATOMICOPS_INTERNALS_MIPS_GCC_H_
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 8cd29b21..9c9bac76 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -44,100 +44,57 @@
namespace v8 {
namespace internal {
-// A SourceCodeCache uses a FixedArray to store pairs of
-// (AsciiString*, JSFunction*), mapping names of native code files
-// (runtime.js, etc.) to precompiled functions. Instead of mapping
-// names to functions it might make sense to let the JS2C tool
-// generate an index for each native JS file.
-class SourceCodeCache BASE_EMBEDDED {
- public:
- explicit SourceCodeCache(Script::Type type): type_(type), cache_(NULL) { }
-
- void Initialize(bool create_heap_objects) {
- cache_ = create_heap_objects ? Heap::empty_fixed_array() : NULL;
- }
-
- void Iterate(ObjectVisitor* v) {
- v->VisitPointer(BitCast<Object**>(&cache_));
- }
-
-
- bool Lookup(Vector<const char> name, Handle<SharedFunctionInfo>* handle) {
- for (int i = 0; i < cache_->length(); i+=2) {
- SeqAsciiString* str = SeqAsciiString::cast(cache_->get(i));
- if (str->IsEqualTo(name)) {
- *handle = Handle<SharedFunctionInfo>(
- SharedFunctionInfo::cast(cache_->get(i + 1)));
- return true;
- }
- }
- return false;
- }
-
-
- void Add(Vector<const char> name, Handle<SharedFunctionInfo> shared) {
- HandleScope scope;
- int length = cache_->length();
- Handle<FixedArray> new_array =
- Factory::NewFixedArray(length + 2, TENURED);
- cache_->CopyTo(0, *new_array, 0, cache_->length());
- cache_ = *new_array;
- Handle<String> str = Factory::NewStringFromAscii(name, TENURED);
- cache_->set(length, *str);
- cache_->set(length + 1, *shared);
- Script::cast(shared->script())->set_type(Smi::FromInt(type_));
- }
-
- private:
- Script::Type type_;
- FixedArray* cache_;
- DISALLOW_COPY_AND_ASSIGN(SourceCodeCache);
-};
-
-static SourceCodeCache extensions_cache(Script::TYPE_EXTENSION);
-// This is for delete, not delete[].
-static List<char*>* delete_these_non_arrays_on_tear_down = NULL;
-// This is for delete[]
-static List<char*>* delete_these_arrays_on_tear_down = NULL;
-
-NativesExternalStringResource::NativesExternalStringResource(const char* source)
+NativesExternalStringResource::NativesExternalStringResource(
+ Bootstrapper* bootstrapper,
+ const char* source)
: data_(source), length_(StrLength(source)) {
- if (delete_these_non_arrays_on_tear_down == NULL) {
- delete_these_non_arrays_on_tear_down = new List<char*>(2);
+ if (bootstrapper->delete_these_non_arrays_on_tear_down_ == NULL) {
+ bootstrapper->delete_these_non_arrays_on_tear_down_ = new List<char*>(2);
}
// The resources are small objects and we only make a fixed number of
// them, but let's clean them up on exit for neatness.
- delete_these_non_arrays_on_tear_down->
+ bootstrapper->delete_these_non_arrays_on_tear_down_->
Add(reinterpret_cast<char*>(this));
}
+Bootstrapper::Bootstrapper()
+ : nesting_(0),
+ extensions_cache_(Script::TYPE_EXTENSION),
+ delete_these_non_arrays_on_tear_down_(NULL),
+ delete_these_arrays_on_tear_down_(NULL) {
+}
+
+
Handle<String> Bootstrapper::NativesSourceLookup(int index) {
ASSERT(0 <= index && index < Natives::GetBuiltinsCount());
- if (Heap::natives_source_cache()->get(index)->IsUndefined()) {
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Heap* heap = isolate->heap();
+ if (heap->natives_source_cache()->get(index)->IsUndefined()) {
if (!Snapshot::IsEnabled() || FLAG_new_snapshot) {
// We can use external strings for the natives.
NativesExternalStringResource* resource =
- new NativesExternalStringResource(
+ new NativesExternalStringResource(this,
Natives::GetScriptSource(index).start());
Handle<String> source_code =
- Factory::NewExternalStringFromAscii(resource);
- Heap::natives_source_cache()->set(index, *source_code);
+ factory->NewExternalStringFromAscii(resource);
+ heap->natives_source_cache()->set(index, *source_code);
} else {
// Old snapshot code can't cope with external strings at all.
Handle<String> source_code =
- Factory::NewStringFromAscii(Natives::GetScriptSource(index));
- Heap::natives_source_cache()->set(index, *source_code);
+ factory->NewStringFromAscii(Natives::GetScriptSource(index));
+ heap->natives_source_cache()->set(index, *source_code);
}
}
- Handle<Object> cached_source(Heap::natives_source_cache()->get(index));
+ Handle<Object> cached_source(heap->natives_source_cache()->get(index));
return Handle<String>::cast(cached_source);
}
void Bootstrapper::Initialize(bool create_heap_objects) {
- extensions_cache.Initialize(create_heap_objects);
+ extensions_cache_.Initialize(create_heap_objects);
GCExtension::Register();
ExternalizeStringExtension::Register();
}
@@ -146,39 +103,39 @@ void Bootstrapper::Initialize(bool create_heap_objects) {
char* Bootstrapper::AllocateAutoDeletedArray(int bytes) {
char* memory = new char[bytes];
if (memory != NULL) {
- if (delete_these_arrays_on_tear_down == NULL) {
- delete_these_arrays_on_tear_down = new List<char*>(2);
+ if (delete_these_arrays_on_tear_down_ == NULL) {
+ delete_these_arrays_on_tear_down_ = new List<char*>(2);
}
- delete_these_arrays_on_tear_down->Add(memory);
+ delete_these_arrays_on_tear_down_->Add(memory);
}
return memory;
}
void Bootstrapper::TearDown() {
- if (delete_these_non_arrays_on_tear_down != NULL) {
- int len = delete_these_non_arrays_on_tear_down->length();
+ if (delete_these_non_arrays_on_tear_down_ != NULL) {
+ int len = delete_these_non_arrays_on_tear_down_->length();
ASSERT(len < 20); // Don't use this mechanism for unbounded allocations.
for (int i = 0; i < len; i++) {
- delete delete_these_non_arrays_on_tear_down->at(i);
- delete_these_non_arrays_on_tear_down->at(i) = NULL;
+ delete delete_these_non_arrays_on_tear_down_->at(i);
+ delete_these_non_arrays_on_tear_down_->at(i) = NULL;
}
- delete delete_these_non_arrays_on_tear_down;
- delete_these_non_arrays_on_tear_down = NULL;
+ delete delete_these_non_arrays_on_tear_down_;
+ delete_these_non_arrays_on_tear_down_ = NULL;
}
- if (delete_these_arrays_on_tear_down != NULL) {
- int len = delete_these_arrays_on_tear_down->length();
+ if (delete_these_arrays_on_tear_down_ != NULL) {
+ int len = delete_these_arrays_on_tear_down_->length();
ASSERT(len < 1000); // Don't use this mechanism for unbounded allocations.
for (int i = 0; i < len; i++) {
- delete[] delete_these_arrays_on_tear_down->at(i);
- delete_these_arrays_on_tear_down->at(i) = NULL;
+ delete[] delete_these_arrays_on_tear_down_->at(i);
+ delete_these_arrays_on_tear_down_->at(i) = NULL;
}
- delete delete_these_arrays_on_tear_down;
- delete_these_arrays_on_tear_down = NULL;
+ delete delete_these_arrays_on_tear_down_;
+ delete_these_arrays_on_tear_down_ = NULL;
}
- extensions_cache.Initialize(false); // Yes, symmetrical
+ extensions_cache_.Initialize(false); // Yes, symmetrical
}
@@ -207,6 +164,10 @@ class Genesis BASE_EMBEDDED {
void CreateRoots();
// Creates the empty function. Used for creating a context from scratch.
Handle<JSFunction> CreateEmptyFunction();
+ // Creates the ThrowTypeError function. ECMA 5th Ed. 13.2.3
+ Handle<JSFunction> CreateThrowTypeErrorFunction(Builtins::Name builtin);
+
+ void CreateStrictModeFunctionMaps(Handle<JSFunction> empty);
// Creates the global objects using the global and the template passed in
// through the API. We call this regardless of whether we are building a
// context from scratch or using a deserialized one from the partial snapshot
@@ -260,10 +221,24 @@ class Genesis BASE_EMBEDDED {
ADD_READONLY_PROTOTYPE,
ADD_WRITEABLE_PROTOTYPE
};
+
+ Handle<Map> CreateFunctionMap(PrototypePropertyMode prototype_mode);
+
Handle<DescriptorArray> ComputeFunctionInstanceDescriptor(
PrototypePropertyMode prototypeMode);
void MakeFunctionInstancePrototypeWritable();
+ Handle<Map> CreateStrictModeFunctionMap(
+ PrototypePropertyMode prototype_mode,
+ Handle<JSFunction> empty_function,
+ Handle<FixedArray> arguments_callbacks,
+ Handle<FixedArray> caller_callbacks);
+
+ Handle<DescriptorArray> ComputeStrictFunctionInstanceDescriptor(
+ PrototypePropertyMode propertyMode,
+ Handle<FixedArray> arguments,
+ Handle<FixedArray> caller);
+
static bool CompileBuiltin(int index);
static bool CompileNative(Vector<const char> name, Handle<String> source);
static bool CompileScriptCached(Vector<const char> name,
@@ -274,14 +249,21 @@ class Genesis BASE_EMBEDDED {
bool use_runtime_context);
Handle<Context> result_;
- Handle<JSFunction> empty_function_;
+
+ // Function instance maps. Function literal maps are created initially with
+ // a read only prototype for the processing of JS builtins. Later the function
+ // instance maps are replaced in order to make prototype writable.
+ // These are the final, writable prototype, maps.
+ Handle<Map> function_instance_map_writable_prototype_;
+ Handle<Map> strict_mode_function_instance_map_writable_prototype_;
+
BootstrapperActive active_;
friend class Bootstrapper;
};
void Bootstrapper::Iterate(ObjectVisitor* v) {
- extensions_cache.Iterate(v);
+ extensions_cache_.Iterate(v);
v->Synchronize("Extensions");
}
@@ -306,16 +288,17 @@ Handle<Context> Bootstrapper::CreateEnvironment(
static void SetObjectPrototype(Handle<JSObject> object, Handle<Object> proto) {
// object.__proto__ = proto;
Handle<Map> old_to_map = Handle<Map>(object->map());
- Handle<Map> new_to_map = Factory::CopyMapDropTransitions(old_to_map);
+ Handle<Map> new_to_map = FACTORY->CopyMapDropTransitions(old_to_map);
new_to_map->set_prototype(*proto);
object->set_map(*new_to_map);
}
void Bootstrapper::DetachGlobal(Handle<Context> env) {
- JSGlobalProxy::cast(env->global_proxy())->set_context(*Factory::null_value());
+ Factory* factory = Isolate::Current()->factory();
+ JSGlobalProxy::cast(env->global_proxy())->set_context(*factory->null_value());
SetObjectPrototype(Handle<JSObject>(env->global_proxy()),
- Factory::null_value());
+ factory->null_value());
env->set_global_proxy(env->global());
env->global()->set_global_receiver(env->global());
}
@@ -339,11 +322,13 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
Handle<JSObject> prototype,
Builtins::Name call,
bool is_ecma_native) {
- Handle<String> symbol = Factory::LookupAsciiSymbol(name);
- Handle<Code> call_code = Handle<Code>(Builtins::builtin(call));
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Handle<String> symbol = factory->LookupAsciiSymbol(name);
+ Handle<Code> call_code = Handle<Code>(isolate->builtins()->builtin(call));
Handle<JSFunction> function = prototype.is_null() ?
- Factory::NewFunctionWithoutPrototype(symbol, call_code) :
- Factory::NewFunctionWithPrototype(symbol,
+ factory->NewFunctionWithoutPrototype(symbol, call_code) :
+ factory->NewFunctionWithPrototype(symbol,
type,
instance_size,
prototype,
@@ -359,174 +344,305 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
PrototypePropertyMode prototypeMode) {
- Handle<DescriptorArray> result = Factory::empty_descriptor_array();
+ Factory* factory = Isolate::Current()->factory();
+ Handle<DescriptorArray> descriptors =
+ factory->NewDescriptorArray(prototypeMode == DONT_ADD_PROTOTYPE ? 4 : 5);
+ PropertyAttributes attributes =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+ { // Add length.
+ Handle<Proxy> proxy = factory->NewProxy(&Accessors::FunctionLength);
+ CallbacksDescriptor d(*factory->length_symbol(), *proxy, attributes);
+ descriptors->Set(0, &d);
+ }
+ { // Add name.
+ Handle<Proxy> proxy = factory->NewProxy(&Accessors::FunctionName);
+ CallbacksDescriptor d(*factory->name_symbol(), *proxy, attributes);
+ descriptors->Set(1, &d);
+ }
+ { // Add arguments.
+ Handle<Proxy> proxy = factory->NewProxy(&Accessors::FunctionArguments);
+ CallbacksDescriptor d(*factory->arguments_symbol(), *proxy, attributes);
+ descriptors->Set(2, &d);
+ }
+ { // Add caller.
+ Handle<Proxy> proxy = factory->NewProxy(&Accessors::FunctionCaller);
+ CallbacksDescriptor d(*factory->caller_symbol(), *proxy, attributes);
+ descriptors->Set(3, &d);
+ }
if (prototypeMode != DONT_ADD_PROTOTYPE) {
- PropertyAttributes attributes = static_cast<PropertyAttributes>(
- DONT_ENUM |
- DONT_DELETE |
- (prototypeMode == ADD_READONLY_PROTOTYPE ? READ_ONLY : 0));
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::prototype_symbol(),
- Factory::NewProxy(&Accessors::FunctionPrototype),
- attributes);
+ // Add prototype.
+ if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
+ attributes = static_cast<PropertyAttributes>(attributes & ~READ_ONLY);
+ }
+ Handle<Proxy> proxy = factory->NewProxy(&Accessors::FunctionPrototype);
+ CallbacksDescriptor d(*factory->prototype_symbol(), *proxy, attributes);
+ descriptors->Set(4, &d);
}
+ descriptors->Sort();
+ return descriptors;
+}
- PropertyAttributes attributes =
- static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
- // Add length.
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::length_symbol(),
- Factory::NewProxy(&Accessors::FunctionLength),
- attributes);
-
- // Add name.
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::name_symbol(),
- Factory::NewProxy(&Accessors::FunctionName),
- attributes);
-
- // Add arguments.
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::arguments_symbol(),
- Factory::NewProxy(&Accessors::FunctionArguments),
- attributes);
-
- // Add caller.
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::caller_symbol(),
- Factory::NewProxy(&Accessors::FunctionCaller),
- attributes);
- return result;
+Handle<Map> Genesis::CreateFunctionMap(PrototypePropertyMode prototype_mode) {
+ Handle<Map> map = FACTORY->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
+ Handle<DescriptorArray> descriptors =
+ ComputeFunctionInstanceDescriptor(prototype_mode);
+ map->set_instance_descriptors(*descriptors);
+ map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
+ return map;
}
Handle<JSFunction> Genesis::CreateEmptyFunction() {
- // Allocate the map for function instances.
- Handle<Map> fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
- global_context()->set_function_instance_map(*fm);
+ // Allocate the map for function instances. Maps are allocated first and their
+ // prototypes patched later, once empty function is created.
+
// Please note that the prototype property for function instances must be
// writable.
- Handle<DescriptorArray> function_map_descriptors =
- ComputeFunctionInstanceDescriptor(ADD_WRITEABLE_PROTOTYPE);
- fm->set_instance_descriptors(*function_map_descriptors);
- fm->set_function_with_prototype(true);
+ global_context()->set_function_instance_map(
+ *CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE));
// Functions with this map will not have a 'prototype' property, and
// can not be used as constructors.
- Handle<Map> function_without_prototype_map =
- Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
global_context()->set_function_without_prototype_map(
- *function_without_prototype_map);
- Handle<DescriptorArray> function_without_prototype_map_descriptors =
- ComputeFunctionInstanceDescriptor(DONT_ADD_PROTOTYPE);
- function_without_prototype_map->set_instance_descriptors(
- *function_without_prototype_map_descriptors);
- function_without_prototype_map->set_function_with_prototype(false);
+ *CreateFunctionMap(DONT_ADD_PROTOTYPE));
- // Allocate the function map first and then patch the prototype later
- fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
- global_context()->set_function_map(*fm);
- function_map_descriptors =
- ComputeFunctionInstanceDescriptor(ADD_READONLY_PROTOTYPE);
- fm->set_instance_descriptors(*function_map_descriptors);
- fm->set_function_with_prototype(true);
+ // Allocate the function map. This map is temporary, used only for processing
+ // of builtins.
+ // Later the map is replaced with writable prototype map, allocated below.
+ global_context()->set_function_map(
+ *CreateFunctionMap(ADD_READONLY_PROTOTYPE));
- Handle<String> object_name = Handle<String>(Heap::Object_symbol());
+ // The final map for functions. Writeable prototype.
+ // This map is installed in MakeFunctionInstancePrototypeWritable.
+ function_instance_map_writable_prototype_ =
+ CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE);
+
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Heap* heap = isolate->heap();
+
+ Handle<String> object_name = Handle<String>(heap->Object_symbol());
{ // --- O b j e c t ---
Handle<JSFunction> object_fun =
- Factory::NewFunction(object_name, Factory::null_value());
+ factory->NewFunction(object_name, factory->null_value());
Handle<Map> object_function_map =
- Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
object_fun->set_initial_map(*object_function_map);
object_function_map->set_constructor(*object_fun);
global_context()->set_object_function(*object_fun);
// Allocate a new prototype for the object function.
- Handle<JSObject> prototype = Factory::NewJSObject(Top::object_function(),
- TENURED);
+ Handle<JSObject> prototype = factory->NewJSObject(
+ isolate->object_function(),
+ TENURED);
global_context()->set_initial_object_prototype(*prototype);
SetPrototype(object_fun, prototype);
object_function_map->
- set_instance_descriptors(Heap::empty_descriptor_array());
+ set_instance_descriptors(heap->empty_descriptor_array());
}
// Allocate the empty function as the prototype for function ECMAScript
// 262 15.3.4.
- Handle<String> symbol = Factory::LookupAsciiSymbol("Empty");
+ Handle<String> symbol = factory->LookupAsciiSymbol("Empty");
Handle<JSFunction> empty_function =
- Factory::NewFunctionWithoutPrototype(symbol);
+ factory->NewFunctionWithoutPrototype(symbol, kNonStrictMode);
// --- E m p t y ---
Handle<Code> code =
- Handle<Code>(Builtins::builtin(Builtins::EmptyFunction));
+ Handle<Code>(isolate->builtins()->builtin(
+ Builtins::kEmptyFunction));
empty_function->set_code(*code);
empty_function->shared()->set_code(*code);
- Handle<String> source = Factory::NewStringFromAscii(CStrVector("() {}"));
- Handle<Script> script = Factory::NewScript(source);
+ Handle<String> source = factory->NewStringFromAscii(CStrVector("() {}"));
+ Handle<Script> script = factory->NewScript(source);
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
empty_function->shared()->set_script(*script);
empty_function->shared()->set_start_position(0);
empty_function->shared()->set_end_position(source->length());
empty_function->shared()->DontAdaptArguments();
+
+ // Set prototypes for the function maps.
global_context()->function_map()->set_prototype(*empty_function);
global_context()->function_instance_map()->set_prototype(*empty_function);
global_context()->function_without_prototype_map()->
set_prototype(*empty_function);
+ function_instance_map_writable_prototype_->set_prototype(*empty_function);
// Allocate the function map first and then patch the prototype later
- Handle<Map> empty_fm = Factory::CopyMapDropDescriptors(
+ Handle<Map> function_without_prototype_map(
+ global_context()->function_without_prototype_map());
+ Handle<Map> empty_fm = factory->CopyMapDropDescriptors(
function_without_prototype_map);
empty_fm->set_instance_descriptors(
- *function_without_prototype_map_descriptors);
+ function_without_prototype_map->instance_descriptors());
empty_fm->set_prototype(global_context()->object_function()->prototype());
empty_function->set_map(*empty_fm);
return empty_function;
}
+Handle<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
+ PrototypePropertyMode prototypeMode,
+ Handle<FixedArray> arguments,
+ Handle<FixedArray> caller) {
+ Factory* factory = Isolate::Current()->factory();
+ Handle<DescriptorArray> descriptors =
+ factory->NewDescriptorArray(prototypeMode == DONT_ADD_PROTOTYPE ? 4 : 5);
+ PropertyAttributes attributes = static_cast<PropertyAttributes>(
+ DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+ { // length
+ Handle<Proxy> proxy = factory->NewProxy(&Accessors::FunctionLength);
+ CallbacksDescriptor d(*factory->length_symbol(), *proxy, attributes);
+ descriptors->Set(0, &d);
+ }
+ { // name
+ Handle<Proxy> proxy = factory->NewProxy(&Accessors::FunctionName);
+ CallbacksDescriptor d(*factory->name_symbol(), *proxy, attributes);
+ descriptors->Set(1, &d);
+ }
+ { // arguments
+ CallbacksDescriptor d(*factory->arguments_symbol(), *arguments, attributes);
+ descriptors->Set(2, &d);
+ }
+ { // caller
+ CallbacksDescriptor d(*factory->caller_symbol(), *caller, attributes);
+ descriptors->Set(3, &d);
+ }
+
+ // prototype
+ if (prototypeMode != DONT_ADD_PROTOTYPE) {
+ if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
+ attributes = static_cast<PropertyAttributes>(attributes & ~READ_ONLY);
+ }
+ Handle<Proxy> proxy = factory->NewProxy(&Accessors::FunctionPrototype);
+ CallbacksDescriptor d(*factory->prototype_symbol(), *proxy, attributes);
+ descriptors->Set(4, &d);
+ }
+
+ descriptors->Sort();
+ return descriptors;
+}
+
+
+// ECMAScript 5th Edition, 13.2.3
+Handle<JSFunction> Genesis::CreateThrowTypeErrorFunction(
+ Builtins::Name builtin) {
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+
+ Handle<String> name = factory->LookupAsciiSymbol("ThrowTypeError");
+ Handle<JSFunction> throw_type_error =
+ factory->NewFunctionWithoutPrototype(name, kStrictMode);
+ Handle<Code> code = Handle<Code>(
+ isolate->builtins()->builtin(builtin));
+
+ throw_type_error->set_map(global_context()->strict_mode_function_map());
+ throw_type_error->set_code(*code);
+ throw_type_error->shared()->set_code(*code);
+ throw_type_error->shared()->DontAdaptArguments();
+
+ PreventExtensions(throw_type_error);
+
+ return throw_type_error;
+}
+
+
+Handle<Map> Genesis::CreateStrictModeFunctionMap(
+ PrototypePropertyMode prototype_mode,
+ Handle<JSFunction> empty_function,
+ Handle<FixedArray> arguments_callbacks,
+ Handle<FixedArray> caller_callbacks) {
+ Handle<Map> map = FACTORY->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
+ Handle<DescriptorArray> descriptors =
+ ComputeStrictFunctionInstanceDescriptor(prototype_mode,
+ arguments_callbacks,
+ caller_callbacks);
+ map->set_instance_descriptors(*descriptors);
+ map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
+ map->set_prototype(*empty_function);
+ return map;
+}
+
+
+void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
+ // Create the callbacks arrays for ThrowTypeError functions.
+ // The get/set callacks are filled in after the maps are created below.
+ Factory* factory = Isolate::Current()->factory();
+ Handle<FixedArray> arguments = factory->NewFixedArray(2, TENURED);
+ Handle<FixedArray> caller = factory->NewFixedArray(2, TENURED);
+
+ // Allocate map for the strict mode function instances.
+ global_context()->set_strict_mode_function_instance_map(
+ *CreateStrictModeFunctionMap(
+ ADD_WRITEABLE_PROTOTYPE, empty, arguments, caller));
+
+ // Allocate map for the prototype-less strict mode instances.
+ global_context()->set_strict_mode_function_without_prototype_map(
+ *CreateStrictModeFunctionMap(
+ DONT_ADD_PROTOTYPE, empty, arguments, caller));
+
+ // Allocate map for the strict mode functions. This map is temporary, used
+ // only for processing of builtins.
+ // Later the map is replaced with writable prototype map, allocated below.
+ global_context()->set_strict_mode_function_map(
+ *CreateStrictModeFunctionMap(
+ ADD_READONLY_PROTOTYPE, empty, arguments, caller));
+
+ // The final map for the strict mode functions. Writeable prototype.
+ // This map is installed in MakeFunctionInstancePrototypeWritable.
+ strict_mode_function_instance_map_writable_prototype_ =
+ CreateStrictModeFunctionMap(
+ ADD_WRITEABLE_PROTOTYPE, empty, arguments, caller);
+
+ // Create the ThrowTypeError function instances.
+ Handle<JSFunction> arguments_throw =
+ CreateThrowTypeErrorFunction(Builtins::kStrictFunctionArguments);
+ Handle<JSFunction> caller_throw =
+ CreateThrowTypeErrorFunction(Builtins::kStrictFunctionCaller);
+
+ // Complete the callback fixed arrays.
+ arguments->set(0, *arguments_throw);
+ arguments->set(1, *arguments_throw);
+ caller->set(0, *caller_throw);
+ caller->set(1, *caller_throw);
+}
+
+
static void AddToWeakGlobalContextList(Context* context) {
ASSERT(context->IsGlobalContext());
+ Heap* heap = Isolate::Current()->heap();
#ifdef DEBUG
{ // NOLINT
ASSERT(context->get(Context::NEXT_CONTEXT_LINK)->IsUndefined());
// Check that context is not in the list yet.
- for (Object* current = Heap::global_contexts_list();
+ for (Object* current = heap->global_contexts_list();
!current->IsUndefined();
current = Context::cast(current)->get(Context::NEXT_CONTEXT_LINK)) {
ASSERT(current != context);
}
}
#endif
- context->set(Context::NEXT_CONTEXT_LINK, Heap::global_contexts_list());
- Heap::set_global_contexts_list(context);
+ context->set(Context::NEXT_CONTEXT_LINK, heap->global_contexts_list());
+ heap->set_global_contexts_list(context);
}
void Genesis::CreateRoots() {
+ Isolate* isolate = Isolate::Current();
// Allocate the global context FixedArray first and then patch the
// closure and extension object later (we need the empty function
// and the global object, but in order to create those, we need the
// global context).
- global_context_ =
- Handle<Context>::cast(
- GlobalHandles::Create(*Factory::NewGlobalContext()));
+ global_context_ = Handle<Context>::cast(isolate->global_handles()->Create(
+ *isolate->factory()->NewGlobalContext()));
AddToWeakGlobalContextList(*global_context_);
- Top::set_context(*global_context());
+ isolate->set_context(*global_context());
// Allocate the message listeners object.
{
@@ -569,11 +685,16 @@ Handle<JSGlobalProxy> Genesis::CreateNewGlobals(
}
}
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Heap* heap = isolate->heap();
+
if (js_global_template.is_null()) {
- Handle<String> name = Handle<String>(Heap::empty_symbol());
- Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+ Handle<String> name = Handle<String>(heap->empty_symbol());
+ Handle<Code> code = Handle<Code>(isolate->builtins()->builtin(
+ Builtins::kIllegal));
js_global_function =
- Factory::NewFunction(name, JS_GLOBAL_OBJECT_TYPE,
+ factory->NewFunction(name, JS_GLOBAL_OBJECT_TYPE,
JSGlobalObject::kSize, code, true);
// Change the constructor property of the prototype of the
// hidden global function to refer to the Object function.
@@ -581,18 +702,21 @@ Handle<JSGlobalProxy> Genesis::CreateNewGlobals(
Handle<JSObject>(
JSObject::cast(js_global_function->instance_prototype()));
SetLocalPropertyNoThrow(
- prototype, Factory::constructor_symbol(), Top::object_function(), NONE);
+ prototype,
+ factory->constructor_symbol(),
+ isolate->object_function(),
+ NONE);
} else {
Handle<FunctionTemplateInfo> js_global_constructor(
FunctionTemplateInfo::cast(js_global_template->constructor()));
js_global_function =
- Factory::CreateApiFunction(js_global_constructor,
- Factory::InnerGlobalObject);
+ factory->CreateApiFunction(js_global_constructor,
+ factory->InnerGlobalObject);
}
js_global_function->initial_map()->set_is_hidden_prototype();
Handle<GlobalObject> inner_global =
- Factory::NewGlobalObject(js_global_function);
+ factory->NewGlobalObject(js_global_function);
if (inner_global_out != NULL) {
*inner_global_out = inner_global;
}
@@ -600,10 +724,11 @@ Handle<JSGlobalProxy> Genesis::CreateNewGlobals(
// Step 2: create or re-initialize the global proxy object.
Handle<JSFunction> global_proxy_function;
if (global_template.IsEmpty()) {
- Handle<String> name = Handle<String>(Heap::empty_symbol());
- Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+ Handle<String> name = Handle<String>(heap->empty_symbol());
+ Handle<Code> code = Handle<Code>(isolate->builtins()->builtin(
+ Builtins::kIllegal));
global_proxy_function =
- Factory::NewFunction(name, JS_GLOBAL_PROXY_TYPE,
+ factory->NewFunction(name, JS_GLOBAL_PROXY_TYPE,
JSGlobalProxy::kSize, code, true);
} else {
Handle<ObjectTemplateInfo> data =
@@ -611,11 +736,11 @@ Handle<JSGlobalProxy> Genesis::CreateNewGlobals(
Handle<FunctionTemplateInfo> global_constructor(
FunctionTemplateInfo::cast(data->constructor()));
global_proxy_function =
- Factory::CreateApiFunction(global_constructor,
- Factory::OuterGlobalObject);
+ factory->CreateApiFunction(global_constructor,
+ factory->OuterGlobalObject);
}
- Handle<String> global_name = Factory::LookupAsciiSymbol("global");
+ Handle<String> global_name = factory->LookupAsciiSymbol("global");
global_proxy_function->shared()->set_instance_class_name(*global_name);
global_proxy_function->initial_map()->set_is_access_check_needed(true);
@@ -629,7 +754,7 @@ Handle<JSGlobalProxy> Genesis::CreateNewGlobals(
Handle<JSGlobalProxy>::cast(global_object));
} else {
return Handle<JSGlobalProxy>::cast(
- Factory::NewJSObject(global_proxy_function, TENURED));
+ factory->NewJSObject(global_proxy_function, TENURED));
}
}
@@ -654,7 +779,7 @@ void Genesis::HookUpInnerGlobal(Handle<GlobalObject> inner_global) {
static const PropertyAttributes attributes =
static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
ForceSetProperty(builtins_global,
- Factory::LookupAsciiSymbol("global"),
+ FACTORY->LookupAsciiSymbol("global"),
inner_global,
attributes);
// Setup the reference from the global object to the builtins object.
@@ -682,33 +807,37 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// object reinitialization.
global_context()->set_security_token(*inner_global);
- Handle<String> object_name = Handle<String>(Heap::Object_symbol());
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Heap* heap = isolate->heap();
+
+ Handle<String> object_name = Handle<String>(heap->Object_symbol());
SetLocalPropertyNoThrow(inner_global, object_name,
- Top::object_function(), DONT_ENUM);
+ isolate->object_function(), DONT_ENUM);
Handle<JSObject> global = Handle<JSObject>(global_context()->global());
// Install global Function object
InstallFunction(global, "Function", JS_FUNCTION_TYPE, JSFunction::kSize,
- empty_function, Builtins::Illegal, true); // ECMA native.
+ empty_function, Builtins::kIllegal, true); // ECMA native.
{ // --- A r r a y ---
Handle<JSFunction> array_function =
InstallFunction(global, "Array", JS_ARRAY_TYPE, JSArray::kSize,
- Top::initial_object_prototype(), Builtins::ArrayCode,
- true);
+ isolate->initial_object_prototype(),
+ Builtins::kArrayCode, true);
array_function->shared()->set_construct_stub(
- Builtins::builtin(Builtins::ArrayConstructCode));
+ isolate->builtins()->builtin(Builtins::kArrayConstructCode));
array_function->shared()->DontAdaptArguments();
// This seems a bit hackish, but we need to make sure Array.length
// is 1.
array_function->shared()->set_length(1);
Handle<DescriptorArray> array_descriptors =
- Factory::CopyAppendProxyDescriptor(
- Factory::empty_descriptor_array(),
- Factory::length_symbol(),
- Factory::NewProxy(&Accessors::ArrayLength),
+ factory->CopyAppendProxyDescriptor(
+ factory->empty_descriptor_array(),
+ factory->length_symbol(),
+ factory->NewProxy(&Accessors::ArrayLength),
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE));
// Cache the fast JavaScript array map
@@ -725,33 +854,33 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
{ // --- N u m b e r ---
Handle<JSFunction> number_fun =
InstallFunction(global, "Number", JS_VALUE_TYPE, JSValue::kSize,
- Top::initial_object_prototype(), Builtins::Illegal,
- true);
+ isolate->initial_object_prototype(),
+ Builtins::kIllegal, true);
global_context()->set_number_function(*number_fun);
}
{ // --- B o o l e a n ---
Handle<JSFunction> boolean_fun =
InstallFunction(global, "Boolean", JS_VALUE_TYPE, JSValue::kSize,
- Top::initial_object_prototype(), Builtins::Illegal,
- true);
+ isolate->initial_object_prototype(),
+ Builtins::kIllegal, true);
global_context()->set_boolean_function(*boolean_fun);
}
{ // --- S t r i n g ---
Handle<JSFunction> string_fun =
InstallFunction(global, "String", JS_VALUE_TYPE, JSValue::kSize,
- Top::initial_object_prototype(), Builtins::Illegal,
- true);
+ isolate->initial_object_prototype(),
+ Builtins::kIllegal, true);
string_fun->shared()->set_construct_stub(
- Builtins::builtin(Builtins::StringConstructCode));
+ isolate->builtins()->builtin(Builtins::kStringConstructCode));
global_context()->set_string_function(*string_fun);
// Add 'length' property to strings.
Handle<DescriptorArray> string_descriptors =
- Factory::CopyAppendProxyDescriptor(
- Factory::empty_descriptor_array(),
- Factory::length_symbol(),
- Factory::NewProxy(&Accessors::StringLength),
+ factory->CopyAppendProxyDescriptor(
+ factory->empty_descriptor_array(),
+ factory->length_symbol(),
+ factory->NewProxy(&Accessors::StringLength),
static_cast<PropertyAttributes>(DONT_ENUM |
DONT_DELETE |
READ_ONLY));
@@ -765,8 +894,8 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// Builtin functions for Date.prototype.
Handle<JSFunction> date_fun =
InstallFunction(global, "Date", JS_VALUE_TYPE, JSValue::kSize,
- Top::initial_object_prototype(), Builtins::Illegal,
- true);
+ isolate->initial_object_prototype(),
+ Builtins::kIllegal, true);
global_context()->set_date_function(*date_fun);
}
@@ -776,8 +905,8 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// Builtin functions for RegExp.prototype.
Handle<JSFunction> regexp_fun =
InstallFunction(global, "RegExp", JS_REGEXP_TYPE, JSRegExp::kSize,
- Top::initial_object_prototype(), Builtins::Illegal,
- true);
+ isolate->initial_object_prototype(),
+ Builtins::kIllegal, true);
global_context()->set_regexp_function(*regexp_fun);
ASSERT(regexp_fun->has_initial_map());
@@ -785,13 +914,13 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
ASSERT_EQ(0, initial_map->inobject_properties());
- Handle<DescriptorArray> descriptors = Factory::NewDescriptorArray(5);
+ Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(5);
PropertyAttributes final =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
int enum_index = 0;
{
// ECMA-262, section 15.10.7.1.
- FieldDescriptor field(Heap::source_symbol(),
+ FieldDescriptor field(heap->source_symbol(),
JSRegExp::kSourceFieldIndex,
final,
enum_index++);
@@ -799,7 +928,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
}
{
// ECMA-262, section 15.10.7.2.
- FieldDescriptor field(Heap::global_symbol(),
+ FieldDescriptor field(heap->global_symbol(),
JSRegExp::kGlobalFieldIndex,
final,
enum_index++);
@@ -807,7 +936,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
}
{
// ECMA-262, section 15.10.7.3.
- FieldDescriptor field(Heap::ignore_case_symbol(),
+ FieldDescriptor field(heap->ignore_case_symbol(),
JSRegExp::kIgnoreCaseFieldIndex,
final,
enum_index++);
@@ -815,7 +944,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
}
{
// ECMA-262, section 15.10.7.4.
- FieldDescriptor field(Heap::multiline_symbol(),
+ FieldDescriptor field(heap->multiline_symbol(),
JSRegExp::kMultilineFieldIndex,
final,
enum_index++);
@@ -825,7 +954,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// ECMA-262, section 15.10.7.5.
PropertyAttributes writable =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
- FieldDescriptor field(Heap::last_index_symbol(),
+ FieldDescriptor field(heap->last_index_symbol(),
JSRegExp::kLastIndexFieldIndex,
writable,
enum_index++);
@@ -844,13 +973,13 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
}
{ // -- J S O N
- Handle<String> name = Factory::NewStringFromAscii(CStrVector("JSON"));
- Handle<JSFunction> cons = Factory::NewFunction(
+ Handle<String> name = factory->NewStringFromAscii(CStrVector("JSON"));
+ Handle<JSFunction> cons = factory->NewFunction(
name,
- Factory::the_hole_value());
+ factory->the_hole_value());
cons->SetInstancePrototype(global_context()->initial_object_prototype());
cons->SetInstanceClassName(*name);
- Handle<JSObject> json_object = Factory::NewJSObject(cons, TENURED);
+ Handle<JSObject> json_object = factory->NewJSObject(cons, TENURED);
ASSERT(json_object->IsJSObject());
SetLocalPropertyNoThrow(global, name, json_object, DONT_ENUM);
global_context()->set_json_object(*json_object);
@@ -860,14 +989,15 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
// Make sure we can recognize argument objects at runtime.
// This is done by introducing an anonymous function with
// class_name equals 'Arguments'.
- Handle<String> symbol = Factory::LookupAsciiSymbol("Arguments");
- Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+ Handle<String> symbol = factory->LookupAsciiSymbol("Arguments");
+ Handle<Code> code = Handle<Code>(
+ isolate->builtins()->builtin(Builtins::kIllegal));
Handle<JSObject> prototype =
Handle<JSObject>(
JSObject::cast(global_context()->object_function()->prototype()));
Handle<JSFunction> function =
- Factory::NewFunctionWithPrototype(symbol,
+ factory->NewFunctionWithPrototype(symbol,
JS_OBJECT_TYPE,
JSObject::kHeaderSize,
prototype,
@@ -876,30 +1006,101 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
ASSERT(!function->has_initial_map());
function->shared()->set_instance_class_name(*symbol);
function->shared()->set_expected_nof_properties(2);
- Handle<JSObject> result = Factory::NewJSObject(function);
+ Handle<JSObject> result = factory->NewJSObject(function);
global_context()->set_arguments_boilerplate(*result);
- // Note: callee must be added as the first property and
- // length must be added as the second property.
- SetLocalPropertyNoThrow(result, Factory::callee_symbol(),
- Factory::undefined_value(),
+ // Note: length must be added as the first property and
+ // callee must be added as the second property.
+ SetLocalPropertyNoThrow(result, factory->length_symbol(),
+ factory->undefined_value(),
DONT_ENUM);
- SetLocalPropertyNoThrow(result, Factory::length_symbol(),
- Factory::undefined_value(),
+ SetLocalPropertyNoThrow(result, factory->callee_symbol(),
+ factory->undefined_value(),
DONT_ENUM);
#ifdef DEBUG
LookupResult lookup;
- result->LocalLookup(Heap::callee_symbol(), &lookup);
+ result->LocalLookup(heap->callee_symbol(), &lookup);
ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
- ASSERT(lookup.GetFieldIndex() == Heap::arguments_callee_index);
+ ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsCalleeIndex);
- result->LocalLookup(Heap::length_symbol(), &lookup);
+ result->LocalLookup(heap->length_symbol(), &lookup);
ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
- ASSERT(lookup.GetFieldIndex() == Heap::arguments_length_index);
+ ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex);
- ASSERT(result->map()->inobject_properties() > Heap::arguments_callee_index);
- ASSERT(result->map()->inobject_properties() > Heap::arguments_length_index);
+ ASSERT(result->map()->inobject_properties() > Heap::kArgumentsCalleeIndex);
+ ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex);
+
+ // Check the state of the object.
+ ASSERT(result->HasFastProperties());
+ ASSERT(result->HasFastElements());
+#endif
+ }
+
+ { // --- strict mode arguments boilerplate
+ const PropertyAttributes attributes =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+ // Create the ThrowTypeError functions.
+ Handle<FixedArray> callee = factory->NewFixedArray(2, TENURED);
+ Handle<FixedArray> caller = factory->NewFixedArray(2, TENURED);
+
+ Handle<JSFunction> callee_throw =
+ CreateThrowTypeErrorFunction(Builtins::kStrictArgumentsCallee);
+ Handle<JSFunction> caller_throw =
+ CreateThrowTypeErrorFunction(Builtins::kStrictArgumentsCaller);
+
+ // Install the ThrowTypeError functions.
+ callee->set(0, *callee_throw);
+ callee->set(1, *callee_throw);
+ caller->set(0, *caller_throw);
+ caller->set(1, *caller_throw);
+
+ // Create the descriptor array for the arguments object.
+ Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(3);
+ { // length
+ FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM);
+ descriptors->Set(0, &d);
+ }
+ { // callee
+ CallbacksDescriptor d(*factory->callee_symbol(), *callee, attributes);
+ descriptors->Set(1, &d);
+ }
+ { // caller
+ CallbacksDescriptor d(*factory->caller_symbol(), *caller, attributes);
+ descriptors->Set(2, &d);
+ }
+ descriptors->Sort();
+
+ // Create the map. Allocate one in-object field for length.
+ Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE,
+ Heap::kArgumentsObjectSizeStrict);
+ map->set_instance_descriptors(*descriptors);
+ map->set_function_with_prototype(true);
+ map->set_prototype(global_context()->object_function()->prototype());
+ map->set_pre_allocated_property_fields(1);
+ map->set_inobject_properties(1);
+
+ // Copy constructor from the non-strict arguments boilerplate.
+ map->set_constructor(
+ global_context()->arguments_boilerplate()->map()->constructor());
+
+ // Allocate the arguments boilerplate object.
+ Handle<JSObject> result = factory->NewJSObjectFromMap(map);
+ global_context()->set_strict_mode_arguments_boilerplate(*result);
+
+ // Add length property only for strict mode boilerplate.
+ SetLocalPropertyNoThrow(result, factory->length_symbol(),
+ factory->undefined_value(),
+ DONT_ENUM);
+
+#ifdef DEBUG
+ LookupResult lookup;
+ result->LocalLookup(heap->length_symbol(), &lookup);
+ ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
+ ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex);
+
+ ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex);
// Check the state of the object.
ASSERT(result->HasFastProperties());
@@ -909,15 +1110,16 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
{ // --- context extension
// Create a function for the context extension objects.
- Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+ Handle<Code> code = Handle<Code>(
+ isolate->builtins()->builtin(Builtins::kIllegal));
Handle<JSFunction> context_extension_fun =
- Factory::NewFunction(Factory::empty_symbol(),
+ factory->NewFunction(factory->empty_symbol(),
JS_CONTEXT_EXTENSION_OBJECT_TYPE,
JSObject::kHeaderSize,
code,
true);
- Handle<String> name = Factory::LookupAsciiSymbol("context_extension");
+ Handle<String> name = factory->LookupAsciiSymbol("context_extension");
context_extension_fun->shared()->set_instance_class_name(*name);
global_context()->set_context_extension_function(*context_extension_fun);
}
@@ -926,9 +1128,10 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
{
// Setup the call-as-function delegate.
Handle<Code> code =
- Handle<Code>(Builtins::builtin(Builtins::HandleApiCallAsFunction));
+ Handle<Code>(isolate->builtins()->builtin(
+ Builtins::kHandleApiCallAsFunction));
Handle<JSFunction> delegate =
- Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
+ factory->NewFunction(factory->empty_symbol(), JS_OBJECT_TYPE,
JSObject::kHeaderSize, code, true);
global_context()->set_call_as_function_delegate(*delegate);
delegate->shared()->DontAdaptArguments();
@@ -937,44 +1140,47 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
{
// Setup the call-as-constructor delegate.
Handle<Code> code =
- Handle<Code>(Builtins::builtin(Builtins::HandleApiCallAsConstructor));
+ Handle<Code>(isolate->builtins()->builtin(
+ Builtins::kHandleApiCallAsConstructor));
Handle<JSFunction> delegate =
- Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
+ factory->NewFunction(factory->empty_symbol(), JS_OBJECT_TYPE,
JSObject::kHeaderSize, code, true);
global_context()->set_call_as_constructor_delegate(*delegate);
delegate->shared()->DontAdaptArguments();
}
// Initialize the out of memory slot.
- global_context()->set_out_of_memory(Heap::false_value());
+ global_context()->set_out_of_memory(heap->false_value());
// Initialize the data slot.
- global_context()->set_data(Heap::undefined_value());
+ global_context()->set_data(heap->undefined_value());
}
bool Genesis::CompileBuiltin(int index) {
Vector<const char> name = Natives::GetScriptName(index);
- Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
+ Handle<String> source_code =
+ Isolate::Current()->bootstrapper()->NativesSourceLookup(index);
return CompileNative(name, source_code);
}
bool Genesis::CompileNative(Vector<const char> name, Handle<String> source) {
HandleScope scope;
+ Isolate* isolate = Isolate::Current();
#ifdef ENABLE_DEBUGGER_SUPPORT
- Debugger::set_compiling_natives(true);
+ isolate->debugger()->set_compiling_natives(true);
#endif
bool result = CompileScriptCached(name,
source,
NULL,
NULL,
- Handle<Context>(Top::context()),
+ Handle<Context>(isolate->context()),
true);
- ASSERT(Top::has_pending_exception() != result);
- if (!result) Top::clear_pending_exception();
+ ASSERT(isolate->has_pending_exception() != result);
+ if (!result) isolate->clear_pending_exception();
#ifdef ENABLE_DEBUGGER_SUPPORT
- Debugger::set_compiling_natives(false);
+ isolate->debugger()->set_compiling_natives(false);
#endif
return result;
}
@@ -986,6 +1192,7 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
v8::Extension* extension,
Handle<Context> top_context,
bool use_runtime_context) {
+ Factory* factory = Isolate::Current()->factory();
HandleScope scope;
Handle<SharedFunctionInfo> function_info;
@@ -993,7 +1200,7 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
// function and insert it into the cache.
if (cache == NULL || !cache->Lookup(name, &function_info)) {
ASSERT(source->IsAsciiRepresentation());
- Handle<String> script_name = Factory::NewStringFromUtf8(name);
+ Handle<String> script_name = factory->NewStringFromUtf8(name);
function_info = Compiler::Compile(
source,
script_name,
@@ -1016,7 +1223,7 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
? Handle<Context>(top_context->runtime_context())
: top_context);
Handle<JSFunction> fun =
- Factory::NewFunctionFromSharedFunctionInfo(function_info, context);
+ factory->NewFunctionFromSharedFunctionInfo(function_info, context);
// Call function using either the runtime object or the global
// object as the receiver. Provide no parameters.
@@ -1033,11 +1240,13 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
#define INSTALL_NATIVE(Type, name, var) \
- Handle<String> var##_name = Factory::LookupAsciiSymbol(name); \
+ Handle<String> var##_name = factory->LookupAsciiSymbol(name); \
global_context()->set_##var(Type::cast( \
global_context()->builtins()->GetPropertyNoExceptionThrown(*var##_name)));
+
void Genesis::InstallNativeFunctions() {
+ Factory* factory = Isolate::Current()->factory();
HandleScope scope;
INSTALL_NATIVE(JSFunction, "CreateDate", create_date_fun);
INSTALL_NATIVE(JSFunction, "ToNumber", to_number_fun);
@@ -1060,21 +1269,25 @@ void Genesis::InstallNativeFunctions() {
bool Genesis::InstallNatives() {
HandleScope scope;
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Heap* heap = isolate->heap();
// Create a function for the builtins object. Allocate space for the
// JavaScript builtins, a reference to the builtins object
// (itself) and a reference to the global_context directly in the object.
- Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+ Handle<Code> code = Handle<Code>(
+ isolate->builtins()->builtin(Builtins::kIllegal));
Handle<JSFunction> builtins_fun =
- Factory::NewFunction(Factory::empty_symbol(), JS_BUILTINS_OBJECT_TYPE,
+ factory->NewFunction(factory->empty_symbol(), JS_BUILTINS_OBJECT_TYPE,
JSBuiltinsObject::kSize, code, true);
- Handle<String> name = Factory::LookupAsciiSymbol("builtins");
+ Handle<String> name = factory->LookupAsciiSymbol("builtins");
builtins_fun->shared()->set_instance_class_name(*name);
// Allocate the builtins object.
Handle<JSBuiltinsObject> builtins =
- Handle<JSBuiltinsObject>::cast(Factory::NewGlobalObject(builtins_fun));
+ Handle<JSBuiltinsObject>::cast(factory->NewGlobalObject(builtins_fun));
builtins->set_builtins(*builtins);
builtins->set_global_context(*global_context());
builtins->set_global_receiver(*builtins);
@@ -1085,7 +1298,7 @@ bool Genesis::InstallNatives() {
// global object.
static const PropertyAttributes attributes =
static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
- Handle<String> global_symbol = Factory::LookupAsciiSymbol("global");
+ Handle<String> global_symbol = factory->LookupAsciiSymbol("global");
Handle<Object> global_obj(global_context()->global());
SetLocalPropertyNoThrow(builtins, global_symbol, global_obj, attributes);
@@ -1094,12 +1307,12 @@ bool Genesis::InstallNatives() {
// Create a bridge function that has context in the global context.
Handle<JSFunction> bridge =
- Factory::NewFunction(Factory::empty_symbol(), Factory::undefined_value());
- ASSERT(bridge->context() == *Top::global_context());
+ factory->NewFunction(factory->empty_symbol(), factory->undefined_value());
+ ASSERT(bridge->context() == *isolate->global_context());
// Allocate the builtins context.
Handle<Context> context =
- Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, bridge);
+ factory->NewFunctionContext(Context::MIN_CONTEXT_SLOTS, bridge);
context->set_global(*builtins); // override builtins global object
global_context()->set_runtime_context(*context);
@@ -1108,113 +1321,113 @@ bool Genesis::InstallNatives() {
// Builtin functions for Script.
Handle<JSFunction> script_fun =
InstallFunction(builtins, "Script", JS_VALUE_TYPE, JSValue::kSize,
- Top::initial_object_prototype(), Builtins::Illegal,
- false);
+ isolate->initial_object_prototype(),
+ Builtins::kIllegal, false);
Handle<JSObject> prototype =
- Factory::NewJSObject(Top::object_function(), TENURED);
+ factory->NewJSObject(isolate->object_function(), TENURED);
SetPrototype(script_fun, prototype);
global_context()->set_script_function(*script_fun);
// Add 'source' and 'data' property to scripts.
PropertyAttributes common_attributes =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
- Handle<Proxy> proxy_source = Factory::NewProxy(&Accessors::ScriptSource);
+ Handle<Proxy> proxy_source = factory->NewProxy(&Accessors::ScriptSource);
Handle<DescriptorArray> script_descriptors =
- Factory::CopyAppendProxyDescriptor(
- Factory::empty_descriptor_array(),
- Factory::LookupAsciiSymbol("source"),
+ factory->CopyAppendProxyDescriptor(
+ factory->empty_descriptor_array(),
+ factory->LookupAsciiSymbol("source"),
proxy_source,
common_attributes);
- Handle<Proxy> proxy_name = Factory::NewProxy(&Accessors::ScriptName);
+ Handle<Proxy> proxy_name = factory->NewProxy(&Accessors::ScriptName);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("name"),
+ factory->LookupAsciiSymbol("name"),
proxy_name,
common_attributes);
- Handle<Proxy> proxy_id = Factory::NewProxy(&Accessors::ScriptId);
+ Handle<Proxy> proxy_id = factory->NewProxy(&Accessors::ScriptId);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("id"),
+ factory->LookupAsciiSymbol("id"),
proxy_id,
common_attributes);
Handle<Proxy> proxy_line_offset =
- Factory::NewProxy(&Accessors::ScriptLineOffset);
+ factory->NewProxy(&Accessors::ScriptLineOffset);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("line_offset"),
+ factory->LookupAsciiSymbol("line_offset"),
proxy_line_offset,
common_attributes);
Handle<Proxy> proxy_column_offset =
- Factory::NewProxy(&Accessors::ScriptColumnOffset);
+ factory->NewProxy(&Accessors::ScriptColumnOffset);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("column_offset"),
+ factory->LookupAsciiSymbol("column_offset"),
proxy_column_offset,
common_attributes);
- Handle<Proxy> proxy_data = Factory::NewProxy(&Accessors::ScriptData);
+ Handle<Proxy> proxy_data = factory->NewProxy(&Accessors::ScriptData);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("data"),
+ factory->LookupAsciiSymbol("data"),
proxy_data,
common_attributes);
- Handle<Proxy> proxy_type = Factory::NewProxy(&Accessors::ScriptType);
+ Handle<Proxy> proxy_type = factory->NewProxy(&Accessors::ScriptType);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("type"),
+ factory->LookupAsciiSymbol("type"),
proxy_type,
common_attributes);
Handle<Proxy> proxy_compilation_type =
- Factory::NewProxy(&Accessors::ScriptCompilationType);
+ factory->NewProxy(&Accessors::ScriptCompilationType);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("compilation_type"),
+ factory->LookupAsciiSymbol("compilation_type"),
proxy_compilation_type,
common_attributes);
Handle<Proxy> proxy_line_ends =
- Factory::NewProxy(&Accessors::ScriptLineEnds);
+ factory->NewProxy(&Accessors::ScriptLineEnds);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("line_ends"),
+ factory->LookupAsciiSymbol("line_ends"),
proxy_line_ends,
common_attributes);
Handle<Proxy> proxy_context_data =
- Factory::NewProxy(&Accessors::ScriptContextData);
+ factory->NewProxy(&Accessors::ScriptContextData);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("context_data"),
+ factory->LookupAsciiSymbol("context_data"),
proxy_context_data,
common_attributes);
Handle<Proxy> proxy_eval_from_script =
- Factory::NewProxy(&Accessors::ScriptEvalFromScript);
+ factory->NewProxy(&Accessors::ScriptEvalFromScript);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("eval_from_script"),
+ factory->LookupAsciiSymbol("eval_from_script"),
proxy_eval_from_script,
common_attributes);
Handle<Proxy> proxy_eval_from_script_position =
- Factory::NewProxy(&Accessors::ScriptEvalFromScriptPosition);
+ factory->NewProxy(&Accessors::ScriptEvalFromScriptPosition);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("eval_from_script_position"),
+ factory->LookupAsciiSymbol("eval_from_script_position"),
proxy_eval_from_script_position,
common_attributes);
Handle<Proxy> proxy_eval_from_function_name =
- Factory::NewProxy(&Accessors::ScriptEvalFromFunctionName);
+ factory->NewProxy(&Accessors::ScriptEvalFromFunctionName);
script_descriptors =
- Factory::CopyAppendProxyDescriptor(
+ factory->CopyAppendProxyDescriptor(
script_descriptors,
- Factory::LookupAsciiSymbol("eval_from_function_name"),
+ factory->LookupAsciiSymbol("eval_from_function_name"),
proxy_eval_from_function_name,
common_attributes);
@@ -1222,9 +1435,9 @@ bool Genesis::InstallNatives() {
script_map->set_instance_descriptors(*script_descriptors);
// Allocate the empty script.
- Handle<Script> script = Factory::NewScript(Factory::empty_string());
+ Handle<Script> script = factory->NewScript(factory->empty_string());
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
- Heap::public_set_empty_script(*script);
+ heap->public_set_empty_script(*script);
}
{
// Builtin function for OpaqueReference -- a JSValue-based object,
@@ -1232,10 +1445,11 @@ bool Genesis::InstallNatives() {
// objects, that JavaScript code may not access.
Handle<JSFunction> opaque_reference_fun =
InstallFunction(builtins, "OpaqueReference", JS_VALUE_TYPE,
- JSValue::kSize, Top::initial_object_prototype(),
- Builtins::Illegal, false);
+ JSValue::kSize,
+ isolate->initial_object_prototype(),
+ Builtins::kIllegal, false);
Handle<JSObject> prototype =
- Factory::NewJSObject(Top::object_function(), TENURED);
+ factory->NewJSObject(isolate->object_function(), TENURED);
SetPrototype(opaque_reference_fun, prototype);
global_context()->set_opaque_reference_function(*opaque_reference_fun);
}
@@ -1254,23 +1468,23 @@ bool Genesis::InstallNatives() {
"InternalArray",
JS_ARRAY_TYPE,
JSArray::kSize,
- Top::initial_object_prototype(),
- Builtins::ArrayCode,
+ isolate->initial_object_prototype(),
+ Builtins::kArrayCode,
true);
Handle<JSObject> prototype =
- Factory::NewJSObject(Top::object_function(), TENURED);
+ factory->NewJSObject(isolate->object_function(), TENURED);
SetPrototype(array_function, prototype);
array_function->shared()->set_construct_stub(
- Builtins::builtin(Builtins::ArrayConstructCode));
+ isolate->builtins()->builtin(Builtins::kArrayConstructCode));
array_function->shared()->DontAdaptArguments();
// Make "length" magic on instances.
Handle<DescriptorArray> array_descriptors =
- Factory::CopyAppendProxyDescriptor(
- Factory::empty_descriptor_array(),
- Factory::length_symbol(),
- Factory::NewProxy(&Accessors::ArrayLength),
+ factory->CopyAppendProxyDescriptor(
+ factory->empty_descriptor_array(),
+ factory->length_symbol(),
+ factory->NewProxy(&Accessors::ArrayLength),
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE));
array_function->initial_map()->set_instance_descriptors(
@@ -1307,9 +1521,9 @@ bool Genesis::InstallNatives() {
InstallBuiltinFunctionIds();
// Install Function.prototype.call and apply.
- { Handle<String> key = Factory::function_class_symbol();
+ { Handle<String> key = factory->function_class_symbol();
Handle<JSFunction> function =
- Handle<JSFunction>::cast(GetProperty(Top::global(), key));
+ Handle<JSFunction>::cast(GetProperty(isolate->global(), key));
Handle<JSObject> proto =
Handle<JSObject>(JSObject::cast(function->instance_prototype()));
@@ -1317,12 +1531,12 @@ bool Genesis::InstallNatives() {
Handle<JSFunction> call =
InstallFunction(proto, "call", JS_OBJECT_TYPE, JSObject::kHeaderSize,
Handle<JSObject>::null(),
- Builtins::FunctionCall,
+ Builtins::kFunctionCall,
false);
Handle<JSFunction> apply =
InstallFunction(proto, "apply", JS_OBJECT_TYPE, JSObject::kHeaderSize,
Handle<JSObject>::null(),
- Builtins::FunctionApply,
+ Builtins::kFunctionApply,
false);
// Make sure that Function.prototype.call appears to be compiled.
@@ -1351,7 +1565,7 @@ bool Genesis::InstallNatives() {
// Add initial map.
Handle<Map> initial_map =
- Factory::NewMap(JS_ARRAY_TYPE, JSRegExpResult::kSize);
+ factory->NewMap(JS_ARRAY_TYPE, JSRegExpResult::kSize);
initial_map->set_constructor(*array_constructor);
// Set prototype on map.
@@ -1365,13 +1579,13 @@ bool Genesis::InstallNatives() {
ASSERT_EQ(1, array_descriptors->number_of_descriptors());
Handle<DescriptorArray> reresult_descriptors =
- Factory::NewDescriptorArray(3);
+ factory->NewDescriptorArray(3);
reresult_descriptors->CopyFrom(0, *array_descriptors, 0);
int enum_index = 0;
{
- FieldDescriptor index_field(Heap::index_symbol(),
+ FieldDescriptor index_field(heap->index_symbol(),
JSRegExpResult::kIndexIndex,
NONE,
enum_index++);
@@ -1379,7 +1593,7 @@ bool Genesis::InstallNatives() {
}
{
- FieldDescriptor input_field(Heap::input_symbol(),
+ FieldDescriptor input_field(heap->input_symbol(),
JSRegExpResult::kInputIndex,
NONE,
enum_index++);
@@ -1407,17 +1621,18 @@ bool Genesis::InstallNatives() {
static Handle<JSObject> ResolveBuiltinIdHolder(
Handle<Context> global_context,
const char* holder_expr) {
+ Factory* factory = Isolate::Current()->factory();
Handle<GlobalObject> global(global_context->global());
const char* period_pos = strchr(holder_expr, '.');
if (period_pos == NULL) {
return Handle<JSObject>::cast(
- GetProperty(global, Factory::LookupAsciiSymbol(holder_expr)));
+ GetProperty(global, factory->LookupAsciiSymbol(holder_expr)));
}
ASSERT_EQ(".prototype", period_pos);
Vector<const char> property(holder_expr,
static_cast<int>(period_pos - holder_expr));
Handle<JSFunction> function = Handle<JSFunction>::cast(
- GetProperty(global, Factory::LookupSymbol(property)));
+ GetProperty(global, factory->LookupSymbol(property)));
return Handle<JSObject>(JSObject::cast(function->prototype()));
}
@@ -1425,7 +1640,7 @@ static Handle<JSObject> ResolveBuiltinIdHolder(
static void InstallBuiltinFunctionId(Handle<JSObject> holder,
const char* function_name,
BuiltinFunctionId id) {
- Handle<String> name = Factory::LookupAsciiSymbol(function_name);
+ Handle<String> name = FACTORY->LookupAsciiSymbol(function_name);
Object* function_object = holder->GetProperty(*name)->ToObjectUnchecked();
Handle<JSFunction> function(JSFunction::cast(function_object));
function->shared()->set_function_data(Smi::FromInt(id));
@@ -1457,7 +1672,7 @@ static FixedArray* CreateCache(int size, JSFunction* factory) {
int array_size = JSFunctionResultCache::kEntriesIndex + 2 * size;
// Cannot use cast as object is not fully initialized yet.
JSFunctionResultCache* cache = reinterpret_cast<JSFunctionResultCache*>(
- *Factory::NewFixedArrayWithHoles(array_size, TENURED));
+ *FACTORY->NewFixedArrayWithHoles(array_size, TENURED));
cache->set(JSFunctionResultCache::kFactoryIndex, factory);
cache->MakeZeroSize();
return cache;
@@ -1471,7 +1686,7 @@ void Genesis::InstallJSFunctionResultCaches() {
#undef F
;
- Handle<FixedArray> caches = Factory::NewFixedArray(kNumberOfCaches, TENURED);
+ Handle<FixedArray> caches = FACTORY->NewFixedArray(kNumberOfCaches, TENURED);
int index = 0;
@@ -1490,19 +1705,17 @@ void Genesis::InstallJSFunctionResultCaches() {
void Genesis::InitializeNormalizedMapCaches() {
Handle<FixedArray> array(
- Factory::NewFixedArray(NormalizedMapCache::kEntries, TENURED));
+ FACTORY->NewFixedArray(NormalizedMapCache::kEntries, TENURED));
global_context()->set_normalized_map_cache(NormalizedMapCache::cast(*array));
}
-int BootstrapperActive::nesting_ = 0;
-
-
bool Bootstrapper::InstallExtensions(Handle<Context> global_context,
v8::ExtensionConfiguration* extensions) {
+ Isolate* isolate = Isolate::Current();
BootstrapperActive active;
- SaveContext saved_context;
- Top::set_context(*global_context);
+ SaveContext saved_context(isolate);
+ isolate->set_context(*global_context);
if (!Genesis::InstallExtensions(global_context, extensions)) return false;
Genesis::InstallSpecialObjects(global_context);
return true;
@@ -1510,20 +1723,21 @@ bool Bootstrapper::InstallExtensions(Handle<Context> global_context,
void Genesis::InstallSpecialObjects(Handle<Context> global_context) {
+ Factory* factory = Isolate::Current()->factory();
HandleScope scope;
Handle<JSGlobalObject> js_global(
JSGlobalObject::cast(global_context->global()));
// Expose the natives in global if a name for it is specified.
if (FLAG_expose_natives_as != NULL && strlen(FLAG_expose_natives_as) != 0) {
Handle<String> natives_string =
- Factory::LookupAsciiSymbol(FLAG_expose_natives_as);
+ factory->LookupAsciiSymbol(FLAG_expose_natives_as);
SetLocalPropertyNoThrow(js_global, natives_string,
Handle<JSObject>(js_global->builtins()), DONT_ENUM);
}
Handle<Object> Error = GetProperty(js_global, "Error");
if (Error->IsJSObject()) {
- Handle<String> name = Factory::LookupAsciiSymbol("stackTraceLimit");
+ Handle<String> name = factory->LookupAsciiSymbol("stackTraceLimit");
SetLocalPropertyNoThrow(Handle<JSObject>::cast(Error),
name,
Handle<Smi>(Smi::FromInt(FLAG_stack_trace_limit)),
@@ -1533,18 +1747,19 @@ void Genesis::InstallSpecialObjects(Handle<Context> global_context) {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Expose the debug global object in global if a name for it is specified.
if (FLAG_expose_debug_as != NULL && strlen(FLAG_expose_debug_as) != 0) {
+ Debug* debug = Isolate::Current()->debug();
// If loading fails we just bail out without installing the
// debugger but without tanking the whole context.
- if (!Debug::Load()) return;
+ if (!debug->Load()) return;
// Set the security token for the debugger context to the same as
// the shell global context to allow calling between these (otherwise
// exposing debug global object doesn't make much sense).
- Debug::debug_context()->set_security_token(
+ debug->debug_context()->set_security_token(
global_context->security_token());
Handle<String> debug_string =
- Factory::LookupAsciiSymbol(FLAG_expose_debug_as);
- Handle<Object> global_proxy(Debug::debug_context()->global_proxy());
+ factory->LookupAsciiSymbol(FLAG_expose_debug_as);
+ Handle<Object> global_proxy(debug->debug_context()->global_proxy());
SetLocalPropertyNoThrow(js_global, debug_string, global_proxy, DONT_ENUM);
}
#endif
@@ -1553,6 +1768,10 @@ void Genesis::InstallSpecialObjects(Handle<Context> global_context) {
bool Genesis::InstallExtensions(Handle<Context> global_context,
v8::ExtensionConfiguration* extensions) {
+ // TODO(isolates): Extensions on multiple isolates may take a little more
+ // effort. (The external API reads 'ignore'-- does that mean
+ // we can break the interface?)
+
// Clear coloring of extension list
v8::RegisteredExtension* current = v8::RegisteredExtension::first_extension();
while (current != NULL) {
@@ -1620,17 +1839,18 @@ bool Genesis::InstallExtension(v8::RegisteredExtension* current) {
for (int i = 0; i < extension->dependency_count(); i++) {
if (!InstallExtension(extension->dependencies()[i])) return false;
}
+ Isolate* isolate = Isolate::Current();
Vector<const char> source = CStrVector(extension->source());
- Handle<String> source_code = Factory::NewStringFromAscii(source);
+ Handle<String> source_code = isolate->factory()->NewStringFromAscii(source);
bool result = CompileScriptCached(CStrVector(extension->name()),
source_code,
- &extensions_cache,
+ isolate->bootstrapper()->extensions_cache(),
extension,
- Handle<Context>(Top::context()),
+ Handle<Context>(isolate->context()),
false);
- ASSERT(Top::has_pending_exception() != result);
+ ASSERT(isolate->has_pending_exception() != result);
if (!result) {
- Top::clear_pending_exception();
+ isolate->clear_pending_exception();
}
current->set_state(v8::INSTALLED);
return result;
@@ -1641,7 +1861,7 @@ bool Genesis::InstallJSBuiltins(Handle<JSBuiltinsObject> builtins) {
HandleScope scope;
for (int i = 0; i < Builtins::NumberOfJavaScriptBuiltins(); i++) {
Builtins::JavaScript id = static_cast<Builtins::JavaScript>(i);
- Handle<String> name = Factory::LookupAsciiSymbol(Builtins::GetName(id));
+ Handle<String> name = FACTORY->LookupAsciiSymbol(Builtins::GetName(id));
Object* function_object = builtins->GetPropertyNoExceptionThrown(*name);
Handle<JSFunction> function
= Handle<JSFunction>(JSFunction::cast(function_object));
@@ -1690,12 +1910,13 @@ bool Genesis::ConfigureApiObject(Handle<JSObject> object,
ASSERT(object->IsInstanceOf(
FunctionTemplateInfo::cast(object_template->constructor())));
+ Isolate* isolate = Isolate::Current();
bool pending_exception = false;
Handle<JSObject> obj =
Execution::InstantiateObject(object_template, &pending_exception);
if (pending_exception) {
- ASSERT(Top::has_pending_exception());
- Top::clear_pending_exception();
+ ASSERT(isolate->has_pending_exception());
+ isolate->clear_pending_exception();
return false;
}
TransferObject(obj, object);
@@ -1743,6 +1964,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
break;
}
case MAP_TRANSITION:
+ case EXTERNAL_ARRAY_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
// Ignore non-properties.
@@ -1786,7 +2008,7 @@ void Genesis::TransferIndexedProperties(Handle<JSObject> from,
// Cloning the elements array is sufficient.
Handle<FixedArray> from_elements =
Handle<FixedArray>(FixedArray::cast(from->elements()));
- Handle<FixedArray> to_elements = Factory::CopyFixedArray(from_elements);
+ Handle<FixedArray> to_elements = FACTORY->CopyFixedArray(from_elements);
to->set_elements(*to_elements);
}
@@ -1802,29 +2024,31 @@ void Genesis::TransferObject(Handle<JSObject> from, Handle<JSObject> to) {
// Transfer the prototype (new map is needed).
Handle<Map> old_to_map = Handle<Map>(to->map());
- Handle<Map> new_to_map = Factory::CopyMapDropTransitions(old_to_map);
+ Handle<Map> new_to_map = FACTORY->CopyMapDropTransitions(old_to_map);
new_to_map->set_prototype(from->map()->prototype());
to->set_map(*new_to_map);
}
void Genesis::MakeFunctionInstancePrototypeWritable() {
- // Make a new function map so all future functions
- // will have settable and enumerable prototype properties.
- HandleScope scope;
-
- Handle<DescriptorArray> function_map_descriptors =
- ComputeFunctionInstanceDescriptor(ADD_WRITEABLE_PROTOTYPE);
- Handle<Map> fm = Factory::CopyMapDropDescriptors(Top::function_map());
- fm->set_instance_descriptors(*function_map_descriptors);
- fm->set_function_with_prototype(true);
- Top::context()->global_context()->set_function_map(*fm);
+ // The maps with writable prototype are created in CreateEmptyFunction
+ // and CreateStrictModeFunctionMaps respectively. Initially the maps are
+ // created with read-only prototype for JS builtins processing.
+ ASSERT(!function_instance_map_writable_prototype_.is_null());
+ ASSERT(!strict_mode_function_instance_map_writable_prototype_.is_null());
+
+ // Replace function instance maps to make prototype writable.
+ global_context()->set_function_map(
+ *function_instance_map_writable_prototype_);
+ global_context()->set_strict_mode_function_map(
+ *strict_mode_function_instance_map_writable_prototype_);
}
Genesis::Genesis(Handle<Object> global_object,
v8::Handle<v8::ObjectTemplate> global_template,
v8::ExtensionConfiguration* extensions) {
+ Isolate* isolate = Isolate::Current();
result_ = Handle<Context>::null();
// If V8 isn't running and cannot be initialized, just return.
if (!V8::IsRunning() && !V8::Initialize(NULL)) return;
@@ -1832,18 +2056,15 @@ Genesis::Genesis(Handle<Object> global_object,
// Before creating the roots we must save the context and restore it
// on all function exits.
HandleScope scope;
- SaveContext saved_context;
+ SaveContext saved_context(isolate);
Handle<Context> new_context = Snapshot::NewContextFromSnapshot();
if (!new_context.is_null()) {
global_context_ =
- Handle<Context>::cast(GlobalHandles::Create(*new_context));
+ Handle<Context>::cast(isolate->global_handles()->Create(*new_context));
AddToWeakGlobalContextList(*global_context_);
- Top::set_context(*global_context_);
- i::Counters::contexts_created_by_snapshot.Increment();
- JSFunction* empty_function =
- JSFunction::cast(global_context_->function_map()->prototype());
- empty_function_ = Handle<JSFunction>(empty_function);
+ isolate->set_context(*global_context_);
+ isolate->counters()->contexts_created_by_snapshot()->Increment();
Handle<GlobalObject> inner_global;
Handle<JSGlobalProxy> global_proxy =
CreateNewGlobals(global_template,
@@ -1858,6 +2079,7 @@ Genesis::Genesis(Handle<Object> global_object,
// We get here if there was no context snapshot.
CreateRoots();
Handle<JSFunction> empty_function = CreateEmptyFunction();
+ CreateStrictModeFunctionMaps(empty_function);
Handle<GlobalObject> inner_global;
Handle<JSGlobalProxy> global_proxy =
CreateNewGlobals(global_template, global_object, &inner_global);
@@ -1870,7 +2092,7 @@ Genesis::Genesis(Handle<Object> global_object,
MakeFunctionInstancePrototypeWritable();
if (!ConfigureGlobalObjects(global_template)) return;
- i::Counters::contexts_created_from_scratch.Increment();
+ isolate->counters()->contexts_created_from_scratch()->Increment();
}
result_ = global_context_;
@@ -1881,46 +2103,28 @@ Genesis::Genesis(Handle<Object> global_object,
// Reserve space for statics needing saving and restoring.
int Bootstrapper::ArchiveSpacePerThread() {
- return BootstrapperActive::ArchiveSpacePerThread();
+ return sizeof(NestingCounterType);
}
// Archive statics that are thread local.
char* Bootstrapper::ArchiveState(char* to) {
- return BootstrapperActive::ArchiveState(to);
+ *reinterpret_cast<NestingCounterType*>(to) = nesting_;
+ nesting_ = 0;
+ return to + sizeof(NestingCounterType);
}
// Restore statics that are thread local.
char* Bootstrapper::RestoreState(char* from) {
- return BootstrapperActive::RestoreState(from);
+ nesting_ = *reinterpret_cast<NestingCounterType*>(from);
+ return from + sizeof(NestingCounterType);
}
// Called when the top-level V8 mutex is destroyed.
void Bootstrapper::FreeThreadResources() {
- ASSERT(!BootstrapperActive::IsActive());
-}
-
-
-// Reserve space for statics needing saving and restoring.
-int BootstrapperActive::ArchiveSpacePerThread() {
- return sizeof(nesting_);
-}
-
-
-// Archive statics that are thread local.
-char* BootstrapperActive::ArchiveState(char* to) {
- *reinterpret_cast<int*>(to) = nesting_;
- nesting_ = 0;
- return to + sizeof(nesting_);
-}
-
-
-// Restore statics that are thread local.
-char* BootstrapperActive::RestoreState(char* from) {
- nesting_ = *reinterpret_cast<int*>(from);
- return from + sizeof(nesting_);
+ ASSERT(!IsActive());
}
} } // namespace v8::internal
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index 2b789e28..3e158d66 100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -33,73 +33,140 @@ namespace v8 {
namespace internal {
-class BootstrapperActive BASE_EMBEDDED {
+// A SourceCodeCache uses a FixedArray to store pairs of
+// (AsciiString*, JSFunction*), mapping names of native code files
+// (runtime.js, etc.) to precompiled functions. Instead of mapping
+// names to functions it might make sense to let the JS2C tool
+// generate an index for each native JS file.
+class SourceCodeCache BASE_EMBEDDED {
public:
- BootstrapperActive() { nesting_++; }
- ~BootstrapperActive() { nesting_--; }
+ explicit SourceCodeCache(Script::Type type): type_(type), cache_(NULL) { }
- // Support for thread preemption.
- static int ArchiveSpacePerThread();
- static char* ArchiveState(char* to);
- static char* RestoreState(char* from);
+ void Initialize(bool create_heap_objects) {
+ cache_ = create_heap_objects ? HEAP->empty_fixed_array() : NULL;
+ }
+
+ void Iterate(ObjectVisitor* v) {
+ v->VisitPointer(BitCast<Object**, FixedArray**>(&cache_));
+ }
+
+ bool Lookup(Vector<const char> name, Handle<SharedFunctionInfo>* handle) {
+ for (int i = 0; i < cache_->length(); i+=2) {
+ SeqAsciiString* str = SeqAsciiString::cast(cache_->get(i));
+ if (str->IsEqualTo(name)) {
+ *handle = Handle<SharedFunctionInfo>(
+ SharedFunctionInfo::cast(cache_->get(i + 1)));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void Add(Vector<const char> name, Handle<SharedFunctionInfo> shared) {
+ HandleScope scope;
+ int length = cache_->length();
+ Handle<FixedArray> new_array =
+ FACTORY->NewFixedArray(length + 2, TENURED);
+ cache_->CopyTo(0, *new_array, 0, cache_->length());
+ cache_ = *new_array;
+ Handle<String> str = FACTORY->NewStringFromAscii(name, TENURED);
+ cache_->set(length, *str);
+ cache_->set(length + 1, *shared);
+ Script::cast(shared->script())->set_type(Smi::FromInt(type_));
+ }
private:
- static bool IsActive() { return nesting_ != 0; }
- static int nesting_;
- friend class Bootstrapper;
+ Script::Type type_;
+ FixedArray* cache_;
+ DISALLOW_COPY_AND_ASSIGN(SourceCodeCache);
};
// The Boostrapper is the public interface for creating a JavaScript global
// context.
-class Bootstrapper : public AllStatic {
+class Bootstrapper {
public:
// Requires: Heap::Setup has been called.
- static void Initialize(bool create_heap_objects);
- static void TearDown();
+ void Initialize(bool create_heap_objects);
+ void TearDown();
// Creates a JavaScript Global Context with initial object graph.
// The returned value is a global handle casted to V8Environment*.
- static Handle<Context> CreateEnvironment(
+ Handle<Context> CreateEnvironment(
Handle<Object> global_object,
v8::Handle<v8::ObjectTemplate> global_template,
v8::ExtensionConfiguration* extensions);
// Detach the environment from its outer global object.
- static void DetachGlobal(Handle<Context> env);
+ void DetachGlobal(Handle<Context> env);
// Reattach an outer global object to an environment.
- static void ReattachGlobal(Handle<Context> env, Handle<Object> global_object);
+ void ReattachGlobal(Handle<Context> env, Handle<Object> global_object);
// Traverses the pointers for memory management.
- static void Iterate(ObjectVisitor* v);
+ void Iterate(ObjectVisitor* v);
// Accessor for the native scripts source code.
- static Handle<String> NativesSourceLookup(int index);
+ Handle<String> NativesSourceLookup(int index);
// Tells whether bootstrapping is active.
- static bool IsActive() { return BootstrapperActive::IsActive(); }
+ bool IsActive() const { return nesting_ != 0; }
// Support for thread preemption.
- static int ArchiveSpacePerThread();
- static char* ArchiveState(char* to);
- static char* RestoreState(char* from);
- static void FreeThreadResources();
+ RLYSTC int ArchiveSpacePerThread();
+ char* ArchiveState(char* to);
+ char* RestoreState(char* from);
+ void FreeThreadResources();
// This will allocate a char array that is deleted when V8 is shut down.
// It should only be used for strictly finite allocations.
- static char* AllocateAutoDeletedArray(int bytes);
+ char* AllocateAutoDeletedArray(int bytes);
// Used for new context creation.
- static bool InstallExtensions(Handle<Context> global_context,
- v8::ExtensionConfiguration* extensions);
+ bool InstallExtensions(Handle<Context> global_context,
+ v8::ExtensionConfiguration* extensions);
+
+ SourceCodeCache* extensions_cache() { return &extensions_cache_; }
+
+ private:
+ typedef int NestingCounterType;
+ NestingCounterType nesting_;
+ SourceCodeCache extensions_cache_;
+ // This is for delete, not delete[].
+ List<char*>* delete_these_non_arrays_on_tear_down_;
+ // This is for delete[]
+ List<char*>* delete_these_arrays_on_tear_down_;
+
+ friend class BootstrapperActive;
+ friend class Isolate;
+ friend class NativesExternalStringResource;
+
+ Bootstrapper();
+
+ DISALLOW_COPY_AND_ASSIGN(Bootstrapper);
+};
+
+
+class BootstrapperActive BASE_EMBEDDED {
+ public:
+ BootstrapperActive() {
+ ++Isolate::Current()->bootstrapper()->nesting_;
+ }
+
+ ~BootstrapperActive() {
+ --Isolate::Current()->bootstrapper()->nesting_;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BootstrapperActive);
};
class NativesExternalStringResource
: public v8::String::ExternalAsciiStringResource {
public:
- explicit NativesExternalStringResource(const char* source);
+ explicit NativesExternalStringResource(Bootstrapper* bootstrapper,
+ const char* source);
const char* data() const {
return data_;
diff --git a/src/builtins.cc b/src/builtins.cc
index 01e8deb4..72f9d577 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -107,7 +107,6 @@ BUILTIN_LIST_C(DEF_ARG_TYPE)
} // namespace
-
// ----------------------------------------------------------------------------
// Support macro for defining builtins in C++.
// ----------------------------------------------------------------------------
@@ -123,26 +122,27 @@ BUILTIN_LIST_C(DEF_ARG_TYPE)
#ifdef DEBUG
-#define BUILTIN(name) \
- MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
- name##ArgumentsType args); \
- MUST_USE_RESULT static MaybeObject* Builtin_##name( \
- name##ArgumentsType args) { \
- args.Verify(); \
- return Builtin_Impl_##name(args); \
- } \
- MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
- name##ArgumentsType args)
+#define BUILTIN(name) \
+ MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
+ name##ArgumentsType args, Isolate* isolate); \
+ MUST_USE_RESULT static MaybeObject* Builtin_##name( \
+ name##ArgumentsType args, Isolate* isolate) { \
+ ASSERT(isolate == Isolate::Current()); \
+ args.Verify(); \
+ return Builtin_Impl_##name(args, isolate); \
+ } \
+ MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
+ name##ArgumentsType args, Isolate* isolate)
#else // For release mode.
-#define BUILTIN(name) \
- static MaybeObject* Builtin_##name(name##ArgumentsType args)
+#define BUILTIN(name) \
+ static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
#endif
-static inline bool CalledAsConstructor() {
+static inline bool CalledAsConstructor(Isolate* isolate) {
#ifdef DEBUG
// Calculate the result using a full stack frame iterator and check
// that the state of the stack is as we assume it to be in the
@@ -153,7 +153,7 @@ static inline bool CalledAsConstructor() {
StackFrame* frame = it.frame();
bool reference_result = frame->is_construct();
#endif
- Address fp = Top::c_entry_fp(Top::GetCurrentThread());
+ Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
// Because we know fp points to an exit frame we can use the relevant
// part of ExitFrame::ComputeCallerState directly.
const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
@@ -172,30 +172,30 @@ static inline bool CalledAsConstructor() {
// ----------------------------------------------------------------------------
-
BUILTIN(Illegal) {
UNREACHABLE();
- return Heap::undefined_value(); // Make compiler happy.
+ return isolate->heap()->undefined_value(); // Make compiler happy.
}
BUILTIN(EmptyFunction) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
BUILTIN(ArrayCodeGeneric) {
- Counters::array_function_runtime.Increment();
+ Heap* heap = isolate->heap();
+ isolate->counters()->array_function_runtime()->Increment();
JSArray* array;
- if (CalledAsConstructor()) {
+ if (CalledAsConstructor(isolate)) {
array = JSArray::cast(*args.receiver());
} else {
// Allocate the JS Array
JSFunction* constructor =
- Top::context()->global_context()->array_function();
+ isolate->context()->global_context()->array_function();
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateJSObject(constructor);
+ { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
array = JSArray::cast(obj);
@@ -212,7 +212,7 @@ BUILTIN(ArrayCodeGeneric) {
int len = Smi::cast(obj)->value();
if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(len);
+ { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
array->SetContent(FixedArray::cast(obj));
@@ -235,7 +235,7 @@ BUILTIN(ArrayCodeGeneric) {
int number_of_elements = args.length() - 1;
Smi* len = Smi::FromInt(number_of_elements);
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(len->value());
+ { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len->value());
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
@@ -255,77 +255,81 @@ BUILTIN(ArrayCodeGeneric) {
}
-MUST_USE_RESULT static MaybeObject* AllocateJSArray() {
+MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) {
JSFunction* array_function =
- Top::context()->global_context()->array_function();
+ heap->isolate()->context()->global_context()->array_function();
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateJSObject(array_function);
+ { MaybeObject* maybe_result = heap->AllocateJSObject(array_function);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
return result;
}
-MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray() {
+MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray(Heap* heap) {
Object* result;
- { MaybeObject* maybe_result = AllocateJSArray();
+ { MaybeObject* maybe_result = AllocateJSArray(heap);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
JSArray* result_array = JSArray::cast(result);
result_array->set_length(Smi::FromInt(0));
- result_array->set_elements(Heap::empty_fixed_array());
+ result_array->set_elements(heap->empty_fixed_array());
return result_array;
}
-static void CopyElements(AssertNoAllocation* no_gc,
+static void CopyElements(Heap* heap,
+ AssertNoAllocation* no_gc,
FixedArray* dst,
int dst_index,
FixedArray* src,
int src_index,
int len) {
ASSERT(dst != src); // Use MoveElements instead.
- ASSERT(dst->map() != Heap::fixed_cow_array_map());
+ ASSERT(dst->map() != HEAP->fixed_cow_array_map());
ASSERT(len > 0);
CopyWords(dst->data_start() + dst_index,
src->data_start() + src_index,
len);
WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
if (mode == UPDATE_WRITE_BARRIER) {
- Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
+ heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
}
}
-static void MoveElements(AssertNoAllocation* no_gc,
+static void MoveElements(Heap* heap,
+ AssertNoAllocation* no_gc,
FixedArray* dst,
int dst_index,
FixedArray* src,
int src_index,
int len) {
- ASSERT(dst->map() != Heap::fixed_cow_array_map());
+ ASSERT(dst->map() != HEAP->fixed_cow_array_map());
memmove(dst->data_start() + dst_index,
src->data_start() + src_index,
len * kPointerSize);
WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
if (mode == UPDATE_WRITE_BARRIER) {
- Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
+ heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
}
}
-static void FillWithHoles(FixedArray* dst, int from, int to) {
- ASSERT(dst->map() != Heap::fixed_cow_array_map());
- MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
+static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
+ ASSERT(dst->map() != heap->fixed_cow_array_map());
+ MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
}
-static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
- ASSERT(elms->map() != Heap::fixed_cow_array_map());
+static FixedArray* LeftTrimFixedArray(Heap* heap,
+ FixedArray* elms,
+ int to_trim) {
+ ASSERT(elms->map() != HEAP->fixed_cow_array_map());
// For now this trick is only applied to fixed arrays in new and paged space.
// In large object space the object's start must coincide with chunk
// and thus the trick is just not applicable.
- ASSERT(!Heap::lo_space()->Contains(elms));
+ ASSERT(!HEAP->lo_space()->Contains(elms));
STATIC_ASSERT(FixedArray::kMapOffset == 0);
STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
@@ -336,7 +340,7 @@ static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
const int len = elms->length();
if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
- !Heap::new_space()->Contains(elms)) {
+ !heap->new_space()->Contains(elms)) {
// If we are doing a big trim in old space then we zap the space that was
// formerly part of the array so that the GC (aided by the card-based
// remembered set) won't find pointers to new-space there.
@@ -349,9 +353,9 @@ static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
// Technically in new space this write might be omitted (except for
// debug mode which iterates through the heap), but to play safer
// we still do it.
- Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
+ heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
- former_start[to_trim] = Heap::fixed_array_map();
+ former_start[to_trim] = heap->fixed_array_map();
former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
return FixedArray::cast(HeapObject::FromAddress(
@@ -359,20 +363,21 @@ static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
}
-static bool ArrayPrototypeHasNoElements(Context* global_context,
+static bool ArrayPrototypeHasNoElements(Heap* heap,
+ Context* global_context,
JSObject* array_proto) {
// This method depends on non writability of Object and Array prototype
// fields.
- if (array_proto->elements() != Heap::empty_fixed_array()) return false;
+ if (array_proto->elements() != heap->empty_fixed_array()) return false;
// Hidden prototype
array_proto = JSObject::cast(array_proto->GetPrototype());
- ASSERT(array_proto->elements() == Heap::empty_fixed_array());
+ ASSERT(array_proto->elements() == heap->empty_fixed_array());
// Object.prototype
Object* proto = array_proto->GetPrototype();
- if (proto == Heap::null_value()) return false;
+ if (proto == heap->null_value()) return false;
array_proto = JSObject::cast(proto);
if (array_proto != global_context->initial_object_prototype()) return false;
- if (array_proto->elements() != Heap::empty_fixed_array()) return false;
+ if (array_proto->elements() != heap->empty_fixed_array()) return false;
ASSERT(array_proto->GetPrototype()->IsNull());
return true;
}
@@ -380,35 +385,38 @@ static bool ArrayPrototypeHasNoElements(Context* global_context,
MUST_USE_RESULT
static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
- Object* receiver) {
+ Heap* heap, Object* receiver) {
if (!receiver->IsJSArray()) return NULL;
JSArray* array = JSArray::cast(receiver);
HeapObject* elms = array->elements();
- if (elms->map() == Heap::fixed_array_map()) return elms;
- if (elms->map() == Heap::fixed_cow_array_map()) {
+ if (elms->map() == heap->fixed_array_map()) return elms;
+ if (elms->map() == heap->fixed_cow_array_map()) {
return array->EnsureWritableFastElements();
}
return NULL;
}
-static inline bool IsJSArrayFastElementMovingAllowed(JSArray* receiver) {
- Context* global_context = Top::context()->global_context();
+static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
+ JSArray* receiver) {
+ Context* global_context = heap->isolate()->context()->global_context();
JSObject* array_proto =
JSObject::cast(global_context->array_function()->prototype());
return receiver->GetPrototype() == array_proto &&
- ArrayPrototypeHasNoElements(global_context, array_proto);
+ ArrayPrototypeHasNoElements(heap, global_context, array_proto);
}
MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
+ Isolate* isolate,
const char* name,
BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
- HandleScope handleScope;
+ HandleScope handleScope(isolate);
Handle<Object> js_builtin =
- GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
- name);
+ GetProperty(Handle<JSObject>(
+ isolate->global_context()->builtins()),
+ name);
ASSERT(js_builtin->IsJSFunction());
Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
ScopedVector<Object**> argv(args.length() - 1);
@@ -428,11 +436,14 @@ MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
BUILTIN(ArrayPush) {
+ Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(receiver);
- if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayPush", args);
+ EnsureJSArrayWithWritableFastElements(heap, receiver);
+ if (maybe_elms_obj == NULL) {
+ return CallJsBuiltin(isolate, "ArrayPush", args);
+ }
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
}
FixedArray* elms = FixedArray::cast(elms_obj);
@@ -453,16 +464,16 @@ BUILTIN(ArrayPush) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(capacity);
+ { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* new_elms = FixedArray::cast(obj);
AssertNoAllocation no_gc;
if (len > 0) {
- CopyElements(&no_gc, new_elms, 0, elms, 0, len);
+ CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len);
}
- FillWithHoles(new_elms, new_length, capacity);
+ FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
@@ -482,18 +493,19 @@ BUILTIN(ArrayPush) {
BUILTIN(ArrayPop) {
+ Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(receiver);
- if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayPop", args);
+ EnsureJSArrayWithWritableFastElements(heap, receiver);
+ if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
int len = Smi::cast(array->length())->value();
- if (len == 0) return Heap::undefined_value();
+ if (len == 0) return heap->undefined_value();
// Get top element
MaybeObject* top = elms->get(len - 1);
@@ -514,38 +526,40 @@ BUILTIN(ArrayPop) {
BUILTIN(ArrayShift) {
+ Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(receiver);
- if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayShift", args);
+ EnsureJSArrayWithWritableFastElements(heap, receiver);
+ if (maybe_elms_obj == NULL)
+ return CallJsBuiltin(isolate, "ArrayShift", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
}
- if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
- return CallJsBuiltin("ArrayShift", args);
+ if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
+ return CallJsBuiltin(isolate, "ArrayShift", args);
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastElements());
int len = Smi::cast(array->length())->value();
- if (len == 0) return Heap::undefined_value();
+ if (len == 0) return heap->undefined_value();
// Get first element
Object* first = elms->get(0);
if (first->IsTheHole()) {
- first = Heap::undefined_value();
+ first = heap->undefined_value();
}
- if (!Heap::lo_space()->Contains(elms)) {
+ if (!heap->lo_space()->Contains(elms)) {
// As elms still in the same space they used to be,
// there is no need to update region dirty mark.
- array->set_elements(LeftTrimFixedArray(elms, 1), SKIP_WRITE_BARRIER);
+ array->set_elements(LeftTrimFixedArray(heap, elms, 1), SKIP_WRITE_BARRIER);
} else {
// Shift the elements.
AssertNoAllocation no_gc;
- MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
- elms->set(len - 1, Heap::the_hole_value());
+ MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
+ elms->set(len - 1, heap->the_hole_value());
}
// Set the length.
@@ -556,15 +570,17 @@ BUILTIN(ArrayShift) {
BUILTIN(ArrayUnshift) {
+ Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(receiver);
- if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayUnshift", args);
+ EnsureJSArrayWithWritableFastElements(heap, receiver);
+ if (maybe_elms_obj == NULL)
+ return CallJsBuiltin(isolate, "ArrayUnshift", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
}
- if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
- return CallJsBuiltin("ArrayUnshift", args);
+ if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
+ return CallJsBuiltin(isolate, "ArrayUnshift", args);
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
@@ -581,22 +597,22 @@ BUILTIN(ArrayUnshift) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(capacity);
+ { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* new_elms = FixedArray::cast(obj);
AssertNoAllocation no_gc;
if (len > 0) {
- CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
+ CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len);
}
- FillWithHoles(new_elms, new_length, capacity);
+ FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
} else {
AssertNoAllocation no_gc;
- MoveElements(&no_gc, elms, to_add, elms, 0, len);
+ MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
}
// Add the provided values.
@@ -613,14 +629,15 @@ BUILTIN(ArrayUnshift) {
BUILTIN(ArraySlice) {
+ Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
FixedArray* elms;
int len = -1;
if (receiver->IsJSArray()) {
JSArray* array = JSArray::cast(receiver);
if (!array->HasFastElements() ||
- !IsJSArrayFastElementMovingAllowed(array)) {
- return CallJsBuiltin("ArraySlice", args);
+ !IsJSArrayFastElementMovingAllowed(heap, array)) {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
}
elms = FixedArray::cast(array->elements());
@@ -629,28 +646,28 @@ BUILTIN(ArraySlice) {
// Array.slice(arguments, ...) is quite a common idiom (notably more
// than 50% of invocations in Web apps). Treat it in C++ as well.
Map* arguments_map =
- Top::context()->global_context()->arguments_boilerplate()->map();
+ isolate->context()->global_context()->arguments_boilerplate()->map();
bool is_arguments_object_with_fast_elements =
receiver->IsJSObject()
&& JSObject::cast(receiver)->map() == arguments_map
&& JSObject::cast(receiver)->HasFastElements();
if (!is_arguments_object_with_fast_elements) {
- return CallJsBuiltin("ArraySlice", args);
+ return CallJsBuiltin(isolate, "ArraySlice", args);
}
elms = FixedArray::cast(JSObject::cast(receiver)->elements());
Object* len_obj = JSObject::cast(receiver)
- ->InObjectPropertyAt(Heap::arguments_length_index);
+ ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
if (!len_obj->IsSmi()) {
- return CallJsBuiltin("ArraySlice", args);
+ return CallJsBuiltin(isolate, "ArraySlice", args);
}
len = Smi::cast(len_obj)->value();
if (len > elms->length()) {
- return CallJsBuiltin("ArraySlice", args);
+ return CallJsBuiltin(isolate, "ArraySlice", args);
}
for (int i = 0; i < len; i++) {
- if (elms->get(i) == Heap::the_hole_value()) {
- return CallJsBuiltin("ArraySlice", args);
+ if (elms->get(i) == heap->the_hole_value()) {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
}
}
}
@@ -667,14 +684,14 @@ BUILTIN(ArraySlice) {
if (arg1->IsSmi()) {
relative_start = Smi::cast(arg1)->value();
} else if (!arg1->IsUndefined()) {
- return CallJsBuiltin("ArraySlice", args);
+ return CallJsBuiltin(isolate, "ArraySlice", args);
}
if (n_arguments > 1) {
Object* arg2 = args[2];
if (arg2->IsSmi()) {
relative_end = Smi::cast(arg2)->value();
} else if (!arg2->IsUndefined()) {
- return CallJsBuiltin("ArraySlice", args);
+ return CallJsBuiltin(isolate, "ArraySlice", args);
}
}
}
@@ -690,23 +707,23 @@ BUILTIN(ArraySlice) {
// Calculate the length of result array.
int result_len = final - k;
if (result_len <= 0) {
- return AllocateEmptyJSArray();
+ return AllocateEmptyJSArray(heap);
}
Object* result;
- { MaybeObject* maybe_result = AllocateJSArray();
+ { MaybeObject* maybe_result = AllocateJSArray(heap);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
JSArray* result_array = JSArray::cast(result);
{ MaybeObject* maybe_result =
- Heap::AllocateUninitializedFixedArray(result_len);
+ heap->AllocateUninitializedFixedArray(result_len);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
FixedArray* result_elms = FixedArray::cast(result);
AssertNoAllocation no_gc;
- CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
+ CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len);
// Set elements.
result_array->set_elements(result_elms);
@@ -718,15 +735,17 @@ BUILTIN(ArraySlice) {
BUILTIN(ArraySplice) {
+ Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(receiver);
- if (maybe_elms_obj == NULL) return CallJsBuiltin("ArraySplice", args);
+ EnsureJSArrayWithWritableFastElements(heap, receiver);
+ if (maybe_elms_obj == NULL)
+ return CallJsBuiltin(isolate, "ArraySplice", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
}
- if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
- return CallJsBuiltin("ArraySplice", args);
+ if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
+ return CallJsBuiltin(isolate, "ArraySplice", args);
}
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
@@ -742,7 +761,7 @@ BUILTIN(ArraySplice) {
if (arg1->IsSmi()) {
relative_start = Smi::cast(arg1)->value();
} else if (!arg1->IsUndefined()) {
- return CallJsBuiltin("ArraySplice", args);
+ return CallJsBuiltin(isolate, "ArraySplice", args);
}
}
int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
@@ -764,7 +783,7 @@ BUILTIN(ArraySplice) {
if (arg2->IsSmi()) {
value = Smi::cast(arg2)->value();
} else {
- return CallJsBuiltin("ArraySplice", args);
+ return CallJsBuiltin(isolate, "ArraySplice", args);
}
}
actual_delete_count = Min(Max(value, 0), len - actual_start);
@@ -773,27 +792,28 @@ BUILTIN(ArraySplice) {
JSArray* result_array = NULL;
if (actual_delete_count == 0) {
Object* result;
- { MaybeObject* maybe_result = AllocateEmptyJSArray();
+ { MaybeObject* maybe_result = AllocateEmptyJSArray(heap);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
result_array = JSArray::cast(result);
} else {
// Allocate result array.
Object* result;
- { MaybeObject* maybe_result = AllocateJSArray();
+ { MaybeObject* maybe_result = AllocateJSArray(heap);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
result_array = JSArray::cast(result);
{ MaybeObject* maybe_result =
- Heap::AllocateUninitializedFixedArray(actual_delete_count);
+ heap->AllocateUninitializedFixedArray(actual_delete_count);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
FixedArray* result_elms = FixedArray::cast(result);
AssertNoAllocation no_gc;
// Fill newly created array.
- CopyElements(&no_gc,
+ CopyElements(heap,
+ &no_gc,
result_elms, 0,
elms, actual_start,
actual_delete_count);
@@ -811,7 +831,7 @@ BUILTIN(ArraySplice) {
if (item_count < actual_delete_count) {
// Shrink the array.
- const bool trim_array = !Heap::lo_space()->Contains(elms) &&
+ const bool trim_array = !heap->lo_space()->Contains(elms) &&
((actual_start + item_count) <
(len - actual_delete_count - actual_start));
if (trim_array) {
@@ -822,15 +842,15 @@ BUILTIN(ArraySplice) {
memmove(start + delta, start, actual_start * kPointerSize);
}
- elms = LeftTrimFixedArray(elms, delta);
+ elms = LeftTrimFixedArray(heap, elms, delta);
array->set_elements(elms, SKIP_WRITE_BARRIER);
} else {
AssertNoAllocation no_gc;
- MoveElements(&no_gc,
+ MoveElements(heap, &no_gc,
elms, actual_start + item_count,
elms, actual_start + actual_delete_count,
(len - actual_delete_count - actual_start));
- FillWithHoles(elms, new_length, len);
+ FillWithHoles(heap, elms, new_length, len);
}
} else if (item_count > actual_delete_count) {
// Currently fixed arrays cannot grow too big, so
@@ -843,7 +863,7 @@ BUILTIN(ArraySplice) {
int capacity = new_length + (new_length >> 1) + 16;
Object* obj;
{ MaybeObject* maybe_obj =
- Heap::AllocateUninitializedFixedArray(capacity);
+ heap->AllocateUninitializedFixedArray(capacity);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* new_elms = FixedArray::cast(obj);
@@ -851,22 +871,22 @@ BUILTIN(ArraySplice) {
AssertNoAllocation no_gc;
// Copy the part before actual_start as is.
if (actual_start > 0) {
- CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start);
+ CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start);
}
const int to_copy = len - actual_delete_count - actual_start;
if (to_copy > 0) {
- CopyElements(&no_gc,
+ CopyElements(heap, &no_gc,
new_elms, actual_start + item_count,
elms, actual_start + actual_delete_count,
to_copy);
}
- FillWithHoles(new_elms, new_length, capacity);
+ FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
} else {
AssertNoAllocation no_gc;
- MoveElements(&no_gc,
+ MoveElements(heap, &no_gc,
elms, actual_start + item_count,
elms, actual_start + actual_delete_count,
(len - actual_delete_count - actual_start));
@@ -887,11 +907,12 @@ BUILTIN(ArraySplice) {
BUILTIN(ArrayConcat) {
- Context* global_context = Top::context()->global_context();
+ Heap* heap = isolate->heap();
+ Context* global_context = isolate->context()->global_context();
JSObject* array_proto =
JSObject::cast(global_context->array_function()->prototype());
- if (!ArrayPrototypeHasNoElements(global_context, array_proto)) {
- return CallJsBuiltin("ArrayConcat", args);
+ if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) {
+ return CallJsBuiltin(isolate, "ArrayConcat", args);
}
// Iterate through all the arguments performing checks
@@ -902,7 +923,7 @@ BUILTIN(ArrayConcat) {
Object* arg = args[i];
if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
|| JSArray::cast(arg)->GetPrototype() != array_proto) {
- return CallJsBuiltin("ArrayConcat", args);
+ return CallJsBuiltin(isolate, "ArrayConcat", args);
}
int len = Smi::cast(JSArray::cast(arg)->length())->value();
@@ -915,23 +936,23 @@ BUILTIN(ArrayConcat) {
ASSERT(result_len >= 0);
if (result_len > FixedArray::kMaxLength) {
- return CallJsBuiltin("ArrayConcat", args);
+ return CallJsBuiltin(isolate, "ArrayConcat", args);
}
}
if (result_len == 0) {
- return AllocateEmptyJSArray();
+ return AllocateEmptyJSArray(heap);
}
// Allocate result.
Object* result;
- { MaybeObject* maybe_result = AllocateJSArray();
+ { MaybeObject* maybe_result = AllocateJSArray(heap);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
JSArray* result_array = JSArray::cast(result);
{ MaybeObject* maybe_result =
- Heap::AllocateUninitializedFixedArray(result_len);
+ heap->AllocateUninitializedFixedArray(result_len);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
FixedArray* result_elms = FixedArray::cast(result);
@@ -944,7 +965,7 @@ BUILTIN(ArrayConcat) {
int len = Smi::cast(array->length())->value();
if (len > 0) {
FixedArray* elms = FixedArray::cast(array->elements());
- CopyElements(&no_gc, result_elms, start_pos, elms, 0, len);
+ CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len);
start_pos += len;
}
}
@@ -959,6 +980,38 @@ BUILTIN(ArrayConcat) {
// -----------------------------------------------------------------------------
+// Strict mode poison pills
+
+
+BUILTIN(StrictArgumentsCallee) {
+ HandleScope scope;
+ return isolate->Throw(*isolate->factory()->NewTypeError(
+ "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
+}
+
+
+BUILTIN(StrictArgumentsCaller) {
+ HandleScope scope;
+ return isolate->Throw(*isolate->factory()->NewTypeError(
+ "strict_arguments_caller", HandleVector<Object>(NULL, 0)));
+}
+
+
+BUILTIN(StrictFunctionCaller) {
+ HandleScope scope;
+ return isolate->Throw(*isolate->factory()->NewTypeError(
+ "strict_function_caller", HandleVector<Object>(NULL, 0)));
+}
+
+
+BUILTIN(StrictFunctionArguments) {
+ HandleScope scope;
+ return isolate->Throw(*isolate->factory()->NewTypeError(
+ "strict_function_arguments", HandleVector<Object>(NULL, 0)));
+}
+
+
+// -----------------------------------------------------------------------------
//
@@ -968,7 +1021,8 @@ BUILTIN(ArrayConcat) {
// overwritten with undefined. Arguments that do fit the expected
// type is overwritten with the object in the prototype chain that
// actually has that type.
-static inline Object* TypeCheck(int argc,
+static inline Object* TypeCheck(Heap* heap,
+ int argc,
Object** argv,
FunctionTemplateInfo* info) {
Object* recv = argv[0];
@@ -980,12 +1034,12 @@ static inline Object* TypeCheck(int argc,
Object* holder = recv;
if (!recv_type->IsUndefined()) {
- for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
+ for (; holder != heap->null_value(); holder = holder->GetPrototype()) {
if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
break;
}
}
- if (holder == Heap::null_value()) return holder;
+ if (holder == heap->null_value()) return holder;
}
Object* args_obj = sig->args();
// If there is no argument signature we're done
@@ -998,13 +1052,13 @@ static inline Object* TypeCheck(int argc,
if (argtype->IsUndefined()) continue;
Object** arg = &argv[-1 - i];
Object* current = *arg;
- for (; current != Heap::null_value(); current = current->GetPrototype()) {
+ for (; current != heap->null_value(); current = current->GetPrototype()) {
if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
*arg = current;
break;
}
}
- if (current == Heap::null_value()) *arg = Heap::undefined_value();
+ if (current == heap->null_value()) *arg = heap->undefined_value();
}
return holder;
}
@@ -1012,31 +1066,33 @@ static inline Object* TypeCheck(int argc,
template <bool is_construct>
MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
- BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
- ASSERT(is_construct == CalledAsConstructor());
+ BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
+ ASSERT(is_construct == CalledAsConstructor(isolate));
+ Heap* heap = isolate->heap();
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<JSFunction> function = args.called_function();
ASSERT(function->shared()->IsApiFunction());
FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
if (is_construct) {
- Handle<FunctionTemplateInfo> desc(fun_data);
+ Handle<FunctionTemplateInfo> desc(fun_data, isolate);
bool pending_exception = false;
- Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
- &pending_exception);
- ASSERT(Top::has_pending_exception() == pending_exception);
+ isolate->factory()->ConfigureInstance(
+ desc, Handle<JSObject>::cast(args.receiver()), &pending_exception);
+ ASSERT(isolate->has_pending_exception() == pending_exception);
if (pending_exception) return Failure::Exception();
fun_data = *desc;
}
- Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
+ Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
if (raw_holder->IsNull()) {
// This function cannot be called with the given receiver. Abort!
Handle<Object> obj =
- Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
- return Top::Throw(*obj);
+ isolate->factory()->NewTypeError(
+ "illegal_invocation", HandleVector(&function, 1));
+ return isolate->Throw(*obj);
}
Object* raw_call_data = fun_data->call_code();
@@ -1048,10 +1104,10 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
Object* data_obj = call_data->data();
Object* result;
- LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
+ LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
ASSERT(raw_holder->IsJSObject());
- CustomArguments custom;
+ CustomArguments custom(isolate);
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
data_obj, *function, raw_holder);
@@ -1064,17 +1120,18 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
- ExternalCallbackScope call_scope(v8::ToCData<Address>(callback_obj));
+ VMState state(isolate, EXTERNAL);
+ ExternalCallbackScope call_scope(isolate,
+ v8::ToCData<Address>(callback_obj));
value = callback(new_args);
}
if (value.IsEmpty()) {
- result = Heap::undefined_value();
+ result = heap->undefined_value();
} else {
result = *reinterpret_cast<Object**>(*value);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!is_construct || result->IsJSObject()) return result;
}
@@ -1083,12 +1140,12 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
BUILTIN(HandleApiCall) {
- return HandleApiCallHelper<false>(args);
+ return HandleApiCallHelper<false>(args, isolate);
}
BUILTIN(HandleApiCallConstruct) {
- return HandleApiCallHelper<true>(args);
+ return HandleApiCallHelper<true>(args, isolate);
}
@@ -1110,7 +1167,8 @@ static void VerifyTypeCheck(Handle<JSObject> object,
BUILTIN(FastHandleApiCall) {
- ASSERT(!CalledAsConstructor());
+ ASSERT(!CalledAsConstructor(isolate));
+ Heap* heap = isolate->heap();
const bool is_construct = false;
// We expect four more arguments: callback, function, call data, and holder.
@@ -1129,25 +1187,26 @@ BUILTIN(FastHandleApiCall) {
VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()),
Utils::OpenHandle(*new_args.Callee()));
#endif
- HandleScope scope;
+ HandleScope scope(isolate);
Object* result;
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
- ExternalCallbackScope call_scope(v8::ToCData<Address>(callback_obj));
+ VMState state(isolate, EXTERNAL);
+ ExternalCallbackScope call_scope(isolate,
+ v8::ToCData<Address>(callback_obj));
v8::InvocationCallback callback =
v8::ToCData<v8::InvocationCallback>(callback_obj);
value = callback(new_args);
}
if (value.IsEmpty()) {
- result = Heap::undefined_value();
+ result = heap->undefined_value();
} else {
result = *reinterpret_cast<Object**>(*value);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return result;
}
@@ -1156,11 +1215,13 @@ BUILTIN(FastHandleApiCall) {
// API. The object can be called as either a constructor (using new) or just as
// a function (without new).
MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
+ Isolate* isolate,
bool is_construct_call,
BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
// Non-functions are never called as constructors. Even if this is an object
// called as a constructor the delegate call is not a construct call.
- ASSERT(!CalledAsConstructor());
+ ASSERT(!CalledAsConstructor(isolate));
+ Heap* heap = isolate->heap();
Handle<Object> receiver = args.at<Object>(0);
@@ -1183,11 +1244,10 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
// Get the data for the call and perform the callback.
Object* result;
{
- HandleScope scope;
+ HandleScope scope(isolate);
+ LOG(isolate, ApiObjectAccess("call non-function", obj));
- LOG(ApiObjectAccess("call non-function", obj));
-
- CustomArguments custom;
+ CustomArguments custom(isolate);
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
call_data->data(), constructor, obj);
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
@@ -1198,18 +1258,19 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
- ExternalCallbackScope call_scope(v8::ToCData<Address>(callback_obj));
+ VMState state(isolate, EXTERNAL);
+ ExternalCallbackScope call_scope(isolate,
+ v8::ToCData<Address>(callback_obj));
value = callback(new_args);
}
if (value.IsEmpty()) {
- result = Heap::undefined_value();
+ result = heap->undefined_value();
} else {
result = *reinterpret_cast<Object**>(*value);
}
}
// Check for exceptions and return result.
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return result;
}
@@ -1217,14 +1278,14 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a normal function call.
BUILTIN(HandleApiCallAsFunction) {
- return HandleApiCallAsFunctionOrConstructor(false, args);
+ return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
}
// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a construct call.
BUILTIN(HandleApiCallAsConstructor) {
- return HandleApiCallAsFunctionOrConstructor(true, args);
+ return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
}
@@ -1433,73 +1494,112 @@ static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
}
#endif
-Object* Builtins::builtins_[builtin_count] = { NULL, };
-const char* Builtins::names_[builtin_count] = { NULL, };
+
+Builtins::Builtins() : initialized_(false) {
+ memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
+ memset(names_, 0, sizeof(names_[0]) * builtin_count);
+}
+
+
+Builtins::~Builtins() {
+}
+
#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
- Address Builtins::c_functions_[cfunction_count] = {
- BUILTIN_LIST_C(DEF_ENUM_C)
- };
+Address const Builtins::c_functions_[cfunction_count] = {
+ BUILTIN_LIST_C(DEF_ENUM_C)
+};
#undef DEF_ENUM_C
#define DEF_JS_NAME(name, ignore) #name,
#define DEF_JS_ARGC(ignore, argc) argc,
-const char* Builtins::javascript_names_[id_count] = {
+const char* const Builtins::javascript_names_[id_count] = {
BUILTINS_LIST_JS(DEF_JS_NAME)
};
-int Builtins::javascript_argc_[id_count] = {
+int const Builtins::javascript_argc_[id_count] = {
BUILTINS_LIST_JS(DEF_JS_ARGC)
};
#undef DEF_JS_NAME
#undef DEF_JS_ARGC
-static bool is_initialized = false;
-void Builtins::Setup(bool create_heap_objects) {
- ASSERT(!is_initialized);
+struct BuiltinDesc {
+ byte* generator;
+ byte* c_code;
+ const char* s_name; // name is only used for generating log information.
+ int name;
+ Code::Flags flags;
+ BuiltinExtraArguments extra_args;
+};
- // Create a scope for the handles in the builtins.
- HandleScope scope;
+class BuiltinFunctionTable {
+ public:
+ BuiltinFunctionTable() {
+ Builtins::InitBuiltinFunctionTable();
+ }
+
+ static const BuiltinDesc* functions() { return functions_; }
+
+ private:
+ static BuiltinDesc functions_[Builtins::builtin_count + 1];
- struct BuiltinDesc {
- byte* generator;
- byte* c_code;
- const char* s_name; // name is only used for generating log information.
- int name;
- Code::Flags flags;
- BuiltinExtraArguments extra_args;
- };
-
-#define DEF_FUNCTION_PTR_C(name, extra_args) \
- { FUNCTION_ADDR(Generate_Adaptor), \
- FUNCTION_ADDR(Builtin_##name), \
- #name, \
- c_##name, \
- Code::ComputeFlags(Code::BUILTIN), \
- extra_args \
- },
-
-#define DEF_FUNCTION_PTR_A(name, kind, state, extra) \
- { FUNCTION_ADDR(Generate_##name), \
- NULL, \
- #name, \
- name, \
- Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state, extra), \
- NO_EXTRA_ARGUMENTS \
- },
-
- // Define array of pointers to generators and C builtin functions.
- static BuiltinDesc functions[] = {
- BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
- BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
- BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
- // Terminator:
- { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
- NO_EXTRA_ARGUMENTS }
- };
+ friend class Builtins;
+};
+
+BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1];
+
+static const BuiltinFunctionTable builtin_function_table_init;
+
+// Define array of pointers to generators and C builtin functions.
+// We do this in a sort of roundabout way so that we can do the initialization
+// within the lexical scope of Builtins:: and within a context where
+// Code::Flags names a non-abstract type.
+void Builtins::InitBuiltinFunctionTable() {
+ BuiltinDesc* functions = BuiltinFunctionTable::functions_;
+ functions[builtin_count].generator = NULL;
+ functions[builtin_count].c_code = NULL;
+ functions[builtin_count].s_name = NULL;
+ functions[builtin_count].name = builtin_count;
+ functions[builtin_count].flags = static_cast<Code::Flags>(0);
+ functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
+
+#define DEF_FUNCTION_PTR_C(aname, aextra_args) \
+ functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
+ functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
+ functions->s_name = #aname; \
+ functions->name = c_##aname; \
+ functions->flags = Code::ComputeFlags(Code::BUILTIN); \
+ functions->extra_args = aextra_args; \
+ ++functions;
+
+#define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
+ functions->generator = FUNCTION_ADDR(Generate_##aname); \
+ functions->c_code = NULL; \
+ functions->s_name = #aname; \
+ functions->name = k##aname; \
+ functions->flags = Code::ComputeFlags(Code::kind, \
+ NOT_IN_LOOP, \
+ state, \
+ extra); \
+ functions->extra_args = NO_EXTRA_ARGUMENTS; \
+ ++functions;
+
+ BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
+ BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
+ BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
#undef DEF_FUNCTION_PTR_C
#undef DEF_FUNCTION_PTR_A
+}
+
+void Builtins::Setup(bool create_heap_objects) {
+ ASSERT(!initialized_);
+ Heap* heap = Isolate::Current()->heap();
+
+ // Create a scope for the handles in the builtins.
+ HandleScope scope;
+
+ const BuiltinDesc* functions = BuiltinFunctionTable::functions();
// For now we generate builtin adaptor code into a stack-allocated
// buffer, before copying it into individual code objects.
@@ -1527,14 +1627,15 @@ void Builtins::Setup(bool create_heap_objects) {
// This simplifies things because we don't need to retry.
AlwaysAllocateScope __scope__;
{ MaybeObject* maybe_code =
- Heap::CreateCode(desc, flags, masm.CodeObject());
+ heap->CreateCode(desc, flags, masm.CodeObject());
if (!maybe_code->ToObject(&code)) {
v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
}
}
}
// Log the event and add the code to the builtins array.
- PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
+ PROFILE(ISOLATE,
+ CodeCreateEvent(Logger::BUILTIN_TAG,
Code::cast(code),
functions[i].s_name));
GDBJIT(AddCode(GDBJITInterface::BUILTIN,
@@ -1556,12 +1657,12 @@ void Builtins::Setup(bool create_heap_objects) {
}
// Mark as initialized.
- is_initialized = true;
+ initialized_ = true;
}
void Builtins::TearDown() {
- is_initialized = false;
+ initialized_ = false;
}
@@ -1571,7 +1672,8 @@ void Builtins::IterateBuiltins(ObjectVisitor* v) {
const char* Builtins::Lookup(byte* pc) {
- if (is_initialized) { // may be called during initialization (disassembler!)
+ // may be called during initialization (disassembler!)
+ if (initialized_) {
for (int i = 0; i < builtin_count; i++) {
Code* entry = Code::cast(builtins_[i]);
if (entry->contains(pc)) {
@@ -1583,4 +1685,23 @@ const char* Builtins::Lookup(byte* pc) {
}
+#define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
+Handle<Code> Builtins::name() { \
+ Code** code_address = \
+ reinterpret_cast<Code**>(builtin_address(k##name)); \
+ return Handle<Code>(code_address); \
+}
+#define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
+Handle<Code> Builtins::name() { \
+ Code** code_address = \
+ reinterpret_cast<Code**>(builtin_address(k##name)); \
+ return Handle<Code>(code_address); \
+}
+BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
+BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
+BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
+#undef DEFINE_BUILTIN_ACCESSOR_C
+#undef DEFINE_BUILTIN_ACCESSOR_A
+
+
} } // namespace v8::internal
diff --git a/src/builtins.h b/src/builtins.h
index 5ea46651..bc0facb4 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -58,7 +58,12 @@ enum BuiltinExtraArguments {
V(FastHandleApiCall, NO_EXTRA_ARGUMENTS) \
V(HandleApiCallConstruct, NEEDS_CALLED_FUNCTION) \
V(HandleApiCallAsFunction, NO_EXTRA_ARGUMENTS) \
- V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS)
+ V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS) \
+ \
+ V(StrictArgumentsCallee, NO_EXTRA_ARGUMENTS) \
+ V(StrictArgumentsCaller, NO_EXTRA_ARGUMENTS) \
+ V(StrictFunctionCaller, NO_EXTRA_ARGUMENTS) \
+ V(StrictFunctionArguments, NO_EXTRA_ARGUMENTS)
// Define list of builtins implemented in assembly.
@@ -235,25 +240,28 @@ enum BuiltinExtraArguments {
V(APPLY_OVERFLOW, 1)
+class BuiltinFunctionTable;
class ObjectVisitor;
-class Builtins : public AllStatic {
+class Builtins {
public:
+ ~Builtins();
+
// Generate all builtin code objects. Should be called once during
- // VM initialization.
- static void Setup(bool create_heap_objects);
- static void TearDown();
+ // isolate initialization.
+ void Setup(bool create_heap_objects);
+ void TearDown();
// Garbage collection support.
- static void IterateBuiltins(ObjectVisitor* v);
+ void IterateBuiltins(ObjectVisitor* v);
// Disassembler support.
- static const char* Lookup(byte* pc);
+ const char* Lookup(byte* pc);
enum Name {
-#define DEF_ENUM_C(name, ignore) name,
-#define DEF_ENUM_A(name, kind, state, extra) name,
+#define DEF_ENUM_C(name, ignore) k##name,
+#define DEF_ENUM_A(name, kind, state, extra) k##name,
BUILTIN_LIST_C(DEF_ENUM_C)
BUILTIN_LIST_A(DEF_ENUM_A)
BUILTIN_LIST_DEBUG_A(DEF_ENUM_A)
@@ -276,13 +284,22 @@ class Builtins : public AllStatic {
id_count
};
- static Code* builtin(Name name) {
+#define DECLARE_BUILTIN_ACCESSOR_C(name, ignore) Handle<Code> name();
+#define DECLARE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
+ Handle<Code> name();
+ BUILTIN_LIST_C(DECLARE_BUILTIN_ACCESSOR_C)
+ BUILTIN_LIST_A(DECLARE_BUILTIN_ACCESSOR_A)
+ BUILTIN_LIST_DEBUG_A(DECLARE_BUILTIN_ACCESSOR_A)
+#undef DECLARE_BUILTIN_ACCESSOR_C
+#undef DECLARE_BUILTIN_ACCESSOR_A
+
+ Code* builtin(Name name) {
// Code::cast cannot be used here since we access builtins
// during the marking phase of mark sweep. See IC::Clear.
return reinterpret_cast<Code*>(builtins_[name]);
}
- static Address builtin_address(Name name) {
+ Address builtin_address(Name name) {
return reinterpret_cast<Address>(&builtins_[name]);
}
@@ -292,20 +309,24 @@ class Builtins : public AllStatic {
static const char* GetName(JavaScript id) { return javascript_names_[id]; }
static int GetArgumentsCount(JavaScript id) { return javascript_argc_[id]; }
- static Handle<Code> GetCode(JavaScript id, bool* resolved);
+ Handle<Code> GetCode(JavaScript id, bool* resolved);
static int NumberOfJavaScriptBuiltins() { return id_count; }
+ bool is_initialized() const { return initialized_; }
+
private:
+ Builtins();
+
// The external C++ functions called from the code.
- static Address c_functions_[cfunction_count];
+ static Address const c_functions_[cfunction_count];
// Note: These are always Code objects, but to conform with
// IterateBuiltins() above which assumes Object**'s for the callback
// function f, we use an Object* array here.
- static Object* builtins_[builtin_count];
- static const char* names_[builtin_count];
- static const char* javascript_names_[id_count];
- static int javascript_argc_[id_count];
+ Object* builtins_[builtin_count];
+ const char* names_[builtin_count];
+ static const char* const javascript_names_[id_count];
+ static int const javascript_argc_[id_count];
static void Generate_Adaptor(MacroAssembler* masm,
CFunctionId id,
@@ -330,8 +351,16 @@ class Builtins : public AllStatic {
static void Generate_ArrayConstructCode(MacroAssembler* masm);
static void Generate_StringConstructCode(MacroAssembler* masm);
-
static void Generate_OnStackReplacement(MacroAssembler* masm);
+
+ static void InitBuiltinFunctionTable();
+
+ bool initialized_;
+
+ friend class BuiltinFunctionTable;
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(Builtins);
};
} } // namespace v8::internal
diff --git a/src/checks.cc b/src/checks.cc
index 3c3d940b..320fd6b5 100644
--- a/src/checks.cc
+++ b/src/checks.cc
@@ -30,8 +30,8 @@
#include "v8.h"
#include "platform.h"
-#include "top.h"
+// TODO(isolates): is it necessary to lift this?
static int fatal_error_handler_nesting_depth = 0;
// Contains protection against recursive calls (faults while handling faults).
@@ -52,7 +52,7 @@ extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
if (fatal_error_handler_nesting_depth < 3) {
if (i::FLAG_stack_trace_on_abort) {
// Call this one twice on double fault
- i::Top::PrintStack();
+ i::Isolate::Current()->PrintStack();
}
}
i::OS::Abort();
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index ba77b21c..2ecd3361 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -37,9 +37,10 @@ namespace v8 {
namespace internal {
bool CodeStub::FindCodeInCache(Code** code_out) {
- int index = Heap::code_stubs()->FindEntry(GetKey());
+ Heap* heap = Isolate::Current()->heap();
+ int index = heap->code_stubs()->FindEntry(GetKey());
if (index != NumberDictionary::kNotFound) {
- *code_out = Code::cast(Heap::code_stubs()->ValueAt(index));
+ *code_out = Code::cast(heap->code_stubs()->ValueAt(index));
return true;
}
return false;
@@ -48,7 +49,7 @@ bool CodeStub::FindCodeInCache(Code** code_out) {
void CodeStub::GenerateCode(MacroAssembler* masm) {
// Update the static counter each time a new code stub is generated.
- Counters::code_stubs.Increment();
+ masm->isolate()->counters()->code_stubs()->Increment();
// Nested stubs are not allowed for leafs.
AllowStubCallsScope allow_scope(masm, AllowsStubCalls());
@@ -62,9 +63,11 @@ void CodeStub::GenerateCode(MacroAssembler* masm) {
void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
code->set_major_key(MajorKey());
- PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, GetName()));
+ Isolate* isolate = masm->isolate();
+ PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, GetName()));
GDBJIT(AddCode(GDBJITInterface::STUB, GetName(), code));
- Counters::total_stubs_code_size.Increment(code->instruction_size());
+ Counters* counters = isolate->counters();
+ counters->total_stubs_code_size()->Increment(code->instruction_size());
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code_stubs) {
@@ -84,9 +87,12 @@ int CodeStub::GetCodeKind() {
Handle<Code> CodeStub::GetCode() {
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ Heap* heap = isolate->heap();
Code* code;
if (!FindCodeInCache(&code)) {
- v8::HandleScope scope;
+ HandleScope scope(isolate);
// Generate the new code.
MacroAssembler masm(NULL, 256);
@@ -101,22 +107,24 @@ Handle<Code> CodeStub::GetCode() {
static_cast<Code::Kind>(GetCodeKind()),
InLoop(),
GetICState());
- Handle<Code> new_object = Factory::NewCode(desc, flags, masm.CodeObject());
+ Handle<Code> new_object = factory->NewCode(
+ desc, flags, masm.CodeObject(), NeedsImmovableCode());
RecordCodeGeneration(*new_object, &masm);
FinishCode(*new_object);
// Update the dictionary and the root in Heap.
Handle<NumberDictionary> dict =
- Factory::DictionaryAtNumberPut(
- Handle<NumberDictionary>(Heap::code_stubs()),
+ factory->DictionaryAtNumberPut(
+ Handle<NumberDictionary>(heap->code_stubs()),
GetKey(),
new_object);
- Heap::public_set_code_stubs(*dict);
+ heap->public_set_code_stubs(*dict);
code = *new_object;
}
- return Handle<Code>(code);
+ ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code));
+ return Handle<Code>(code, isolate);
}
@@ -126,6 +134,7 @@ MaybeObject* CodeStub::TryGetCode() {
// Generate the new code.
MacroAssembler masm(NULL, 256);
GenerateCode(&masm);
+ Heap* heap = masm.isolate()->heap();
// Create the code object.
CodeDesc desc;
@@ -138,7 +147,7 @@ MaybeObject* CodeStub::TryGetCode() {
GetICState());
Object* new_object;
{ MaybeObject* maybe_new_object =
- Heap::CreateCode(desc, flags, masm.CodeObject());
+ heap->CreateCode(desc, flags, masm.CodeObject());
if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
}
code = Code::cast(new_object);
@@ -147,9 +156,9 @@ MaybeObject* CodeStub::TryGetCode() {
// Try to update the code cache but do not fail if unable.
MaybeObject* maybe_new_object =
- Heap::code_stubs()->AtNumberPut(GetKey(), code);
+ heap->code_stubs()->AtNumberPut(GetKey(), code);
if (maybe_new_object->ToObject(&new_object)) {
- Heap::public_set_code_stubs(NumberDictionary::cast(new_object));
+ heap->public_set_code_stubs(NumberDictionary::cast(new_object));
}
}
@@ -200,7 +209,8 @@ void ICCompareStub::Generate(MacroAssembler* masm) {
const char* InstanceofStub::GetName() {
if (name_ != NULL) return name_;
const int kMaxNameLength = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
+ kMaxNameLength);
if (name_ == NULL) return "OOM";
const char* args = "";
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 96ac7335..d408034f 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -40,7 +40,6 @@ namespace internal {
V(GenericBinaryOp) \
V(TypeRecordingBinaryOp) \
V(StringAdd) \
- V(StringCharAt) \
V(SubString) \
V(StringCompare) \
V(SmiOp) \
@@ -81,10 +80,19 @@ namespace internal {
#define CODE_STUB_LIST_ARM(V)
#endif
+// List of code stubs only used on MIPS platforms.
+#ifdef V8_TARGET_ARCH_MIPS
+#define CODE_STUB_LIST_MIPS(V) \
+ V(RegExpCEntry)
+#else
+#define CODE_STUB_LIST_MIPS(V)
+#endif
+
// Combined list of code stubs.
#define CODE_STUB_LIST(V) \
CODE_STUB_LIST_ALL_PLATFORMS(V) \
- CODE_STUB_LIST_ARM(V)
+ CODE_STUB_LIST_ARM(V) \
+ CODE_STUB_LIST_MIPS(V)
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
@@ -167,7 +175,11 @@ class CodeStub BASE_EMBEDDED {
// Returns a name for logging/debugging purposes.
virtual const char* GetName() { return MajorName(MajorKey(), false); }
-#ifdef DEBUG
+ // Returns whether the code generated for this stub needs to be allocated as
+ // a fixed (non-moveable) code object.
+ virtual bool NeedsImmovableCode() { return false; }
+
+ #ifdef DEBUG
virtual void Print() { PrintF("%s\n", GetName()); }
#endif
@@ -274,12 +286,17 @@ class ToNumberStub: public CodeStub {
class FastNewClosureStub : public CodeStub {
public:
+ explicit FastNewClosureStub(StrictModeFlag strict_mode)
+ : strict_mode_(strict_mode) { }
+
void Generate(MacroAssembler* masm);
private:
const char* GetName() { return "FastNewClosureStub"; }
Major MajorKey() { return FastNewClosure; }
- int MinorKey() { return 0; }
+ int MinorKey() { return strict_mode_; }
+
+ StrictModeFlag strict_mode_;
};
@@ -434,18 +451,6 @@ class MathPowStub: public CodeStub {
};
-class StringCharAtStub: public CodeStub {
- public:
- StringCharAtStub() {}
-
- private:
- Major MajorKey() { return StringCharAt; }
- int MinorKey() { return 0; }
-
- void Generate(MacroAssembler* masm);
-};
-
-
class ICCompareStub: public CodeStub {
public:
ICCompareStub(Token::Value op, CompareIC::State state)
@@ -623,6 +628,8 @@ class CEntryStub : public CodeStub {
Major MajorKey() { return CEntry; }
int MinorKey();
+ bool NeedsImmovableCode();
+
const char* GetName() { return "CEntryStub"; }
};
@@ -661,7 +668,8 @@ class ArgumentsAccessStub: public CodeStub {
public:
enum Type {
READ_ELEMENT,
- NEW_OBJECT
+ NEW_NON_STRICT,
+ NEW_STRICT
};
explicit ArgumentsAccessStub(Type type) : type_(type) { }
@@ -676,6 +684,19 @@ class ArgumentsAccessStub: public CodeStub {
void GenerateReadElement(MacroAssembler* masm);
void GenerateNewObject(MacroAssembler* masm);
+ int GetArgumentsBoilerplateIndex() const {
+ return (type_ == NEW_STRICT)
+ ? Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX
+ : Context::ARGUMENTS_BOILERPLATE_INDEX;
+ }
+
+ int GetArgumentsObjectSize() const {
+ if (type_ == NEW_STRICT)
+ return Heap::kArgumentsObjectSizeStrict;
+ else
+ return Heap::kArgumentsObjectSize;
+ }
+
const char* GetName() { return "ArgumentsAccessStub"; }
#ifdef DEBUG
diff --git a/src/codegen-inl.h b/src/codegen-inl.h
index 54677894..f7da54a2 100644
--- a/src/codegen-inl.h
+++ b/src/codegen-inl.h
@@ -55,8 +55,12 @@ bool CodeGenerator::is_eval() { return info_->is_eval(); }
Scope* CodeGenerator::scope() { return info_->function()->scope(); }
+bool CodeGenerator::is_strict_mode() {
+ return info_->function()->strict_mode();
+}
+
StrictModeFlag CodeGenerator::strict_mode_flag() {
- return info_->function()->strict_mode() ? kStrictMode : kNonStrictMode;
+ return is_strict_mode() ? kStrictMode : kNonStrictMode;
}
} } // namespace v8::internal
diff --git a/src/codegen.cc b/src/codegen.cc
index e6fcecde..03f64a15 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -61,9 +61,6 @@ Comment::~Comment() {
#undef __
-CodeGenerator* CodeGeneratorScope::top_ = NULL;
-
-
void CodeGenerator::ProcessDeferred() {
while (!deferred_.is_empty()) {
DeferredCode* code = deferred_.RemoveLast();
@@ -129,7 +126,7 @@ void CodeGenerator::MakeCodePrologue(CompilationInfo* info) {
bool print_json_ast = false;
const char* ftype;
- if (Bootstrapper::IsActive()) {
+ if (Isolate::Current()->bootstrapper()->IsActive()) {
print_source = FLAG_print_builtin_source;
print_ast = FLAG_print_builtin_ast;
print_json_ast = FLAG_print_builtin_json_ast;
@@ -178,13 +175,17 @@ void CodeGenerator::MakeCodePrologue(CompilationInfo* info) {
Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
Code::Flags flags,
CompilationInfo* info) {
+ Isolate* isolate = info->isolate();
+
// Allocate and install the code.
CodeDesc desc;
masm->GetCode(&desc);
- Handle<Code> code = Factory::NewCode(desc, flags, masm->CodeObject());
+ Handle<Code> code =
+ isolate->factory()->NewCode(desc, flags, masm->CodeObject());
if (!code.is_null()) {
- Counters::total_compiled_code_size.Increment(code->instruction_size());
+ isolate->counters()->total_compiled_code_size()->Increment(
+ code->instruction_size());
}
return code;
}
@@ -192,7 +193,7 @@ Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
#ifdef ENABLE_DISASSEMBLER
- bool print_code = Bootstrapper::IsActive()
+ bool print_code = Isolate::Current()->bootstrapper()->IsActive()
? FLAG_print_builtin_code
: (FLAG_print_code || (info->IsOptimizing() && FLAG_print_opt_code));
Vector<const char> filter = CStrVector(FLAG_hydrogen_filter);
@@ -238,7 +239,8 @@ bool CodeGenerator::MakeCode(CompilationInfo* info) {
Handle<Script> script = info->script();
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
int len = String::cast(script->source())->length();
- Counters::total_old_codegen_source_size.Increment(len);
+ Counters* counters = info->isolate()->counters();
+ counters->total_old_codegen_source_size()->Increment(len);
}
if (FLAG_trace_codegen) {
PrintF("Classic Compiler - ");
@@ -251,10 +253,10 @@ bool CodeGenerator::MakeCode(CompilationInfo* info) {
masm.positions_recorder()->StartGDBJITLineInfoRecording();
#endif
CodeGenerator cgen(&masm);
- CodeGeneratorScope scope(&cgen);
+ CodeGeneratorScope scope(Isolate::Current(), &cgen);
cgen.Generate(info);
if (cgen.HasStackOverflow()) {
- ASSERT(!Top::has_pending_exception());
+ ASSERT(!Isolate::Current()->has_pending_exception());
return false;
}
@@ -279,12 +281,15 @@ bool CodeGenerator::MakeCode(CompilationInfo* info) {
#ifdef ENABLE_LOGGING_AND_PROFILING
+
+static Vector<const char> kRegexp = CStrVector("regexp");
+
+
bool CodeGenerator::ShouldGenerateLog(Expression* type) {
ASSERT(type != NULL);
- if (!Logger::is_logging() && !CpuProfiler::is_profiling()) return false;
+ if (!LOGGER->is_logging() && !CpuProfiler::is_profiling()) return false;
Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
if (FLAG_log_regexp) {
- static Vector<const char> kRegexp = CStrVector("regexp");
if (name->IsEqualTo(kRegexp))
return true;
}
@@ -317,7 +322,7 @@ void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
if (globals == 0) return;
// Compute array of global variable and function declarations.
- Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
+ Handle<FixedArray> array = FACTORY->NewFixedArray(2 * globals, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* node = declarations->at(i);
Variable* var = node->proxy()->var();
@@ -374,7 +379,7 @@ const CodeGenerator::InlineFunctionGenerator
bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments();
Handle<String> name = node->name();
- Runtime::Function* function = node->function();
+ const Runtime::Function* function = node->function();
if (function != NULL && function->intrinsic_type == Runtime::INLINE) {
int lookup_index = static_cast<int>(function->function_id) -
static_cast<int>(Runtime::kFirstInlineFunction);
@@ -475,8 +480,13 @@ const char* GenericUnaryOpStub::GetName() {
void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
switch (type_) {
- case READ_ELEMENT: GenerateReadElement(masm); break;
- case NEW_OBJECT: GenerateNewObject(masm); break;
+ case READ_ELEMENT:
+ GenerateReadElement(masm);
+ break;
+ case NEW_NON_STRICT:
+ case NEW_STRICT:
+ GenerateNewObject(masm);
+ break;
}
}
diff --git a/src/codegen.h b/src/codegen.h
index 23b36f07..aa319997 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -92,26 +92,26 @@ namespace internal {
// of active code generators.
class CodeGeneratorScope BASE_EMBEDDED {
public:
- explicit CodeGeneratorScope(CodeGenerator* cgen) {
- previous_ = top_;
- top_ = cgen;
+ explicit CodeGeneratorScope(Isolate* isolate, CodeGenerator* cgen)
+ : isolate_(isolate) {
+ previous_ = isolate->current_code_generator();
+ isolate->set_current_code_generator(cgen);
}
~CodeGeneratorScope() {
- top_ = previous_;
+ isolate_->set_current_code_generator(previous_);
}
- static CodeGenerator* Current() {
- ASSERT(top_ != NULL);
- return top_;
+ static CodeGenerator* Current(Isolate* isolate) {
+ ASSERT(isolate->current_code_generator() != NULL);
+ return isolate->current_code_generator();
}
private:
- static CodeGenerator* top_;
CodeGenerator* previous_;
+ Isolate* isolate_;
};
-
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
// State of used registers in a virtual frame.
diff --git a/src/compilation-cache.cc b/src/compilation-cache.cc
index cccb7a4f..5bd8bf31 100644
--- a/src/compilation-cache.cc
+++ b/src/compilation-cache.cc
@@ -33,8 +33,6 @@
namespace v8 {
namespace internal {
-// The number of sub caches covering the different types to cache.
-static const int kSubCacheCount = 4;
// The number of generations for each sub cache.
// The number of ScriptGenerations is carefully chosen based on histograms.
@@ -47,162 +45,32 @@ static const int kRegExpGenerations = 2;
// Initial size of each compilation cache table allocated.
static const int kInitialCacheSize = 64;
-// Index for the first generation in the cache.
-static const int kFirstGeneration = 0;
-
-// The compilation cache consists of several generational sub-caches which uses
-// this class as a base class. A sub-cache contains a compilation cache tables
-// for each generation of the sub-cache. Since the same source code string has
-// different compiled code for scripts and evals, we use separate sub-caches
-// for different compilation modes, to avoid retrieving the wrong result.
-class CompilationSubCache {
- public:
- explicit CompilationSubCache(int generations): generations_(generations) {
- tables_ = NewArray<Object*>(generations);
- }
-
- ~CompilationSubCache() { DeleteArray(tables_); }
-
- // Get the compilation cache tables for a specific generation.
- Handle<CompilationCacheTable> GetTable(int generation);
- // Accessors for first generation.
- Handle<CompilationCacheTable> GetFirstTable() {
- return GetTable(kFirstGeneration);
+CompilationCache::CompilationCache(Isolate* isolate)
+ : isolate_(isolate),
+ script_(isolate, kScriptGenerations),
+ eval_global_(isolate, kEvalGlobalGenerations),
+ eval_contextual_(isolate, kEvalContextualGenerations),
+ reg_exp_(isolate, kRegExpGenerations),
+ enabled_(true),
+ eager_optimizing_set_(NULL) {
+ CompilationSubCache* subcaches[kSubCacheCount] =
+ {&script_, &eval_global_, &eval_contextual_, &reg_exp_};
+ for (int i = 0; i < kSubCacheCount; ++i) {
+ subcaches_[i] = subcaches[i];
}
- void SetFirstTable(Handle<CompilationCacheTable> value) {
- ASSERT(kFirstGeneration < generations_);
- tables_[kFirstGeneration] = *value;
- }
-
- // Age the sub-cache by evicting the oldest generation and creating a new
- // young generation.
- void Age();
-
- // GC support.
- void Iterate(ObjectVisitor* v);
- void IterateFunctions(ObjectVisitor* v);
-
- // Clear this sub-cache evicting all its content.
- void Clear();
-
- // Remove given shared function info from sub-cache.
- void Remove(Handle<SharedFunctionInfo> function_info);
-
- // Number of generations in this sub-cache.
- inline int generations() { return generations_; }
-
- private:
- int generations_; // Number of generations.
- Object** tables_; // Compilation cache tables - one for each generation.
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationSubCache);
-};
-
-
-// Sub-cache for scripts.
-class CompilationCacheScript : public CompilationSubCache {
- public:
- explicit CompilationCacheScript(int generations)
- : CompilationSubCache(generations) { }
-
- Handle<SharedFunctionInfo> Lookup(Handle<String> source,
- Handle<Object> name,
- int line_offset,
- int column_offset);
- void Put(Handle<String> source, Handle<SharedFunctionInfo> function_info);
-
- private:
- MUST_USE_RESULT MaybeObject* TryTablePut(
- Handle<String> source, Handle<SharedFunctionInfo> function_info);
-
- // Note: Returns a new hash table if operation results in expansion.
- Handle<CompilationCacheTable> TablePut(
- Handle<String> source, Handle<SharedFunctionInfo> function_info);
-
- bool HasOrigin(Handle<SharedFunctionInfo> function_info,
- Handle<Object> name,
- int line_offset,
- int column_offset);
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript);
-};
-
-
-// Sub-cache for eval scripts.
-class CompilationCacheEval: public CompilationSubCache {
- public:
- explicit CompilationCacheEval(int generations)
- : CompilationSubCache(generations) { }
-
- Handle<SharedFunctionInfo> Lookup(Handle<String> source,
- Handle<Context> context,
- StrictModeFlag strict_mode);
-
- void Put(Handle<String> source,
- Handle<Context> context,
- Handle<SharedFunctionInfo> function_info);
-
- private:
- MUST_USE_RESULT MaybeObject* TryTablePut(
- Handle<String> source,
- Handle<Context> context,
- Handle<SharedFunctionInfo> function_info);
-
-
- // Note: Returns a new hash table if operation results in expansion.
- Handle<CompilationCacheTable> TablePut(
- Handle<String> source,
- Handle<Context> context,
- Handle<SharedFunctionInfo> function_info);
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval);
-};
-
-
-// Sub-cache for regular expressions.
-class CompilationCacheRegExp: public CompilationSubCache {
- public:
- explicit CompilationCacheRegExp(int generations)
- : CompilationSubCache(generations) { }
-
- Handle<FixedArray> Lookup(Handle<String> source, JSRegExp::Flags flags);
-
- void Put(Handle<String> source,
- JSRegExp::Flags flags,
- Handle<FixedArray> data);
- private:
- MUST_USE_RESULT MaybeObject* TryTablePut(Handle<String> source,
- JSRegExp::Flags flags,
- Handle<FixedArray> data);
-
- // Note: Returns a new hash table if operation results in expansion.
- Handle<CompilationCacheTable> TablePut(Handle<String> source,
- JSRegExp::Flags flags,
- Handle<FixedArray> data);
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheRegExp);
-};
-
-
-// Statically allocate all the sub-caches.
-static CompilationCacheScript script(kScriptGenerations);
-static CompilationCacheEval eval_global(kEvalGlobalGenerations);
-static CompilationCacheEval eval_contextual(kEvalContextualGenerations);
-static CompilationCacheRegExp reg_exp(kRegExpGenerations);
-static CompilationSubCache* subcaches[kSubCacheCount] =
- {&script, &eval_global, &eval_contextual, &reg_exp};
+}
-// Current enable state of the compilation cache.
-static bool enabled = true;
-static inline bool IsEnabled() {
- return FLAG_compilation_cache && enabled;
+CompilationCache::~CompilationCache() {
+ delete eager_optimizing_set_;
+ eager_optimizing_set_ = NULL;
}
-static Handle<CompilationCacheTable> AllocateTable(int size) {
- CALL_HEAP_FUNCTION(CompilationCacheTable::Allocate(size),
+static Handle<CompilationCacheTable> AllocateTable(Isolate* isolate, int size) {
+ CALL_HEAP_FUNCTION(isolate,
+ CompilationCacheTable::Allocate(size),
CompilationCacheTable);
}
@@ -211,17 +79,16 @@ Handle<CompilationCacheTable> CompilationSubCache::GetTable(int generation) {
ASSERT(generation < generations_);
Handle<CompilationCacheTable> result;
if (tables_[generation]->IsUndefined()) {
- result = AllocateTable(kInitialCacheSize);
+ result = AllocateTable(isolate(), kInitialCacheSize);
tables_[generation] = *result;
} else {
CompilationCacheTable* table =
CompilationCacheTable::cast(tables_[generation]);
- result = Handle<CompilationCacheTable>(table);
+ result = Handle<CompilationCacheTable>(table, isolate());
}
return result;
}
-
void CompilationSubCache::Age() {
// Age the generations implicitly killing off the oldest.
for (int i = generations_ - 1; i > 0; i--) {
@@ -229,12 +96,12 @@ void CompilationSubCache::Age() {
}
// Set the first generation as unborn.
- tables_[0] = Heap::undefined_value();
+ tables_[0] = isolate()->heap()->undefined_value();
}
void CompilationSubCache::IterateFunctions(ObjectVisitor* v) {
- Object* undefined = Heap::raw_unchecked_undefined_value();
+ Object* undefined = isolate()->heap()->raw_unchecked_undefined_value();
for (int i = 0; i < generations_; i++) {
if (tables_[i] != undefined) {
reinterpret_cast<CompilationCacheTable*>(tables_[i])->IterateElements(v);
@@ -249,14 +116,14 @@ void CompilationSubCache::Iterate(ObjectVisitor* v) {
void CompilationSubCache::Clear() {
- MemsetPointer(tables_, Heap::undefined_value(), generations_);
+ MemsetPointer(tables_, isolate()->heap()->undefined_value(), generations_);
}
void CompilationSubCache::Remove(Handle<SharedFunctionInfo> function_info) {
// Probe the script generation tables. Make sure not to leak handles
// into the caller's handle scope.
- { HandleScope scope;
+ { HandleScope scope(isolate());
for (int generation = 0; generation < generations(); generation++) {
Handle<CompilationCacheTable> table = GetTable(generation);
table->Remove(*function_info);
@@ -265,6 +132,13 @@ void CompilationSubCache::Remove(Handle<SharedFunctionInfo> function_info) {
}
+CompilationCacheScript::CompilationCacheScript(Isolate* isolate,
+ int generations)
+ : CompilationSubCache(isolate, generations),
+ script_histogram_(NULL),
+ script_histogram_initialized_(false) { }
+
+
// We only re-use a cached function for some script source code if the
// script originates from the same place. This is to avoid issues
// when reporting errors, etc.
@@ -274,7 +148,7 @@ bool CompilationCacheScript::HasOrigin(
int line_offset,
int column_offset) {
Handle<Script> script =
- Handle<Script>(Script::cast(function_info->script()));
+ Handle<Script>(Script::cast(function_info->script()), isolate());
// If the script name isn't set, the boilerplate script should have
// an undefined name to have the same origin.
if (name.is_null()) {
@@ -303,10 +177,10 @@ Handle<SharedFunctionInfo> CompilationCacheScript::Lookup(Handle<String> source,
// Probe the script generation tables. Make sure not to leak handles
// into the caller's handle scope.
- { HandleScope scope;
+ { HandleScope scope(isolate());
for (generation = 0; generation < generations(); generation++) {
Handle<CompilationCacheTable> table = GetTable(generation);
- Handle<Object> probe(table->Lookup(*source));
+ Handle<Object> probe(table->Lookup(*source), isolate());
if (probe->IsSharedFunctionInfo()) {
Handle<SharedFunctionInfo> function_info =
Handle<SharedFunctionInfo>::cast(probe);
@@ -320,30 +194,34 @@ Handle<SharedFunctionInfo> CompilationCacheScript::Lookup(Handle<String> source,
}
}
- static void* script_histogram = StatsTable::CreateHistogram(
- "V8.ScriptCache",
- 0,
- kScriptGenerations,
- kScriptGenerations + 1);
+ if (!script_histogram_initialized_) {
+ script_histogram_ = isolate()->stats_table()->CreateHistogram(
+ "V8.ScriptCache",
+ 0,
+ kScriptGenerations,
+ kScriptGenerations + 1);
+ script_histogram_initialized_ = true;
+ }
- if (script_histogram != NULL) {
+ if (script_histogram_ != NULL) {
// The level NUMBER_OF_SCRIPT_GENERATIONS is equivalent to a cache miss.
- StatsTable::AddHistogramSample(script_histogram, generation);
+ isolate()->stats_table()->AddHistogramSample(script_histogram_, generation);
}
// Once outside the manacles of the handle scope, we need to recheck
// to see if we actually found a cached script. If so, we return a
// handle created in the caller's handle scope.
if (result != NULL) {
- Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
+ Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result),
+ isolate());
ASSERT(HasOrigin(shared, name, line_offset, column_offset));
// If the script was found in a later generation, we promote it to
// the first generation to let it survive longer in the cache.
if (generation != 0) Put(source, shared);
- Counters::compilation_cache_hits.Increment();
+ isolate()->counters()->compilation_cache_hits()->Increment();
return shared;
} else {
- Counters::compilation_cache_misses.Increment();
+ isolate()->counters()->compilation_cache_misses()->Increment();
return Handle<SharedFunctionInfo>::null();
}
}
@@ -360,13 +238,15 @@ MaybeObject* CompilationCacheScript::TryTablePut(
Handle<CompilationCacheTable> CompilationCacheScript::TablePut(
Handle<String> source,
Handle<SharedFunctionInfo> function_info) {
- CALL_HEAP_FUNCTION(TryTablePut(source, function_info), CompilationCacheTable);
+ CALL_HEAP_FUNCTION(isolate(),
+ TryTablePut(source, function_info),
+ CompilationCacheTable);
}
void CompilationCacheScript::Put(Handle<String> source,
Handle<SharedFunctionInfo> function_info) {
- HandleScope scope;
+ HandleScope scope(isolate());
SetFirstTable(TablePut(source, function_info));
}
@@ -380,7 +260,7 @@ Handle<SharedFunctionInfo> CompilationCacheEval::Lookup(
// having cleared the cache.
Object* result = NULL;
int generation;
- { HandleScope scope;
+ { HandleScope scope(isolate());
for (generation = 0; generation < generations(); generation++) {
Handle<CompilationCacheTable> table = GetTable(generation);
result = table->LookupEval(*source, *context, strict_mode);
@@ -391,14 +271,14 @@ Handle<SharedFunctionInfo> CompilationCacheEval::Lookup(
}
if (result->IsSharedFunctionInfo()) {
Handle<SharedFunctionInfo>
- function_info(SharedFunctionInfo::cast(result));
+ function_info(SharedFunctionInfo::cast(result), isolate());
if (generation != 0) {
Put(source, context, function_info);
}
- Counters::compilation_cache_hits.Increment();
+ isolate()->counters()->compilation_cache_hits()->Increment();
return function_info;
} else {
- Counters::compilation_cache_misses.Increment();
+ isolate()->counters()->compilation_cache_misses()->Increment();
return Handle<SharedFunctionInfo>::null();
}
}
@@ -417,7 +297,8 @@ Handle<CompilationCacheTable> CompilationCacheEval::TablePut(
Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info) {
- CALL_HEAP_FUNCTION(TryTablePut(source, context, function_info),
+ CALL_HEAP_FUNCTION(isolate(),
+ TryTablePut(source, context, function_info),
CompilationCacheTable);
}
@@ -425,7 +306,7 @@ Handle<CompilationCacheTable> CompilationCacheEval::TablePut(
void CompilationCacheEval::Put(Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info) {
- HandleScope scope;
+ HandleScope scope(isolate());
SetFirstTable(TablePut(source, context, function_info));
}
@@ -437,7 +318,7 @@ Handle<FixedArray> CompilationCacheRegExp::Lookup(Handle<String> source,
// having cleared the cache.
Object* result = NULL;
int generation;
- { HandleScope scope;
+ { HandleScope scope(isolate());
for (generation = 0; generation < generations(); generation++) {
Handle<CompilationCacheTable> table = GetTable(generation);
result = table->LookupRegExp(*source, flags);
@@ -447,14 +328,14 @@ Handle<FixedArray> CompilationCacheRegExp::Lookup(Handle<String> source,
}
}
if (result->IsFixedArray()) {
- Handle<FixedArray> data(FixedArray::cast(result));
+ Handle<FixedArray> data(FixedArray::cast(result), isolate());
if (generation != 0) {
Put(source, flags, data);
}
- Counters::compilation_cache_hits.Increment();
+ isolate()->counters()->compilation_cache_hits()->Increment();
return data;
} else {
- Counters::compilation_cache_misses.Increment();
+ isolate()->counters()->compilation_cache_misses()->Increment();
return Handle<FixedArray>::null();
}
}
@@ -473,14 +354,16 @@ Handle<CompilationCacheTable> CompilationCacheRegExp::TablePut(
Handle<String> source,
JSRegExp::Flags flags,
Handle<FixedArray> data) {
- CALL_HEAP_FUNCTION(TryTablePut(source, flags, data), CompilationCacheTable);
+ CALL_HEAP_FUNCTION(isolate(),
+ TryTablePut(source, flags, data),
+ CompilationCacheTable);
}
void CompilationCacheRegExp::Put(Handle<String> source,
JSRegExp::Flags flags,
Handle<FixedArray> data) {
- HandleScope scope;
+ HandleScope scope(isolate());
SetFirstTable(TablePut(source, flags, data));
}
@@ -488,9 +371,9 @@ void CompilationCacheRegExp::Put(Handle<String> source,
void CompilationCache::Remove(Handle<SharedFunctionInfo> function_info) {
if (!IsEnabled()) return;
- eval_global.Remove(function_info);
- eval_contextual.Remove(function_info);
- script.Remove(function_info);
+ eval_global_.Remove(function_info);
+ eval_contextual_.Remove(function_info);
+ script_.Remove(function_info);
}
@@ -502,7 +385,7 @@ Handle<SharedFunctionInfo> CompilationCache::LookupScript(Handle<String> source,
return Handle<SharedFunctionInfo>::null();
}
- return script.Lookup(source, name, line_offset, column_offset);
+ return script_.Lookup(source, name, line_offset, column_offset);
}
@@ -517,9 +400,9 @@ Handle<SharedFunctionInfo> CompilationCache::LookupEval(
Handle<SharedFunctionInfo> result;
if (is_global) {
- result = eval_global.Lookup(source, context, strict_mode);
+ result = eval_global_.Lookup(source, context, strict_mode);
} else {
- result = eval_contextual.Lookup(source, context, strict_mode);
+ result = eval_contextual_.Lookup(source, context, strict_mode);
}
return result;
}
@@ -531,7 +414,7 @@ Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
return Handle<FixedArray>::null();
}
- return reg_exp.Lookup(source, flags);
+ return reg_exp_.Lookup(source, flags);
}
@@ -541,7 +424,7 @@ void CompilationCache::PutScript(Handle<String> source,
return;
}
- script.Put(source, function_info);
+ script_.Put(source, function_info);
}
@@ -553,11 +436,11 @@ void CompilationCache::PutEval(Handle<String> source,
return;
}
- HandleScope scope;
+ HandleScope scope(isolate());
if (is_global) {
- eval_global.Put(source, context, function_info);
+ eval_global_.Put(source, context, function_info);
} else {
- eval_contextual.Put(source, context, function_info);
+ eval_contextual_.Put(source, context, function_info);
}
}
@@ -570,7 +453,7 @@ void CompilationCache::PutRegExp(Handle<String> source,
return;
}
- reg_exp.Put(source, flags, data);
+ reg_exp_.Put(source, flags, data);
}
@@ -579,9 +462,11 @@ static bool SourceHashCompare(void* key1, void* key2) {
}
-static HashMap* EagerOptimizingSet() {
- static HashMap map(&SourceHashCompare);
- return &map;
+HashMap* CompilationCache::EagerOptimizingSet() {
+ if (eager_optimizing_set_ == NULL) {
+ eager_optimizing_set_ = new HashMap(&SourceHashCompare);
+ }
+ return eager_optimizing_set_;
}
@@ -615,38 +500,39 @@ void CompilationCache::ResetEagerOptimizingData() {
void CompilationCache::Clear() {
for (int i = 0; i < kSubCacheCount; i++) {
- subcaches[i]->Clear();
+ subcaches_[i]->Clear();
}
}
+
void CompilationCache::Iterate(ObjectVisitor* v) {
for (int i = 0; i < kSubCacheCount; i++) {
- subcaches[i]->Iterate(v);
+ subcaches_[i]->Iterate(v);
}
}
void CompilationCache::IterateFunctions(ObjectVisitor* v) {
for (int i = 0; i < kSubCacheCount; i++) {
- subcaches[i]->IterateFunctions(v);
+ subcaches_[i]->IterateFunctions(v);
}
}
void CompilationCache::MarkCompactPrologue() {
for (int i = 0; i < kSubCacheCount; i++) {
- subcaches[i]->Age();
+ subcaches_[i]->Age();
}
}
void CompilationCache::Enable() {
- enabled = true;
+ enabled_ = true;
}
void CompilationCache::Disable() {
- enabled = false;
+ enabled_ = false;
Clear();
}
diff --git a/src/compilation-cache.h b/src/compilation-cache.h
index f779a23a..887d4e84 100644
--- a/src/compilation-cache.h
+++ b/src/compilation-cache.h
@@ -31,6 +31,152 @@
namespace v8 {
namespace internal {
+class HashMap;
+
+// The compilation cache consists of several generational sub-caches which uses
+// this class as a base class. A sub-cache contains a compilation cache tables
+// for each generation of the sub-cache. Since the same source code string has
+// different compiled code for scripts and evals, we use separate sub-caches
+// for different compilation modes, to avoid retrieving the wrong result.
+class CompilationSubCache {
+ public:
+ CompilationSubCache(Isolate* isolate, int generations)
+ : isolate_(isolate),
+ generations_(generations) {
+ tables_ = NewArray<Object*>(generations);
+ }
+
+ ~CompilationSubCache() { DeleteArray(tables_); }
+
+ // Index for the first generation in the cache.
+ static const int kFirstGeneration = 0;
+
+ // Get the compilation cache tables for a specific generation.
+ Handle<CompilationCacheTable> GetTable(int generation);
+
+ // Accessors for first generation.
+ Handle<CompilationCacheTable> GetFirstTable() {
+ return GetTable(kFirstGeneration);
+ }
+ void SetFirstTable(Handle<CompilationCacheTable> value) {
+ ASSERT(kFirstGeneration < generations_);
+ tables_[kFirstGeneration] = *value;
+ }
+
+ // Age the sub-cache by evicting the oldest generation and creating a new
+ // young generation.
+ void Age();
+
+ // GC support.
+ void Iterate(ObjectVisitor* v);
+ void IterateFunctions(ObjectVisitor* v);
+
+ // Clear this sub-cache evicting all its content.
+ void Clear();
+
+ // Remove given shared function info from sub-cache.
+ void Remove(Handle<SharedFunctionInfo> function_info);
+
+ // Number of generations in this sub-cache.
+ inline int generations() { return generations_; }
+
+ protected:
+ Isolate* isolate() { return isolate_; }
+
+ private:
+ Isolate* isolate_;
+ int generations_; // Number of generations.
+ Object** tables_; // Compilation cache tables - one for each generation.
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationSubCache);
+};
+
+
+// Sub-cache for scripts.
+class CompilationCacheScript : public CompilationSubCache {
+ public:
+ CompilationCacheScript(Isolate* isolate, int generations);
+
+ Handle<SharedFunctionInfo> Lookup(Handle<String> source,
+ Handle<Object> name,
+ int line_offset,
+ int column_offset);
+ void Put(Handle<String> source, Handle<SharedFunctionInfo> function_info);
+
+ private:
+ MUST_USE_RESULT MaybeObject* TryTablePut(
+ Handle<String> source, Handle<SharedFunctionInfo> function_info);
+
+ // Note: Returns a new hash table if operation results in expansion.
+ Handle<CompilationCacheTable> TablePut(
+ Handle<String> source, Handle<SharedFunctionInfo> function_info);
+
+ bool HasOrigin(Handle<SharedFunctionInfo> function_info,
+ Handle<Object> name,
+ int line_offset,
+ int column_offset);
+
+ void* script_histogram_;
+ bool script_histogram_initialized_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript);
+};
+
+
+// Sub-cache for eval scripts.
+class CompilationCacheEval: public CompilationSubCache {
+ public:
+ CompilationCacheEval(Isolate* isolate, int generations)
+ : CompilationSubCache(isolate, generations) { }
+
+ Handle<SharedFunctionInfo> Lookup(Handle<String> source,
+ Handle<Context> context,
+ StrictModeFlag strict_mode);
+
+ void Put(Handle<String> source,
+ Handle<Context> context,
+ Handle<SharedFunctionInfo> function_info);
+
+ private:
+ MUST_USE_RESULT MaybeObject* TryTablePut(
+ Handle<String> source,
+ Handle<Context> context,
+ Handle<SharedFunctionInfo> function_info);
+
+ // Note: Returns a new hash table if operation results in expansion.
+ Handle<CompilationCacheTable> TablePut(
+ Handle<String> source,
+ Handle<Context> context,
+ Handle<SharedFunctionInfo> function_info);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval);
+};
+
+
+// Sub-cache for regular expressions.
+class CompilationCacheRegExp: public CompilationSubCache {
+ public:
+ CompilationCacheRegExp(Isolate* isolate, int generations)
+ : CompilationSubCache(isolate, generations) { }
+
+ Handle<FixedArray> Lookup(Handle<String> source, JSRegExp::Flags flags);
+
+ void Put(Handle<String> source,
+ JSRegExp::Flags flags,
+ Handle<FixedArray> data);
+ private:
+ MUST_USE_RESULT MaybeObject* TryTablePut(Handle<String> source,
+ JSRegExp::Flags flags,
+ Handle<FixedArray> data);
+
+ // Note: Returns a new hash table if operation results in expansion.
+ Handle<CompilationCacheTable> TablePut(Handle<String> source,
+ JSRegExp::Flags flags,
+ Handle<FixedArray> data);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheRegExp);
+};
+
// The compilation cache keeps shared function infos for compiled
// scripts and evals. The shared function infos are looked up using
@@ -41,69 +187,98 @@ class CompilationCache {
// Finds the script shared function info for a source
// string. Returns an empty handle if the cache doesn't contain a
// script for the given source string with the right origin.
- static Handle<SharedFunctionInfo> LookupScript(Handle<String> source,
- Handle<Object> name,
- int line_offset,
- int column_offset);
+ Handle<SharedFunctionInfo> LookupScript(Handle<String> source,
+ Handle<Object> name,
+ int line_offset,
+ int column_offset);
// Finds the shared function info for a source string for eval in a
// given context. Returns an empty handle if the cache doesn't
// contain a script for the given source string.
- static Handle<SharedFunctionInfo> LookupEval(Handle<String> source,
- Handle<Context> context,
- bool is_global,
- StrictModeFlag strict_mode);
+ Handle<SharedFunctionInfo> LookupEval(Handle<String> source,
+ Handle<Context> context,
+ bool is_global,
+ StrictModeFlag strict_mode);
// Returns the regexp data associated with the given regexp if it
// is in cache, otherwise an empty handle.
- static Handle<FixedArray> LookupRegExp(Handle<String> source,
- JSRegExp::Flags flags);
+ Handle<FixedArray> LookupRegExp(Handle<String> source,
+ JSRegExp::Flags flags);
// Associate the (source, kind) pair to the shared function
// info. This may overwrite an existing mapping.
- static void PutScript(Handle<String> source,
- Handle<SharedFunctionInfo> function_info);
+ void PutScript(Handle<String> source,
+ Handle<SharedFunctionInfo> function_info);
// Associate the (source, context->closure()->shared(), kind) triple
// with the shared function info. This may overwrite an existing mapping.
- static void PutEval(Handle<String> source,
- Handle<Context> context,
- bool is_global,
- Handle<SharedFunctionInfo> function_info);
+ void PutEval(Handle<String> source,
+ Handle<Context> context,
+ bool is_global,
+ Handle<SharedFunctionInfo> function_info);
// Associate the (source, flags) pair to the given regexp data.
// This may overwrite an existing mapping.
- static void PutRegExp(Handle<String> source,
- JSRegExp::Flags flags,
- Handle<FixedArray> data);
+ void PutRegExp(Handle<String> source,
+ JSRegExp::Flags flags,
+ Handle<FixedArray> data);
// Support for eager optimization tracking.
- static bool ShouldOptimizeEagerly(Handle<JSFunction> function);
- static void MarkForEagerOptimizing(Handle<JSFunction> function);
- static void MarkForLazyOptimizing(Handle<JSFunction> function);
+ bool ShouldOptimizeEagerly(Handle<JSFunction> function);
+ void MarkForEagerOptimizing(Handle<JSFunction> function);
+ void MarkForLazyOptimizing(Handle<JSFunction> function);
// Reset the eager optimization tracking data.
- static void ResetEagerOptimizingData();
+ void ResetEagerOptimizingData();
// Clear the cache - also used to initialize the cache at startup.
- static void Clear();
+ void Clear();
// Remove given shared function info from all caches.
- static void Remove(Handle<SharedFunctionInfo> function_info);
+ void Remove(Handle<SharedFunctionInfo> function_info);
// GC support.
- static void Iterate(ObjectVisitor* v);
- static void IterateFunctions(ObjectVisitor* v);
+ void Iterate(ObjectVisitor* v);
+ void IterateFunctions(ObjectVisitor* v);
// Notify the cache that a mark-sweep garbage collection is about to
// take place. This is used to retire entries from the cache to
// avoid keeping them alive too long without using them.
- static void MarkCompactPrologue();
+ void MarkCompactPrologue();
// Enable/disable compilation cache. Used by debugger to disable compilation
// cache during debugging to make sure new scripts are always compiled.
- static void Enable();
- static void Disable();
+ void Enable();
+ void Disable();
+ private:
+ explicit CompilationCache(Isolate* isolate);
+ ~CompilationCache();
+
+ HashMap* EagerOptimizingSet();
+
+ // The number of sub caches covering the different types to cache.
+ static const int kSubCacheCount = 4;
+
+ bool IsEnabled() { return FLAG_compilation_cache && enabled_; }
+
+ Isolate* isolate() { return isolate_; }
+
+ Isolate* isolate_;
+
+ CompilationCacheScript script_;
+ CompilationCacheEval eval_global_;
+ CompilationCacheEval eval_contextual_;
+ CompilationCacheRegExp reg_exp_;
+ CompilationSubCache* subcaches_[kSubCacheCount];
+
+ // Current enable state of the compilation cache.
+ bool enabled_;
+
+ HashMap* eager_optimizing_set_;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(CompilationCache);
};
diff --git a/src/compiler.cc b/src/compiler.cc
index 667432f2..1ec4414a 100755
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -51,7 +51,8 @@ namespace internal {
CompilationInfo::CompilationInfo(Handle<Script> script)
- : flags_(0),
+ : isolate_(script->GetIsolate()),
+ flags_(0),
function_(NULL),
scope_(NULL),
script_(script),
@@ -64,7 +65,8 @@ CompilationInfo::CompilationInfo(Handle<Script> script)
CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
- : flags_(IsLazy::encode(true)),
+ : isolate_(shared_info->GetIsolate()),
+ flags_(IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
shared_info_(shared_info),
@@ -78,7 +80,8 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
CompilationInfo::CompilationInfo(Handle<JSFunction> closure)
- : flags_(IsLazy::encode(true)),
+ : isolate_(closure->GetIsolate()),
+ flags_(IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
closure_(closure),
@@ -121,10 +124,11 @@ void CompilationInfo::DisableOptimization() {
// break points has actually been set.
static bool AlwaysFullCompiler() {
#ifdef ENABLE_DEBUGGER_SUPPORT
+ Isolate* isolate = Isolate::Current();
if (V8::UseCrankshaft()) {
- return FLAG_always_full_compiler || Debug::has_break_points();
+ return FLAG_always_full_compiler || isolate->debug()->has_break_points();
} else {
- return FLAG_always_full_compiler || Debugger::IsDebuggerActive();
+ return FLAG_always_full_compiler || isolate->debugger()->IsDebuggerActive();
}
#else
return FLAG_always_full_compiler;
@@ -172,6 +176,8 @@ static void AbortAndDisable(CompilationInfo* info) {
ASSERT(code->kind() == Code::FUNCTION);
code->set_optimizable(false);
info->SetCode(code);
+ Isolate* isolate = code->GetIsolate();
+ isolate->compilation_cache()->MarkForLazyOptimizing(info->closure());
if (FLAG_trace_opt) {
PrintF("[disabled optimization for: ");
info->closure()->PrintName();
@@ -197,6 +203,10 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
Handle<Code> code(info->shared_info()->code());
ASSERT(code->kind() == Code::FUNCTION);
+ // We should never arrive here if optimization has been disabled on the
+ // shared function info.
+ ASSERT(!info->shared_info()->optimization_disabled());
+
// Fall back to using the full code generator if it's not possible
// to use the Hydrogen-based optimizing compiler. We already have
// generated code for this from the shared function object.
@@ -248,7 +258,7 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
// performance of the hydrogen-based compiler.
int64_t start = OS::Ticks();
bool should_recompile = !info->shared_info()->has_deoptimization_support();
- if (should_recompile || FLAG_time_hydrogen) {
+ if (should_recompile || FLAG_hydrogen_stats) {
HPhase phase(HPhase::kFullCodeGen);
CompilationInfo unoptimized(info->shared_info());
// Note that we use the same AST that we will use for generating the
@@ -286,7 +296,7 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
HGraphBuilder builder(info, &oracle);
HPhase phase(HPhase::kTotal);
HGraph* graph = builder.CreateGraph();
- if (Top::has_pending_exception()) {
+ if (info->isolate()->has_pending_exception()) {
info->SetCode(Handle<Code>::null());
return false;
}
@@ -364,11 +374,12 @@ bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) {
static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
CompilationZoneScope zone_scope(DELETE_ON_EXIT);
- PostponeInterruptsScope postpone;
+ Isolate* isolate = info->isolate();
+ PostponeInterruptsScope postpone(isolate);
- ASSERT(!i::Top::global_context().is_null());
+ ASSERT(!isolate->global_context().is_null());
Handle<Script> script = info->script();
- script->set_context_data((*i::Top::global_context())->data());
+ script->set_context_data((*isolate->global_context())->data());
#ifdef ENABLE_DEBUGGER_SUPPORT
if (info->is_eval()) {
@@ -381,15 +392,16 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
if (!it.done()) {
script->set_eval_from_shared(
JSFunction::cast(it.frame()->function())->shared());
+ Code* code = it.frame()->LookupCode(isolate);
int offset = static_cast<int>(
- it.frame()->pc() - it.frame()->code()->instruction_start());
+ it.frame()->pc() - code->instruction_start());
script->set_eval_from_instructions_offset(Smi::FromInt(offset));
}
}
}
// Notify debugger
- Debugger::OnBeforeCompile(script);
+ isolate->debugger()->OnBeforeCompile(script);
#endif
// Only allow non-global compiles for eval.
@@ -401,22 +413,22 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
// rest of the function into account to avoid overlap with the
// parsing statistics.
HistogramTimer* rate = info->is_eval()
- ? &Counters::compile_eval
- : &Counters::compile;
+ ? info->isolate()->counters()->compile_eval()
+ : info->isolate()->counters()->compile();
HistogramTimerScope timer(rate);
// Compile the code.
FunctionLiteral* lit = info->function();
- LiveEditFunctionTracker live_edit_tracker(lit);
+ LiveEditFunctionTracker live_edit_tracker(isolate, lit);
if (!MakeCode(info)) {
- Top::StackOverflow();
+ isolate->StackOverflow();
return Handle<SharedFunctionInfo>::null();
}
// Allocate function.
ASSERT(!info->code().is_null());
Handle<SharedFunctionInfo> result =
- Factory::NewSharedFunctionInfo(
+ isolate->factory()->NewSharedFunctionInfo(
lit->name(),
lit->materialized_literal_count(),
info->code(),
@@ -426,7 +438,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
Compiler::SetFunctionInfo(result, lit, true, script);
if (script->name()->IsString()) {
- PROFILE(CodeCreateEvent(
+ PROFILE(isolate, CodeCreateEvent(
info->is_eval()
? Logger::EVAL_TAG
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
@@ -437,13 +449,13 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
script,
info->code()));
} else {
- PROFILE(CodeCreateEvent(
+ PROFILE(isolate, CodeCreateEvent(
info->is_eval()
? Logger::EVAL_TAG
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
*info->code(),
*result,
- Heap::empty_string()));
+ isolate->heap()->empty_string()));
GDBJIT(AddCode(Handle<String>(), script, info->code()));
}
@@ -454,7 +466,8 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Notify debugger
- Debugger::OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS);
+ isolate->debugger()->OnAfterCompile(
+ script, Debugger::NO_AFTER_COMPILE_FLAGS);
#endif
live_edit_tracker.RecordFunctionInfo(result, lit);
@@ -471,20 +484,23 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
ScriptDataImpl* input_pre_data,
Handle<Object> script_data,
NativesFlag natives) {
+ Isolate* isolate = source->GetIsolate();
int source_length = source->length();
- Counters::total_load_size.Increment(source_length);
- Counters::total_compile_size.Increment(source_length);
+ isolate->counters()->total_load_size()->Increment(source_length);
+ isolate->counters()->total_compile_size()->Increment(source_length);
// The VM is in the COMPILER state until exiting this function.
- VMState state(COMPILER);
+ VMState state(isolate, COMPILER);
+
+ CompilationCache* compilation_cache = isolate->compilation_cache();
// Do a lookup in the compilation cache but not for extensions.
Handle<SharedFunctionInfo> result;
if (extension == NULL) {
- result = CompilationCache::LookupScript(source,
- script_name,
- line_offset,
- column_offset);
+ result = compilation_cache->LookupScript(source,
+ script_name,
+ line_offset,
+ column_offset);
}
if (result.is_null()) {
@@ -510,7 +526,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
}
// Create a script object describing the script to be compiled.
- Handle<Script> script = Factory::NewScript(source);
+ Handle<Script> script = FACTORY->NewScript(source);
if (natives == NATIVES_CODE) {
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
}
@@ -520,7 +536,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
script->set_column_offset(Smi::FromInt(column_offset));
}
- script->set_data(script_data.is_null() ? Heap::undefined_value()
+ script->set_data(script_data.is_null() ? HEAP->undefined_value()
: *script_data);
// Compile the function and add it to the cache.
@@ -528,9 +544,10 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
info.MarkAsGlobal();
info.SetExtension(extension);
info.SetPreParseData(pre_data);
+ if (natives == NATIVES_CODE) info.MarkAsAllowingNativesSyntax();
result = MakeFunctionInfo(&info);
if (extension == NULL && !result.is_null()) {
- CompilationCache::PutScript(source, result);
+ compilation_cache->PutScript(source, result);
}
// Get rid of the pre-parsing data (if necessary).
@@ -539,7 +556,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
}
}
- if (result.is_null()) Top::ReportPendingMessages();
+ if (result.is_null()) isolate->ReportPendingMessages();
return result;
}
@@ -548,24 +565,26 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
Handle<Context> context,
bool is_global,
StrictModeFlag strict_mode) {
+ Isolate* isolate = source->GetIsolate();
int source_length = source->length();
- Counters::total_eval_size.Increment(source_length);
- Counters::total_compile_size.Increment(source_length);
+ isolate->counters()->total_eval_size()->Increment(source_length);
+ isolate->counters()->total_compile_size()->Increment(source_length);
// The VM is in the COMPILER state until exiting this function.
- VMState state(COMPILER);
+ VMState state(isolate, COMPILER);
// Do a lookup in the compilation cache; if the entry is not there, invoke
// the compiler and add the result to the cache.
Handle<SharedFunctionInfo> result;
- result = CompilationCache::LookupEval(source,
- context,
- is_global,
- strict_mode);
+ CompilationCache* compilation_cache = isolate->compilation_cache();
+ result = compilation_cache->LookupEval(source,
+ context,
+ is_global,
+ strict_mode);
if (result.is_null()) {
// Create a script object describing the script to be compiled.
- Handle<Script> script = Factory::NewScript(source);
+ Handle<Script> script = isolate->factory()->NewScript(source);
CompilationInfo info(script);
info.MarkAsEval();
if (is_global) info.MarkAsGlobal();
@@ -573,11 +592,12 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
info.SetCallingContext(context);
result = MakeFunctionInfo(&info);
if (!result.is_null()) {
+ CompilationCache* compilation_cache = isolate->compilation_cache();
// If caller is strict mode, the result must be strict as well,
// but not the other way around. Consider:
// eval("'use strict'; ...");
ASSERT(strict_mode == kNonStrictMode || result->strict_mode());
- CompilationCache::PutEval(source, context, is_global, result);
+ compilation_cache->PutEval(source, context, is_global, result);
}
}
@@ -589,29 +609,35 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
CompilationZoneScope zone_scope(DELETE_ON_EXIT);
// The VM is in the COMPILER state until exiting this function.
- VMState state(COMPILER);
+ VMState state(info->isolate(), COMPILER);
- PostponeInterruptsScope postpone;
+ Isolate* isolate = info->isolate();
+ PostponeInterruptsScope postpone(isolate);
Handle<SharedFunctionInfo> shared = info->shared_info();
int compiled_size = shared->end_position() - shared->start_position();
- Counters::total_compile_size.Increment(compiled_size);
+ isolate->counters()->total_compile_size()->Increment(compiled_size);
// Generate the AST for the lazily compiled function.
if (ParserApi::Parse(info)) {
// Measure how long it takes to do the lazy compilation; only take the
// rest of the function into account to avoid overlap with the lazy
// parsing statistics.
- HistogramTimerScope timer(&Counters::compile_lazy);
+ HistogramTimerScope timer(isolate->counters()->compile_lazy());
// Compile the code.
if (!MakeCode(info)) {
- if (!Top::has_pending_exception()) {
- Top::StackOverflow();
+ if (!isolate->has_pending_exception()) {
+ isolate->StackOverflow();
}
} else {
ASSERT(!info->code().is_null());
Handle<Code> code = info->code();
+ // Set optimizable to false if this is disallowed by the shared
+ // function info, e.g., we might have flushed the code and must
+ // reset this bit when lazy compiling the code again.
+ if (shared->optimization_disabled()) code->set_optimizable(false);
+
Handle<JSFunction> function = info->closure();
RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
@@ -648,16 +674,18 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
ASSERT(shared->is_compiled());
shared->set_code_age(0);
- if (V8::UseCrankshaft() && info->AllowOptimize()) {
+ if (info->AllowOptimize() && !shared->optimization_disabled()) {
// If we're asked to always optimize, we compile the optimized
// version of the function right away - unless the debugger is
// active as it makes no sense to compile optimized code then.
- if (FLAG_always_opt && !Debug::has_break_points()) {
+ if (FLAG_always_opt &&
+ !Isolate::Current()->debug()->has_break_points()) {
CompilationInfo optimized(function);
optimized.SetOptimizing(AstNode::kNoNumber);
return CompileLazy(&optimized);
- } else if (CompilationCache::ShouldOptimizeEagerly(function)) {
- RuntimeProfiler::OptimizeSoon(*function);
+ } else if (isolate->compilation_cache()->ShouldOptimizeEagerly(
+ function)) {
+ isolate->runtime_profiler()->OptimizeSoon(*function);
}
}
}
@@ -678,20 +706,20 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
info.SetFunction(literal);
info.SetScope(literal->scope());
- LiveEditFunctionTracker live_edit_tracker(literal);
+ LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal);
// Determine if the function can be lazily compiled. This is necessary to
// allow some of our builtin JS files to be lazily compiled. These
// builtins cannot be handled lazily by the parser, since we have to know
// if a function uses the special natives syntax, which is something the
// parser records.
bool allow_lazy = literal->AllowsLazyCompilation() &&
- !LiveEditFunctionTracker::IsActive();
+ !LiveEditFunctionTracker::IsActive(info.isolate());
Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
// Generate code
if (FLAG_lazy && allow_lazy) {
- Handle<Code> code(Builtins::builtin(Builtins::LazyCompile));
+ Handle<Code> code = info.isolate()->builtins()->LazyCompile();
info.SetCode(code);
} else {
if (V8::UseCrankshaft()) {
@@ -726,7 +754,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
// Create a shared function info object.
Handle<SharedFunctionInfo> result =
- Factory::NewSharedFunctionInfo(literal->name(),
+ FACTORY->NewSharedFunctionInfo(literal->name(),
literal->materialized_literal_count(),
info.code(),
scope_info);
@@ -778,20 +806,23 @@ void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
// Log the code generation. If source information is available include
// script name and line number. Check explicitly whether logging is
// enabled as finding the line number is not free.
- if (Logger::is_logging() || CpuProfiler::is_profiling()) {
+ if (info->isolate()->logger()->is_logging() || CpuProfiler::is_profiling()) {
Handle<Script> script = info->script();
Handle<Code> code = info->code();
- if (*code == Builtins::builtin(Builtins::LazyCompile)) return;
+ if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile))
+ return;
if (script->name()->IsString()) {
int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
USE(line_num);
- PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
+ PROFILE(info->isolate(),
+ CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
*code,
*shared,
String::cast(script->name()),
line_num));
} else {
- PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
+ PROFILE(info->isolate(),
+ CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
*code,
*shared,
shared->DebugName()));
diff --git a/src/compiler.h b/src/compiler.h
index e0a437ac..a66c5401 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -46,6 +46,10 @@ class CompilationInfo BASE_EMBEDDED {
explicit CompilationInfo(Handle<SharedFunctionInfo> shared_info);
explicit CompilationInfo(Handle<JSFunction> closure);
+ Isolate* isolate() {
+ ASSERT(Isolate::Current() == isolate_);
+ return isolate_;
+ }
bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; }
bool is_eval() const { return (flags_ & IsEval::mask()) != 0; }
bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
@@ -80,6 +84,12 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(is_lazy());
flags_ |= IsInLoop::encode(true);
}
+ void MarkAsAllowingNativesSyntax() {
+ flags_ |= IsNativesSyntaxAllowed::encode(true);
+ }
+ bool allows_natives_syntax() const {
+ return IsNativesSyntaxAllowed::decode(flags_);
+ }
void SetFunction(FunctionLiteral* literal) {
ASSERT(function_ == NULL);
function_ = literal;
@@ -136,6 +146,8 @@ class CompilationInfo BASE_EMBEDDED {
}
private:
+ Isolate* isolate_;
+
// Compilation mode.
// BASE is generated by the full codegen, optionally prepared for bailouts.
// OPTIMIZE is optimized code generated by the Hydrogen-based backend.
@@ -174,6 +186,8 @@ class CompilationInfo BASE_EMBEDDED {
class IsInLoop: public BitField<bool, 3, 1> {};
// Strict mode - used in eager compilation.
class IsStrict: public BitField<bool, 4, 1> {};
+ // Native syntax (%-stuff) allowed?
+ class IsNativesSyntaxAllowed: public BitField<bool, 5, 1> {};
unsigned flags_;
@@ -278,8 +292,9 @@ class CompilationZoneScope : public ZoneScope {
explicit CompilationZoneScope(ZoneScopeMode mode) : ZoneScope(mode) { }
virtual ~CompilationZoneScope() {
if (ShouldDeleteOnExit()) {
- FrameElement::ClearConstantList();
- Result::ClearConstantList();
+ Isolate* isolate = Isolate::Current();
+ isolate->frame_element_constant_list()->Clear();
+ isolate->result_constant_list()->Clear();
}
}
};
diff --git a/src/contexts.cc b/src/contexts.cc
index 3ad72a16..520f3dde 100644
--- a/src/contexts.cc
+++ b/src/contexts.cc
@@ -55,7 +55,7 @@ Context* Context::global_context() {
// During bootstrapping, the global object might not be set and we
// have to search the context chain to find the global context.
- ASSERT(Bootstrapper::IsActive());
+ ASSERT(Isolate::Current()->bootstrapper()->IsActive());
Context* current = this;
while (!current->IsGlobalContext()) {
JSFunction* closure = JSFunction::cast(current->closure());
@@ -76,7 +76,8 @@ void Context::set_global_proxy(JSObject* object) {
Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
int* index_, PropertyAttributes* attributes) {
- Handle<Context> context(this);
+ Isolate* isolate = GetIsolate();
+ Handle<Context> context(this, isolate);
bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
*index_ = -1;
@@ -97,7 +98,8 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
// check extension/with object
if (context->has_extension()) {
- Handle<JSObject> extension = Handle<JSObject>(context->extension());
+ Handle<JSObject> extension = Handle<JSObject>(context->extension(),
+ isolate);
// Context extension objects needs to behave as if they have no
// prototype. So even if we want to follow prototype chains, we
// need to only do a local lookup for context extension objects.
@@ -122,7 +124,7 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
// check non-parameter locals in context
Handle<SerializedScopeInfo> scope_info(
- context->closure()->shared()->scope_info());
+ context->closure()->shared()->scope_info(), isolate);
Variable::Mode mode;
int index = scope_info->ContextSlotIndex(*name, &mode);
ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
@@ -155,11 +157,12 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
int param_index = scope_info->ParameterIndex(*name);
if (param_index >= 0) {
// slot found.
- int index =
- scope_info->ContextSlotIndex(Heap::arguments_shadow_symbol(), NULL);
+ int index = scope_info->ContextSlotIndex(
+ isolate->heap()->arguments_shadow_symbol(), NULL);
ASSERT(index >= 0); // arguments must exist and be in the heap context
- Handle<JSObject> arguments(JSObject::cast(context->get(index)));
- ASSERT(arguments->HasLocalProperty(Heap::length_symbol()));
+ Handle<JSObject> arguments(JSObject::cast(context->get(index)),
+ isolate);
+ ASSERT(arguments->HasLocalProperty(isolate->heap()->length_symbol()));
if (FLAG_trace_contexts) {
PrintF("=> found parameter %d in arguments object\n", param_index);
}
@@ -188,9 +191,10 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
if (context->IsGlobalContext()) {
follow_context_chain = false;
} else if (context->is_function_context()) {
- context = Handle<Context>(Context::cast(context->closure()->context()));
+ context = Handle<Context>(Context::cast(context->closure()->context()),
+ isolate);
} else {
- context = Handle<Context>(context->previous());
+ context = Handle<Context>(context->previous(), isolate);
}
} while (follow_context_chain);
@@ -252,7 +256,7 @@ void Context::AddOptimizedFunction(JSFunction* function) {
// Check that the context belongs to the weak global contexts list.
bool found = false;
- Object* context = Heap::global_contexts_list();
+ Object* context = GetHeap()->global_contexts_list();
while (!context->IsUndefined()) {
if (context == this) {
found = true;
@@ -281,7 +285,7 @@ void Context::RemoveOptimizedFunction(JSFunction* function) {
} else {
prev->set_next_function_link(element_function->next_function_link());
}
- element_function->set_next_function_link(Heap::undefined_value());
+ element_function->set_next_function_link(GetHeap()->undefined_value());
return;
}
prev = element_function;
@@ -298,7 +302,7 @@ Object* Context::OptimizedFunctionsListHead() {
void Context::ClearOptimizedFunctions() {
- set(OPTIMIZED_FUNCTIONS_LIST, Heap::undefined_value());
+ set(OPTIMIZED_FUNCTIONS_LIST, GetHeap()->undefined_value());
}
@@ -306,14 +310,17 @@ void Context::ClearOptimizedFunctions() {
bool Context::IsBootstrappingOrContext(Object* object) {
// During bootstrapping we allow all objects to pass as
// contexts. This is necessary to fix circular dependencies.
- return Bootstrapper::IsActive() || object->IsContext();
+ return Isolate::Current()->bootstrapper()->IsActive() || object->IsContext();
}
bool Context::IsBootstrappingOrGlobalObject(Object* object) {
// During bootstrapping we allow all objects to pass as global
// objects. This is necessary to fix circular dependencies.
- return Bootstrapper::IsActive() || object->IsGlobalObject();
+ Isolate* isolate = Isolate::Current();
+ return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
+ isolate->bootstrapper()->IsActive() ||
+ object->IsGlobalObject();
}
#endif
diff --git a/src/contexts.h b/src/contexts.h
index d0d54d1b..e46619ec 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -78,11 +78,18 @@ enum ContextLookupFlags {
V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun) \
V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun) \
V(FUNCTION_MAP_INDEX, Map, function_map) \
+ V(STRICT_MODE_FUNCTION_MAP_INDEX, Map, strict_mode_function_map) \
V(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, function_without_prototype_map) \
+ V(STRICT_MODE_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \
+ strict_mode_function_without_prototype_map) \
V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \
+ V(STRICT_MODE_FUNCTION_INSTANCE_MAP_INDEX, Map, \
+ strict_mode_function_instance_map) \
V(JS_ARRAY_MAP_INDEX, Map, js_array_map)\
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map)\
V(ARGUMENTS_BOILERPLATE_INDEX, JSObject, arguments_boilerplate) \
+ V(STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX, JSObject, \
+ strict_mode_arguments_boilerplate) \
V(MESSAGE_LISTENERS_INDEX, JSObject, message_listeners) \
V(MAKE_MESSAGE_FUN_INDEX, JSFunction, make_message_fun) \
V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
@@ -182,11 +189,15 @@ class Context: public FixedArray {
GLOBAL_PROXY_INDEX = MIN_CONTEXT_SLOTS,
SECURITY_TOKEN_INDEX,
ARGUMENTS_BOILERPLATE_INDEX,
+ STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX,
JS_ARRAY_MAP_INDEX,
REGEXP_RESULT_MAP_INDEX,
FUNCTION_MAP_INDEX,
+ STRICT_MODE_FUNCTION_MAP_INDEX,
FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
+ STRICT_MODE_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
FUNCTION_INSTANCE_MAP_INDEX,
+ STRICT_MODE_FUNCTION_INSTANCE_MAP_INDEX,
INITIAL_OBJECT_PROTOTYPE_INDEX,
BOOLEAN_FUNCTION_INDEX,
NUMBER_FUNCTION_INDEX,
@@ -257,8 +268,7 @@ class Context: public FixedArray {
GlobalObject* global() {
Object* result = get(GLOBAL_INDEX);
- ASSERT(Heap::gc_state() != Heap::NOT_IN_GC ||
- IsBootstrappingOrGlobalObject(result));
+ ASSERT(IsBootstrappingOrGlobalObject(result));
return reinterpret_cast<GlobalObject*>(result);
}
void set_global(GlobalObject* global) { set(GLOBAL_INDEX, global); }
@@ -277,14 +287,10 @@ class Context: public FixedArray {
bool is_function_context() { return unchecked_previous() == NULL; }
// Tells whether the global context is marked with out of memory.
- bool has_out_of_memory() {
- return global_context()->out_of_memory() == Heap::true_value();
- }
+ inline bool has_out_of_memory();
// Mark the global context with out of memory.
- void mark_out_of_memory() {
- global_context()->set_out_of_memory(Heap::true_value());
- }
+ inline void mark_out_of_memory();
// The exception holder is the object used as a with object in
// the implementation of a catch block.
diff --git a/src/conversions.cc b/src/conversions.cc
index a348235d..c3d7bdfa 100644
--- a/src/conversions.cc
+++ b/src/conversions.cc
@@ -109,9 +109,11 @@ static const double JUNK_STRING_VALUE = OS::nan_value();
// Returns true if a nonspace found and false if the end has reached.
template <class Iterator, class EndMark>
-static inline bool AdvanceToNonspace(Iterator* current, EndMark end) {
+static inline bool AdvanceToNonspace(ScannerConstants* scanner_constants,
+ Iterator* current,
+ EndMark end) {
while (*current != end) {
- if (!ScannerConstants::kIsWhiteSpace.get(**current)) return true;
+ if (!scanner_constants->IsWhiteSpace(**current)) return true;
++*current;
}
return false;
@@ -132,7 +134,8 @@ static double SignedZero(bool negative) {
// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
template <int radix_log_2, class Iterator, class EndMark>
-static double InternalStringToIntDouble(Iterator current,
+static double InternalStringToIntDouble(ScannerConstants* scanner_constants,
+ Iterator current,
EndMark end,
bool negative,
bool allow_trailing_junk) {
@@ -157,7 +160,8 @@ static double InternalStringToIntDouble(Iterator current,
} else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) {
digit = static_cast<char>(*current) - 'A' + 10;
} else {
- if (allow_trailing_junk || !AdvanceToNonspace(&current, end)) {
+ if (allow_trailing_junk ||
+ !AdvanceToNonspace(scanner_constants, &current, end)) {
break;
} else {
return JUNK_STRING_VALUE;
@@ -188,7 +192,8 @@ static double InternalStringToIntDouble(Iterator current,
exponent += radix_log_2;
}
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ if (!allow_trailing_junk &&
+ AdvanceToNonspace(scanner_constants, &current, end)) {
return JUNK_STRING_VALUE;
}
@@ -232,11 +237,16 @@ static double InternalStringToIntDouble(Iterator current,
template <class Iterator, class EndMark>
-static double InternalStringToInt(Iterator current, EndMark end, int radix) {
+static double InternalStringToInt(ScannerConstants* scanner_constants,
+ Iterator current,
+ EndMark end,
+ int radix) {
const bool allow_trailing_junk = true;
const double empty_string_val = JUNK_STRING_VALUE;
- if (!AdvanceToNonspace(&current, end)) return empty_string_val;
+ if (!AdvanceToNonspace(scanner_constants, &current, end)) {
+ return empty_string_val;
+ }
bool negative = false;
bool leading_zero = false;
@@ -244,10 +254,14 @@ static double InternalStringToInt(Iterator current, EndMark end, int radix) {
if (*current == '+') {
// Ignore leading sign; skip following spaces.
++current;
- if (!AdvanceToNonspace(&current, end)) return JUNK_STRING_VALUE;
+ if (!AdvanceToNonspace(scanner_constants, &current, end)) {
+ return JUNK_STRING_VALUE;
+ }
} else if (*current == '-') {
++current;
- if (!AdvanceToNonspace(&current, end)) return JUNK_STRING_VALUE;
+ if (!AdvanceToNonspace(scanner_constants, &current, end)) {
+ return JUNK_STRING_VALUE;
+ }
negative = true;
}
@@ -298,21 +312,21 @@ static double InternalStringToInt(Iterator current, EndMark end, int radix) {
switch (radix) {
case 2:
return InternalStringToIntDouble<1>(
- current, end, negative, allow_trailing_junk);
+ scanner_constants, current, end, negative, allow_trailing_junk);
case 4:
return InternalStringToIntDouble<2>(
- current, end, negative, allow_trailing_junk);
+ scanner_constants, current, end, negative, allow_trailing_junk);
case 8:
return InternalStringToIntDouble<3>(
- current, end, negative, allow_trailing_junk);
+ scanner_constants, current, end, negative, allow_trailing_junk);
case 16:
return InternalStringToIntDouble<4>(
- current, end, negative, allow_trailing_junk);
+ scanner_constants, current, end, negative, allow_trailing_junk);
case 32:
return InternalStringToIntDouble<5>(
- current, end, negative, allow_trailing_junk);
+ scanner_constants, current, end, negative, allow_trailing_junk);
default:
UNREACHABLE();
}
@@ -337,7 +351,8 @@ static double InternalStringToInt(Iterator current, EndMark end, int radix) {
if (current == end) break;
}
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ if (!allow_trailing_junk &&
+ AdvanceToNonspace(scanner_constants, &current, end)) {
return JUNK_STRING_VALUE;
}
@@ -402,7 +417,8 @@ static double InternalStringToInt(Iterator current, EndMark end, int radix) {
v = v * multiplier + part;
} while (!done);
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ if (!allow_trailing_junk &&
+ AdvanceToNonspace(scanner_constants, &current, end)) {
return JUNK_STRING_VALUE;
}
@@ -416,7 +432,8 @@ static double InternalStringToInt(Iterator current, EndMark end, int radix) {
// 2. *current - gets the current character in the sequence.
// 3. ++current (advances the position).
template <class Iterator, class EndMark>
-static double InternalStringToDouble(Iterator current,
+static double InternalStringToDouble(ScannerConstants* scanner_constants,
+ Iterator current,
EndMark end,
int flags,
double empty_string_val) {
@@ -428,7 +445,9 @@ static double InternalStringToDouble(Iterator current,
// 'parsing_done'.
// 4. 'current' is not dereferenced after the 'parsing_done' label.
// 5. Code before 'parsing_done' may rely on 'current != end'.
- if (!AdvanceToNonspace(&current, end)) return empty_string_val;
+ if (!AdvanceToNonspace(scanner_constants, &current, end)) {
+ return empty_string_val;
+ }
const bool allow_trailing_junk = (flags & ALLOW_TRAILING_JUNK) != 0;
@@ -463,7 +482,8 @@ static double InternalStringToDouble(Iterator current,
return JUNK_STRING_VALUE;
}
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ if (!allow_trailing_junk &&
+ AdvanceToNonspace(scanner_constants, &current, end)) {
return JUNK_STRING_VALUE;
}
@@ -485,7 +505,8 @@ static double InternalStringToDouble(Iterator current,
return JUNK_STRING_VALUE; // "0x".
}
- return InternalStringToIntDouble<4>(current,
+ return InternalStringToIntDouble<4>(scanner_constants,
+ current,
end,
negative,
allow_trailing_junk);
@@ -621,7 +642,8 @@ static double InternalStringToDouble(Iterator current,
exponent += (sign == '-' ? -num : num);
}
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ if (!allow_trailing_junk &&
+ AdvanceToNonspace(scanner_constants, &current, end)) {
return JUNK_STRING_VALUE;
}
@@ -629,7 +651,8 @@ static double InternalStringToDouble(Iterator current,
exponent += insignificant_digits;
if (octal) {
- return InternalStringToIntDouble<3>(buffer,
+ return InternalStringToIntDouble<3>(scanner_constants,
+ buffer,
buffer + buffer_pos,
negative,
allow_trailing_junk);
@@ -649,18 +672,23 @@ static double InternalStringToDouble(Iterator current,
double StringToDouble(String* str, int flags, double empty_string_val) {
+ ScannerConstants* scanner_constants =
+ Isolate::Current()->scanner_constants();
StringShape shape(str);
if (shape.IsSequentialAscii()) {
const char* begin = SeqAsciiString::cast(str)->GetChars();
const char* end = begin + str->length();
- return InternalStringToDouble(begin, end, flags, empty_string_val);
+ return InternalStringToDouble(scanner_constants, begin, end, flags,
+ empty_string_val);
} else if (shape.IsSequentialTwoByte()) {
const uc16* begin = SeqTwoByteString::cast(str)->GetChars();
const uc16* end = begin + str->length();
- return InternalStringToDouble(begin, end, flags, empty_string_val);
+ return InternalStringToDouble(scanner_constants, begin, end, flags,
+ empty_string_val);
} else {
StringInputBuffer buffer(str);
- return InternalStringToDouble(StringInputBufferIterator(&buffer),
+ return InternalStringToDouble(scanner_constants,
+ StringInputBufferIterator(&buffer),
StringInputBufferIterator::EndMarker(),
flags,
empty_string_val);
@@ -669,18 +697,21 @@ double StringToDouble(String* str, int flags, double empty_string_val) {
double StringToInt(String* str, int radix) {
+ ScannerConstants* scanner_constants =
+ Isolate::Current()->scanner_constants();
StringShape shape(str);
if (shape.IsSequentialAscii()) {
const char* begin = SeqAsciiString::cast(str)->GetChars();
const char* end = begin + str->length();
- return InternalStringToInt(begin, end, radix);
+ return InternalStringToInt(scanner_constants, begin, end, radix);
} else if (shape.IsSequentialTwoByte()) {
const uc16* begin = SeqTwoByteString::cast(str)->GetChars();
const uc16* end = begin + str->length();
- return InternalStringToInt(begin, end, radix);
+ return InternalStringToInt(scanner_constants, begin, end, radix);
} else {
StringInputBuffer buffer(str);
- return InternalStringToInt(StringInputBufferIterator(&buffer),
+ return InternalStringToInt(scanner_constants,
+ StringInputBufferIterator(&buffer),
StringInputBufferIterator::EndMarker(),
radix);
}
@@ -688,16 +719,22 @@ double StringToInt(String* str, int radix) {
double StringToDouble(const char* str, int flags, double empty_string_val) {
+ ScannerConstants* scanner_constants =
+ Isolate::Current()->scanner_constants();
const char* end = str + StrLength(str);
- return InternalStringToDouble(str, end, flags, empty_string_val);
+ return InternalStringToDouble(scanner_constants, str, end, flags,
+ empty_string_val);
}
double StringToDouble(Vector<const char> str,
int flags,
double empty_string_val) {
+ ScannerConstants* scanner_constants =
+ Isolate::Current()->scanner_constants();
const char* end = str.start() + str.length();
- return InternalStringToDouble(str.start(), end, flags, empty_string_val);
+ return InternalStringToDouble(scanner_constants, str.start(), end, flags,
+ empty_string_val);
}
@@ -1066,4 +1103,23 @@ char* DoubleToRadixCString(double value, int radix) {
}
+static Mutex* dtoa_lock_one = OS::CreateMutex();
+static Mutex* dtoa_lock_zero = OS::CreateMutex();
+
+
} } // namespace v8::internal
+
+
+extern "C" {
+void ACQUIRE_DTOA_LOCK(int n) {
+ ASSERT(n == 0 || n == 1);
+ (n == 0 ? v8::internal::dtoa_lock_zero : v8::internal::dtoa_lock_one)->Lock();
+}
+
+
+void FREE_DTOA_LOCK(int n) {
+ ASSERT(n == 0 || n == 1);
+ (n == 0 ? v8::internal::dtoa_lock_zero : v8::internal::dtoa_lock_one)->
+ Unlock();
+}
+}
diff --git a/src/counters.cc b/src/counters.cc
index 239a5f7a..faad6d40 100644
--- a/src/counters.cc
+++ b/src/counters.cc
@@ -28,14 +28,22 @@
#include "v8.h"
#include "counters.h"
+#include "isolate.h"
#include "platform.h"
namespace v8 {
namespace internal {
-CounterLookupCallback StatsTable::lookup_function_ = NULL;
-CreateHistogramCallback StatsTable::create_histogram_function_ = NULL;
-AddHistogramSampleCallback StatsTable::add_histogram_sample_function_ = NULL;
+StatsTable::StatsTable()
+ : lookup_function_(NULL),
+ create_histogram_function_(NULL),
+ add_histogram_sample_function_(NULL) {}
+
+
+int* StatsCounter::FindLocationInStatsTable() const {
+ return Isolate::Current()->stats_table()->FindLocation(name_);
+}
+
// Start the timer.
void StatsCounterTimer::Start() {
@@ -71,8 +79,15 @@ void HistogramTimer::Stop() {
// Compute the delta between start and stop, in milliseconds.
int milliseconds = static_cast<int>(stop_time_ - start_time_) / 1000;
- StatsTable::AddHistogramSample(histogram_, milliseconds);
+ Isolate::Current()->stats_table()->
+ AddHistogramSample(histogram_, milliseconds);
}
}
+
+void* HistogramTimer::CreateHistogram() const {
+ return Isolate::Current()->stats_table()->
+ CreateHistogram(name_, 0, 10000, 50);
+}
+
} } // namespace v8::internal
diff --git a/src/counters.h b/src/counters.h
index 048fdaab..6498a024 100644
--- a/src/counters.h
+++ b/src/counters.h
@@ -38,27 +38,27 @@ namespace internal {
// counters for monitoring. Counters can be looked up and
// manipulated by name.
-class StatsTable : public AllStatic {
+class StatsTable {
public:
// Register an application-defined function where
// counters can be looked up.
- static void SetCounterFunction(CounterLookupCallback f) {
+ void SetCounterFunction(CounterLookupCallback f) {
lookup_function_ = f;
}
// Register an application-defined function to create
// a histogram for passing to the AddHistogramSample function
- static void SetCreateHistogramFunction(CreateHistogramCallback f) {
+ void SetCreateHistogramFunction(CreateHistogramCallback f) {
create_histogram_function_ = f;
}
// Register an application-defined function to add a sample
// to a histogram created with CreateHistogram function
- static void SetAddHistogramSampleFunction(AddHistogramSampleCallback f) {
+ void SetAddHistogramSampleFunction(AddHistogramSampleCallback f) {
add_histogram_sample_function_ = f;
}
- static bool HasCounterFunction() {
+ bool HasCounterFunction() const {
return lookup_function_ != NULL;
}
@@ -68,7 +68,7 @@ class StatsTable : public AllStatic {
// may receive a different location to store it's counter.
// The return value must not be cached and re-used across
// threads, although a single thread is free to cache it.
- static int* FindLocation(const char* name) {
+ int* FindLocation(const char* name) {
if (!lookup_function_) return NULL;
return lookup_function_(name);
}
@@ -78,25 +78,31 @@ class StatsTable : public AllStatic {
// function. min and max define the expected minimum and maximum
// sample values. buckets is the maximum number of buckets
// that the samples will be grouped into.
- static void* CreateHistogram(const char* name,
- int min,
- int max,
- size_t buckets) {
+ void* CreateHistogram(const char* name,
+ int min,
+ int max,
+ size_t buckets) {
if (!create_histogram_function_) return NULL;
return create_histogram_function_(name, min, max, buckets);
}
// Add a sample to a histogram created with the CreateHistogram
// function.
- static void AddHistogramSample(void* histogram, int sample) {
+ void AddHistogramSample(void* histogram, int sample) {
if (!add_histogram_sample_function_) return;
return add_histogram_sample_function_(histogram, sample);
}
private:
- static CounterLookupCallback lookup_function_;
- static CreateHistogramCallback create_histogram_function_;
- static AddHistogramSampleCallback add_histogram_sample_function_;
+ StatsTable();
+
+ CounterLookupCallback lookup_function_;
+ CreateHistogramCallback create_histogram_function_;
+ AddHistogramSampleCallback add_histogram_sample_function_;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(StatsTable);
};
// StatsCounters are dynamically created values which can be tracked in
@@ -166,9 +172,12 @@ struct StatsCounter {
if (lookup_done_)
return ptr_;
lookup_done_ = true;
- ptr_ = StatsTable::FindLocation(name_);
+ ptr_ = FindLocationInStatsTable();
return ptr_;
}
+
+ private:
+ int* FindLocationInStatsTable() const;
};
// StatsCounterTimer t = { { L"t:foo", NULL, false }, 0, 0 };
@@ -216,10 +225,13 @@ struct HistogramTimer {
void* GetHistogram() {
if (!lookup_done_) {
lookup_done_ = true;
- histogram_ = StatsTable::CreateHistogram(name_, 0, 10000, 50);
+ histogram_ = CreateHistogram();
}
return histogram_;
}
+
+ private:
+ void* CreateHistogram() const;
};
// Helper class for scoping a HistogramTimer.
diff --git a/src/cpu-profiler-inl.h b/src/cpu-profiler-inl.h
index 440dedca..a7fffe00 100644
--- a/src/cpu-profiler-inl.h
+++ b/src/cpu-profiler-inl.h
@@ -41,8 +41,8 @@ namespace internal {
void CodeCreateEventRecord::UpdateCodeMap(CodeMap* code_map) {
code_map->AddCode(start, entry, size);
- if (sfi_address != NULL) {
- entry->set_shared_id(code_map->GetSFITag(sfi_address));
+ if (shared != NULL) {
+ entry->set_shared_id(code_map->GetSharedId(shared));
}
}
@@ -57,7 +57,7 @@ void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) {
}
-void SFIMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
+void SharedFunctionInfoMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
code_map->MoveCode(from, to);
}
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index ad04a003..ef519504 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -46,8 +46,9 @@ static const int kTickSamplesBufferChunkSize = 64*KB;
static const int kTickSamplesBufferChunksCount = 16;
-ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
- : Thread("v8:ProfEvntProc"),
+ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate,
+ ProfileGenerator* generator)
+ : Thread(isolate, "v8:ProfEvntProc"),
generator_(generator),
running_(true),
ticks_buffer_(sizeof(TickSampleEventRecord),
@@ -69,7 +70,7 @@ void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
rec->start = start;
rec->entry = generator_->NewCodeEntry(tag, prefix, name);
rec->size = 1;
- rec->sfi_address = NULL;
+ rec->shared = NULL;
events_buffer_.Enqueue(evt_rec);
}
@@ -80,7 +81,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
int line_number,
Address start,
unsigned size,
- Address sfi_address) {
+ Address shared) {
if (FilterOutCodeCreateEvent(tag)) return;
CodeEventsContainer evt_rec;
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
@@ -89,7 +90,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
rec->start = start;
rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number);
rec->size = size;
- rec->sfi_address = sfi_address;
+ rec->shared = shared;
events_buffer_.Enqueue(evt_rec);
}
@@ -106,7 +107,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
rec->start = start;
rec->entry = generator_->NewCodeEntry(tag, name);
rec->size = size;
- rec->sfi_address = NULL;
+ rec->shared = NULL;
events_buffer_.Enqueue(evt_rec);
}
@@ -123,7 +124,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
rec->start = start;
rec->entry = generator_->NewCodeEntry(tag, args_count);
rec->size = size;
- rec->sfi_address = NULL;
+ rec->shared = NULL;
events_buffer_.Enqueue(evt_rec);
}
@@ -149,10 +150,12 @@ void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
}
-void ProfilerEventsProcessor::SFIMoveEvent(Address from, Address to) {
+void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from,
+ Address to) {
CodeEventsContainer evt_rec;
- SFIMoveEventRecord* rec = &evt_rec.SFIMoveEventRecord_;
- rec->type = CodeEventRecord::SFI_MOVE;
+ SharedFunctionInfoMoveEventRecord* rec =
+ &evt_rec.SharedFunctionInfoMoveEventRecord_;
+ rec->type = CodeEventRecord::SHARED_FUNC_MOVE;
rec->order = ++enqueue_order_;
rec->from = from;
rec->to = to;
@@ -181,7 +184,7 @@ void ProfilerEventsProcessor::RegExpCodeCreateEvent(
void ProfilerEventsProcessor::AddCurrentStack() {
TickSampleEventRecord record;
TickSample* sample = &record.sample;
- sample->state = Top::current_vm_state();
+ sample->state = Isolate::Current()->current_vm_state();
sample->pc = reinterpret_cast<Address>(sample); // Not NULL.
sample->tos = NULL;
sample->frames_count = 0;
@@ -270,82 +273,106 @@ void ProfilerEventsProcessor::Run() {
}
-CpuProfiler* CpuProfiler::singleton_ = NULL;
-Atomic32 CpuProfiler::is_profiling_ = false;
-
void CpuProfiler::StartProfiling(const char* title) {
- ASSERT(singleton_ != NULL);
- singleton_->StartCollectingProfile(title);
+ ASSERT(Isolate::Current()->cpu_profiler() != NULL);
+ Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
}
void CpuProfiler::StartProfiling(String* title) {
- ASSERT(singleton_ != NULL);
- singleton_->StartCollectingProfile(title);
+ ASSERT(Isolate::Current()->cpu_profiler() != NULL);
+ Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
}
CpuProfile* CpuProfiler::StopProfiling(const char* title) {
- return is_profiling() ? singleton_->StopCollectingProfile(title) : NULL;
+ return is_profiling() ?
+ Isolate::Current()->cpu_profiler()->StopCollectingProfile(title) : NULL;
}
CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
return is_profiling() ?
- singleton_->StopCollectingProfile(security_token, title) : NULL;
+ Isolate::Current()->cpu_profiler()->StopCollectingProfile(
+ security_token, title) : NULL;
}
int CpuProfiler::GetProfilesCount() {
- ASSERT(singleton_ != NULL);
+ ASSERT(Isolate::Current()->cpu_profiler() != NULL);
// The count of profiles doesn't depend on a security token.
- return singleton_->profiles_->Profiles(
+ return Isolate::Current()->cpu_profiler()->profiles_->Profiles(
TokenEnumerator::kNoSecurityToken)->length();
}
CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
- ASSERT(singleton_ != NULL);
- const int token = singleton_->token_enumerator_->GetTokenId(security_token);
- return singleton_->profiles_->Profiles(token)->at(index);
+ ASSERT(Isolate::Current()->cpu_profiler() != NULL);
+ CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
+ const int token = profiler->token_enumerator_->GetTokenId(security_token);
+ return profiler->profiles_->Profiles(token)->at(index);
}
CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) {
- ASSERT(singleton_ != NULL);
- const int token = singleton_->token_enumerator_->GetTokenId(security_token);
- return singleton_->profiles_->GetProfile(token, uid);
+ ASSERT(Isolate::Current()->cpu_profiler() != NULL);
+ CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
+ const int token = profiler->token_enumerator_->GetTokenId(security_token);
+ return profiler->profiles_->GetProfile(token, uid);
}
-TickSample* CpuProfiler::TickSampleEvent() {
- if (CpuProfiler::is_profiling()) {
- return singleton_->processor_->TickSampleEvent();
+TickSample* CpuProfiler::TickSampleEvent(Isolate* isolate) {
+ if (CpuProfiler::is_profiling(isolate)) {
+ return isolate->cpu_profiler()->processor_->TickSampleEvent();
} else {
return NULL;
}
}
+void CpuProfiler::DeleteAllProfiles() {
+ Isolate* isolate = Isolate::Current();
+ ASSERT(isolate->cpu_profiler() != NULL);
+ if (is_profiling())
+ isolate->cpu_profiler()->StopProcessor();
+ isolate->cpu_profiler()->ResetProfiles();
+}
+
+
+void CpuProfiler::DeleteProfile(CpuProfile* profile) {
+ ASSERT(Isolate::Current()->cpu_profiler() != NULL);
+ Isolate::Current()->cpu_profiler()->profiles_->RemoveProfile(profile);
+ delete profile;
+}
+
+
+bool CpuProfiler::HasDetachedProfiles() {
+ ASSERT(Isolate::Current()->cpu_profiler() != NULL);
+ return Isolate::Current()->cpu_profiler()->profiles_->HasDetachedProfiles();
+}
+
+
void CpuProfiler::CallbackEvent(String* name, Address entry_point) {
- singleton_->processor_->CallbackCreateEvent(
+ Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
}
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, const char* comment) {
- singleton_->processor_->CodeCreateEvent(
+ Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
tag, comment, code->address(), code->ExecutableSize());
}
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, String* name) {
- singleton_->processor_->CodeCreateEvent(
+ Isolate* isolate = Isolate::Current();
+ isolate->cpu_profiler()->processor_->CodeCreateEvent(
tag,
name,
- Heap::empty_string(),
+ isolate->heap()->empty_string(),
v8::CpuProfileNode::kNoLineNumberInfo,
code->address(),
code->ExecutableSize(),
@@ -357,10 +384,11 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
String* name) {
- singleton_->processor_->CodeCreateEvent(
+ Isolate* isolate = Isolate::Current();
+ isolate->cpu_profiler()->processor_->CodeCreateEvent(
tag,
name,
- Heap::empty_string(),
+ isolate->heap()->empty_string(),
v8::CpuProfileNode::kNoLineNumberInfo,
code->address(),
code->ExecutableSize(),
@@ -372,7 +400,7 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code,
SharedFunctionInfo* shared,
String* source, int line) {
- singleton_->processor_->CodeCreateEvent(
+ Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
tag,
shared->DebugName(),
source,
@@ -385,7 +413,7 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
Code* code, int args_count) {
- singleton_->processor_->CodeCreateEvent(
+ Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
tag,
args_count,
code->address(),
@@ -394,28 +422,29 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
void CpuProfiler::CodeMoveEvent(Address from, Address to) {
- singleton_->processor_->CodeMoveEvent(from, to);
+ Isolate::Current()->cpu_profiler()->processor_->CodeMoveEvent(from, to);
}
void CpuProfiler::CodeDeleteEvent(Address from) {
- singleton_->processor_->CodeDeleteEvent(from);
+ Isolate::Current()->cpu_profiler()->processor_->CodeDeleteEvent(from);
}
-void CpuProfiler::SFIMoveEvent(Address from, Address to) {
- singleton_->processor_->SFIMoveEvent(from, to);
+void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
+ CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
+ profiler->processor_->SharedFunctionInfoMoveEvent(from, to);
}
void CpuProfiler::GetterCallbackEvent(String* name, Address entry_point) {
- singleton_->processor_->CallbackCreateEvent(
+ Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
Logger::CALLBACK_TAG, "get ", name, entry_point);
}
void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
- singleton_->processor_->RegExpCodeCreateEvent(
+ Isolate::Current()->cpu_profiler()->processor_->RegExpCodeCreateEvent(
Logger::REG_EXP_TAG,
"RegExp: ",
source,
@@ -425,7 +454,7 @@ void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) {
- singleton_->processor_->CallbackCreateEvent(
+ Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
Logger::CALLBACK_TAG, "set ", name, entry_point);
}
@@ -435,7 +464,9 @@ CpuProfiler::CpuProfiler()
next_profile_uid_(1),
token_enumerator_(new TokenEnumerator()),
generator_(NULL),
- processor_(NULL) {
+ processor_(NULL),
+ need_to_stop_sampler_(false),
+ is_profiling_(false) {
}
@@ -445,6 +476,11 @@ CpuProfiler::~CpuProfiler() {
}
+void CpuProfiler::ResetProfiles() {
+ delete profiles_;
+ profiles_ = new CpuProfilesCollection();
+}
+
void CpuProfiler::StartCollectingProfile(const char* title) {
if (profiles_->StartProfiling(title, next_profile_uid_++)) {
StartProcessorIfNotStarted();
@@ -460,27 +496,32 @@ void CpuProfiler::StartCollectingProfile(String* title) {
void CpuProfiler::StartProcessorIfNotStarted() {
if (processor_ == NULL) {
+ Isolate* isolate = Isolate::Current();
+
// Disable logging when using the new implementation.
- saved_logging_nesting_ = Logger::logging_nesting_;
- Logger::logging_nesting_ = 0;
+ saved_logging_nesting_ = isolate->logger()->logging_nesting_;
+ isolate->logger()->logging_nesting_ = 0;
generator_ = new ProfileGenerator(profiles_);
- processor_ = new ProfilerEventsProcessor(generator_);
+ processor_ = new ProfilerEventsProcessor(isolate, generator_);
NoBarrier_Store(&is_profiling_, true);
processor_->Start();
// Enumerate stuff we already have in the heap.
- if (Heap::HasBeenSetup()) {
+ if (isolate->heap()->HasBeenSetup()) {
if (!FLAG_prof_browser_mode) {
bool saved_log_code_flag = FLAG_log_code;
FLAG_log_code = true;
- Logger::LogCodeObjects();
+ isolate->logger()->LogCodeObjects();
FLAG_log_code = saved_log_code_flag;
}
- Logger::LogCompiledFunctions();
- Logger::LogAccessorCallbacks();
+ isolate->logger()->LogCompiledFunctions();
+ isolate->logger()->LogAccessorCallbacks();
}
// Enable stack sampling.
- Sampler* sampler = reinterpret_cast<Sampler*>(Logger::ticker_);
- if (!sampler->IsActive()) sampler->Start();
+ Sampler* sampler = reinterpret_cast<Sampler*>(isolate->logger()->ticker_);
+ if (!sampler->IsActive()) {
+ sampler->Start();
+ need_to_stop_sampler_ = true;
+ }
sampler->IncreaseProfilingDepth();
}
}
@@ -511,19 +552,26 @@ CpuProfile* CpuProfiler::StopCollectingProfile(Object* security_token,
void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
- if (profiles_->IsLastProfile(title)) {
- Sampler* sampler = reinterpret_cast<Sampler*>(Logger::ticker_);
- sampler->DecreaseProfilingDepth();
+ if (profiles_->IsLastProfile(title)) StopProcessor();
+}
+
+
+void CpuProfiler::StopProcessor() {
+ Logger* logger = Isolate::Current()->logger();
+ Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
+ sampler->DecreaseProfilingDepth();
+ if (need_to_stop_sampler_) {
sampler->Stop();
- processor_->Stop();
- processor_->Join();
- delete processor_;
- delete generator_;
- processor_ = NULL;
- NoBarrier_Store(&is_profiling_, false);
- generator_ = NULL;
- Logger::logging_nesting_ = saved_logging_nesting_;
+ need_to_stop_sampler_ = false;
}
+ processor_->Stop();
+ processor_->Join();
+ delete processor_;
+ delete generator_;
+ processor_ = NULL;
+ NoBarrier_Store(&is_profiling_, false);
+ generator_ = NULL;
+ logger->logging_nesting_ = saved_logging_nesting_;
}
} } // namespace v8::internal
@@ -535,8 +583,9 @@ namespace internal {
void CpuProfiler::Setup() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (singleton_ == NULL) {
- singleton_ = new CpuProfiler();
+ Isolate* isolate = Isolate::Current();
+ if (isolate->cpu_profiler() == NULL) {
+ isolate->set_cpu_profiler(new CpuProfiler());
}
#endif
}
@@ -544,10 +593,11 @@ void CpuProfiler::Setup() {
void CpuProfiler::TearDown() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (singleton_ != NULL) {
- delete singleton_;
+ Isolate* isolate = Isolate::Current();
+ if (isolate->cpu_profiler() != NULL) {
+ delete isolate->cpu_profiler();
}
- singleton_ = NULL;
+ isolate->set_cpu_profiler(NULL);
#endif
}
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 1ebbfebf..e04cf855 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -46,11 +46,11 @@ class HashMap;
class ProfileGenerator;
class TokenEnumerator;
-#define CODE_EVENTS_TYPE_LIST(V) \
- V(CODE_CREATION, CodeCreateEventRecord) \
- V(CODE_MOVE, CodeMoveEventRecord) \
- V(CODE_DELETE, CodeDeleteEventRecord) \
- V(SFI_MOVE, SFIMoveEventRecord)
+#define CODE_EVENTS_TYPE_LIST(V) \
+ V(CODE_CREATION, CodeCreateEventRecord) \
+ V(CODE_MOVE, CodeMoveEventRecord) \
+ V(CODE_DELETE, CodeDeleteEventRecord) \
+ V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)
class CodeEventRecord {
@@ -73,7 +73,7 @@ class CodeCreateEventRecord : public CodeEventRecord {
Address start;
CodeEntry* entry;
unsigned size;
- Address sfi_address;
+ Address shared;
INLINE(void UpdateCodeMap(CodeMap* code_map));
};
@@ -96,7 +96,7 @@ class CodeDeleteEventRecord : public CodeEventRecord {
};
-class SFIMoveEventRecord : public CodeEventRecord {
+class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
public:
Address from;
Address to;
@@ -133,7 +133,8 @@ class TickSampleEventRecord BASE_EMBEDDED {
// methods called by event producers: VM and stack sampler threads.
class ProfilerEventsProcessor : public Thread {
public:
- explicit ProfilerEventsProcessor(ProfileGenerator* generator);
+ explicit ProfilerEventsProcessor(Isolate* isolate,
+ ProfileGenerator* generator);
virtual ~ProfilerEventsProcessor() {}
// Thread control.
@@ -149,7 +150,7 @@ class ProfilerEventsProcessor : public Thread {
String* name,
String* resource_name, int line_number,
Address start, unsigned size,
- Address sfi_address);
+ Address shared);
void CodeCreateEvent(Logger::LogEventsAndTags tag,
const char* name,
Address start, unsigned size);
@@ -158,7 +159,7 @@ class ProfilerEventsProcessor : public Thread {
Address start, unsigned size);
void CodeMoveEvent(Address from, Address to);
void CodeDeleteEvent(Address from);
- void SFIMoveEvent(Address from, Address to);
+ void SharedFunctionInfoMoveEvent(Address from, Address to);
void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
const char* prefix, String* name,
Address start, unsigned size);
@@ -196,21 +197,23 @@ class ProfilerEventsProcessor : public Thread {
} } // namespace v8::internal
-#define PROFILE(Call) \
- LOG(Call); \
+#define PROFILE(isolate, Call) \
+ LOG(isolate, Call); \
do { \
if (v8::internal::CpuProfiler::is_profiling()) { \
v8::internal::CpuProfiler::Call; \
} \
} while (false)
#else
-#define PROFILE(Call) LOG(Call)
+#define PROFILE(isolate, Call) LOG(isolate, Call)
#endif // ENABLE_LOGGING_AND_PROFILING
namespace v8 {
namespace internal {
+
+// TODO(isolates): isolatify this class.
class CpuProfiler {
public:
static void Setup();
@@ -224,9 +227,12 @@ class CpuProfiler {
static int GetProfilesCount();
static CpuProfile* GetProfile(Object* security_token, int index);
static CpuProfile* FindProfile(Object* security_token, unsigned uid);
+ static void DeleteAllProfiles();
+ static void DeleteProfile(CpuProfile* profile);
+ static bool HasDetachedProfiles();
// Invoked from stack sampler (thread or signal handler.)
- static TickSample* TickSampleEvent();
+ static TickSample* TickSampleEvent(Isolate* isolate);
// Must be called via PROFILE macro, otherwise will crash when
// profiling is not enabled.
@@ -251,10 +257,17 @@ class CpuProfiler {
static void GetterCallbackEvent(String* name, Address entry_point);
static void RegExpCodeCreateEvent(Code* code, String* source);
static void SetterCallbackEvent(String* name, Address entry_point);
- static void SFIMoveEvent(Address from, Address to);
+ static void SharedFunctionInfoMoveEvent(Address from, Address to);
+
+ // TODO(isolates): this doesn't have to use atomics anymore.
static INLINE(bool is_profiling()) {
- return NoBarrier_Load(&is_profiling_);
+ return is_profiling(Isolate::Current());
+ }
+
+ static INLINE(bool is_profiling(Isolate* isolate)) {
+ CpuProfiler* profiler = isolate->cpu_profiler();
+ return profiler != NULL && NoBarrier_Load(&profiler->is_profiling_);
}
private:
@@ -266,6 +279,8 @@ class CpuProfiler {
CpuProfile* StopCollectingProfile(const char* title);
CpuProfile* StopCollectingProfile(Object* security_token, String* title);
void StopProcessorIfLastProfile(const char* title);
+ void StopProcessor();
+ void ResetProfiles();
CpuProfilesCollection* profiles_;
unsigned next_profile_uid_;
@@ -273,9 +288,8 @@ class CpuProfiler {
ProfileGenerator* generator_;
ProfilerEventsProcessor* processor_;
int saved_logging_nesting_;
-
- static CpuProfiler* singleton_;
- static Atomic32 is_profiling_;
+ bool need_to_stop_sampler_;
+ Atomic32 is_profiling_;
#else
static INLINE(bool is_profiling()) { return false; }
diff --git a/src/d8-debug.cc b/src/d8-debug.cc
index 8a3886c6..3df86934 100644
--- a/src/d8-debug.cc
+++ b/src/d8-debug.cc
@@ -159,7 +159,7 @@ void HandleDebugEvent(DebugEvent event,
void RunRemoteDebugger(int port) {
- RemoteDebugger debugger(port);
+ RemoteDebugger debugger(i::Isolate::Current(), port);
debugger.Run();
}
@@ -186,11 +186,11 @@ void RemoteDebugger::Run() {
}
// Start the receiver thread.
- ReceiverThread receiver(this);
+ ReceiverThread receiver(isolate_, this);
receiver.Start();
// Start the keyboard thread.
- KeyboardThread keyboard(this);
+ KeyboardThread keyboard(isolate_, this);
keyboard.Start();
PrintPrompt();
diff --git a/src/d8-debug.h b/src/d8-debug.h
index 4e33e6f4..ceb9e363 100644
--- a/src/d8-debug.h
+++ b/src/d8-debug.h
@@ -53,11 +53,11 @@ class ReceiverThread;
// Remote debugging class.
class RemoteDebugger {
public:
- explicit RemoteDebugger(int port)
+ RemoteDebugger(i::Isolate* isolate, int port)
: port_(port),
event_access_(i::OS::CreateMutex()),
event_available_(i::OS::CreateSemaphore(0)),
- head_(NULL), tail_(NULL) {}
+ head_(NULL), tail_(NULL), isolate_(isolate) {}
void Run();
// Handle events from the subordinate threads.
@@ -89,6 +89,7 @@ class RemoteDebugger {
i::Semaphore* event_available_;
RemoteDebuggerEvent* head_;
RemoteDebuggerEvent* tail_;
+ i::Isolate* isolate_;
friend class ReceiverThread;
};
@@ -97,8 +98,8 @@ class RemoteDebugger {
// Thread reading from debugged V8 instance.
class ReceiverThread: public i::Thread {
public:
- explicit ReceiverThread(RemoteDebugger* remote_debugger)
- : Thread("d8:ReceiverThrd"),
+ ReceiverThread(i::Isolate* isolate, RemoteDebugger* remote_debugger)
+ : Thread(isolate, "d8:ReceiverThrd"),
remote_debugger_(remote_debugger) {}
~ReceiverThread() {}
@@ -112,8 +113,8 @@ class ReceiverThread: public i::Thread {
// Thread reading keyboard input.
class KeyboardThread: public i::Thread {
public:
- explicit KeyboardThread(RemoteDebugger* remote_debugger)
- : Thread("d8:KeyboardThrd"),
+ explicit KeyboardThread(i::Isolate* isolate, RemoteDebugger* remote_debugger)
+ : Thread(isolate, "d8:KeyboardThrd"),
remote_debugger_(remote_debugger) {}
~KeyboardThread() {}
diff --git a/src/d8-posix.cc b/src/d8-posix.cc
index 335bd2b4..a7a40493 100644
--- a/src/d8-posix.cc
+++ b/src/d8-posix.cc
@@ -375,8 +375,10 @@ static Handle<Value> GetStdout(int child_fd,
// a parent process hangs on waiting while a child process is already a zombie.
// See http://code.google.com/p/v8/issues/detail?id=401.
#if defined(WNOWAIT) && !defined(ANDROID) && !defined(__APPLE__)
+#if !defined(__FreeBSD__)
#define HAS_WAITID 1
#endif
+#endif
// Get exit status of child.
diff --git a/src/d8.cc b/src/d8.cc
index 349ec904..7de82b75 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -29,6 +29,8 @@
#include <stdlib.h>
#include <errno.h>
+#include "v8.h"
+
#include "d8.h"
#include "d8-debug.h"
#include "debug.h"
@@ -441,24 +443,25 @@ void Shell::Initialize() {
i::JSArguments js_args = i::FLAG_js_arguments;
i::Handle<i::FixedArray> arguments_array =
- i::Factory::NewFixedArray(js_args.argc());
+ FACTORY->NewFixedArray(js_args.argc());
for (int j = 0; j < js_args.argc(); j++) {
i::Handle<i::String> arg =
- i::Factory::NewStringFromUtf8(i::CStrVector(js_args[j]));
+ FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
arguments_array->set(j, *arg);
}
i::Handle<i::JSArray> arguments_jsarray =
- i::Factory::NewJSArrayWithElements(arguments_array);
+ FACTORY->NewJSArrayWithElements(arguments_array);
global_template->Set(String::New("arguments"),
Utils::ToLocal(arguments_jsarray));
#ifdef ENABLE_DEBUGGER_SUPPORT
// Install the debugger object in the utility scope
- i::Debug::Load();
- i::Handle<i::JSObject> debug
- = i::Handle<i::JSObject>(i::Debug::debug_context()->global());
+ i::Debug* debug = i::Isolate::Current()->debug();
+ debug->Load();
+ i::Handle<i::JSObject> js_debug
+ = i::Handle<i::JSObject>(debug->debug_context()->global());
utility_context_->Global()->Set(String::New("$debug"),
- Utils::ToLocal(debug));
+ Utils::ToLocal(js_debug));
#endif
// Run the d8 shell utility script in the utility context
@@ -490,7 +493,7 @@ void Shell::Initialize() {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Set the security token of the debug context to allow access.
- i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
+ debug->debug_context()->set_security_token(HEAP->undefined_value());
// Start the debugger agent if requested.
if (i::FLAG_debugger_agent) {
@@ -606,8 +609,8 @@ void Shell::RunShell() {
class ShellThread : public i::Thread {
public:
- ShellThread(int no, i::Vector<const char> files)
- : Thread("d8:ShellThread"),
+ ShellThread(i::Isolate* isolate, int no, i::Vector<const char> files)
+ : Thread(isolate, "d8:ShellThread"),
no_(no), files_(files) { }
virtual void Run();
private:
@@ -739,7 +742,8 @@ int Shell::Main(int argc, char* argv[]) {
const char* files = ReadChars(argv[++i], &size);
if (files == NULL) return 1;
ShellThread* thread =
- new ShellThread(threads.length(),
+ new ShellThread(i::Isolate::Current(),
+ threads.length(),
i::Vector<const char>(files, size));
thread->Start();
threads.Add(thread);
diff --git a/src/d8.gyp b/src/d8.gyp
index 3283e38a..901fd651 100644
--- a/src/d8.gyp
+++ b/src/d8.gyp
@@ -38,7 +38,10 @@
'../src',
],
'defines': [
+ 'ENABLE_LOGGING_AND_PROFILING',
'ENABLE_DEBUGGER_SUPPORT',
+ 'ENABLE_VMSTATE_TRACKING',
+ 'V8_FAST_TLS',
],
'sources': [
'd8.cc',
diff --git a/src/data-flow.h b/src/data-flow.h
index 79d760f5..573d7d80 100644
--- a/src/data-flow.h
+++ b/src/data-flow.h
@@ -90,7 +90,7 @@ class BitVector: public ZoneObject {
explicit BitVector(int length)
: length_(length),
data_length_(SizeFor(length)),
- data_(Zone::NewArray<uint32_t>(data_length_)) {
+ data_(ZONE->NewArray<uint32_t>(data_length_)) {
ASSERT(length > 0);
Clear();
}
@@ -98,7 +98,7 @@ class BitVector: public ZoneObject {
BitVector(const BitVector& other)
: length_(other.length()),
data_length_(SizeFor(length_)),
- data_(Zone::NewArray<uint32_t>(data_length_)) {
+ data_(ZONE->NewArray<uint32_t>(data_length_)) {
CopyFrom(other);
}
@@ -237,7 +237,7 @@ class SparseSet: public ZoneObject {
explicit SparseSet(int universe_size)
: dense_(4),
- sparse_(Zone::NewArray<int>(universe_size)) {
+ sparse_(ZONE->NewArray<int>(universe_size)) {
#ifdef DEBUG
size_ = universe_size;
iterator_count_ = 0;
diff --git a/src/dateparser.h b/src/dateparser.h
index 40e56f30..51109ee9 100644
--- a/src/dateparser.h
+++ b/src/dateparser.h
@@ -70,7 +70,8 @@ class DateParser : public AllStatic {
explicit InputReader(Vector<Char> s)
: index_(0),
buffer_(s),
- has_read_number_(false) {
+ has_read_number_(false),
+ scanner_constants_(Isolate::Current()->scanner_constants()) {
Next();
}
@@ -121,7 +122,7 @@ class DateParser : public AllStatic {
}
bool SkipWhiteSpace() {
- if (ScannerConstants::kIsWhiteSpace.get(ch_)) {
+ if (scanner_constants_->IsWhiteSpace(ch_)) {
Next();
return true;
}
@@ -157,6 +158,7 @@ class DateParser : public AllStatic {
Vector<Char> buffer_;
bool has_read_number_;
uint32_t ch_;
+ ScannerConstants* scanner_constants_;
};
enum KeywordType { INVALID, MONTH_NAME, TIME_ZONE_NAME, AM_PM };
diff --git a/src/debug-agent.cc b/src/debug-agent.cc
index 6901079b..498b88ac 100644
--- a/src/debug-agent.cc
+++ b/src/debug-agent.cc
@@ -38,11 +38,11 @@ namespace internal {
// Public V8 debugger API message handler function. This function just delegates
// to the debugger agent through it's data parameter.
void DebuggerAgentMessageHandler(const v8::Debug::Message& message) {
- DebuggerAgent::instance_->DebuggerMessage(message);
+ DebuggerAgent* agent = Isolate::Current()->debugger_agent_instance();
+ ASSERT(agent != NULL);
+ agent->DebuggerMessage(message);
}
-// static
-DebuggerAgent* DebuggerAgent::instance_ = NULL;
// Debugger agent main thread.
void DebuggerAgent::Run() {
@@ -102,20 +102,21 @@ void DebuggerAgent::WaitUntilListening() {
listening_->Wait();
}
+static const char* kCreateSessionMessage =
+ "Remote debugging session already active\r\n";
+
void DebuggerAgent::CreateSession(Socket* client) {
ScopedLock with(session_access_);
// If another session is already established terminate this one.
if (session_ != NULL) {
- static const char* message = "Remote debugging session already active\r\n";
-
- client->Send(message, StrLength(message));
+ client->Send(kCreateSessionMessage, StrLength(kCreateSessionMessage));
delete client;
return;
}
// Create a new session and hook up the debug message handler.
- session_ = new DebuggerAgentSession(this, client);
+ session_ = new DebuggerAgentSession(isolate(), this, client);
v8::Debug::SetMessageHandler2(DebuggerAgentMessageHandler);
session_->Start();
}
@@ -224,8 +225,8 @@ void DebuggerAgentSession::Shutdown() {
}
-const char* DebuggerAgentUtil::kContentLength = "Content-Length";
-int DebuggerAgentUtil::kContentLengthSize =
+const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
+const int DebuggerAgentUtil::kContentLengthSize =
StrLength(kContentLength);
diff --git a/src/debug-agent.h b/src/debug-agent.h
index 4cedb831..a25002e0 100644
--- a/src/debug-agent.h
+++ b/src/debug-agent.h
@@ -43,18 +43,18 @@ class DebuggerAgentSession;
// handles connection from a remote debugger.
class DebuggerAgent: public Thread {
public:
- explicit DebuggerAgent(const char* name, int port)
- : Thread(name),
+ DebuggerAgent(Isolate* isolate, const char* name, int port)
+ : Thread(isolate, name),
name_(StrDup(name)), port_(port),
server_(OS::CreateSocket()), terminate_(false),
session_access_(OS::CreateMutex()), session_(NULL),
terminate_now_(OS::CreateSemaphore(0)),
listening_(OS::CreateSemaphore(0)) {
- ASSERT(instance_ == NULL);
- instance_ = this;
+ ASSERT(Isolate::Current()->debugger_agent_instance() == NULL);
+ Isolate::Current()->set_debugger_agent_instance(this);
}
~DebuggerAgent() {
- instance_ = NULL;
+ Isolate::Current()->set_debugger_agent_instance(NULL);
delete server_;
}
@@ -77,8 +77,6 @@ class DebuggerAgent: public Thread {
Semaphore* terminate_now_; // Semaphore to signal termination.
Semaphore* listening_;
- static DebuggerAgent* instance_;
-
friend class DebuggerAgentSession;
friend void DebuggerAgentMessageHandler(const v8::Debug::Message& message);
@@ -90,8 +88,8 @@ class DebuggerAgent: public Thread {
// debugger and sends debugger events/responses to the remote debugger.
class DebuggerAgentSession: public Thread {
public:
- DebuggerAgentSession(DebuggerAgent* agent, Socket* client)
- : Thread("v8:DbgAgntSessn"),
+ DebuggerAgentSession(Isolate* isolate, DebuggerAgent* agent, Socket* client)
+ : Thread(isolate, "v8:DbgAgntSessn"),
agent_(agent), client_(client) {}
void DebuggerMessage(Vector<uint16_t> message);
@@ -112,8 +110,8 @@ class DebuggerAgentSession: public Thread {
// Utility methods factored out to be used by the D8 shell as well.
class DebuggerAgentUtil {
public:
- static const char* kContentLength;
- static int kContentLengthSize;
+ static const char* const kContentLength;
+ static const int kContentLengthSize;
static SmartPointer<char> ReceiveMessage(const Socket* conn);
static bool SendConnectMessage(const Socket* conn,
diff --git a/src/debug.cc b/src/debug.cc
index d91ad92e..bc532ef1 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -51,6 +51,26 @@ namespace v8 {
namespace internal {
#ifdef ENABLE_DEBUGGER_SUPPORT
+
+
+Debug::Debug(Isolate* isolate)
+ : has_break_points_(false),
+ script_cache_(NULL),
+ debug_info_list_(NULL),
+ disable_break_(false),
+ break_on_exception_(false),
+ break_on_uncaught_exception_(false),
+ debug_break_return_(NULL),
+ debug_break_slot_(NULL),
+ isolate_(isolate) {
+ memset(registers_, 0, sizeof(JSCallerSavedBuffer));
+}
+
+
+Debug::~Debug() {
+}
+
+
static void PrintLn(v8::Local<v8::Value> value) {
v8::Local<v8::String> s = value->ToString();
ScopedVector<char> data(s->Length() + 1);
@@ -64,22 +84,28 @@ static void PrintLn(v8::Local<v8::Value> value) {
static Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind) {
- CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc, kind), Code);
+ Isolate* isolate = Isolate::Current();
+ CALL_HEAP_FUNCTION(
+ isolate,
+ isolate->stub_cache()->ComputeCallDebugBreak(argc, kind),
+ Code);
}
-static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
+static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
+ Isolate* isolate = Isolate::Current();
CALL_HEAP_FUNCTION(
- StubCache::ComputeCallDebugPrepareStepIn(argc, kind), Code);
+ isolate,
+ isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind),
+ Code);
}
-static v8::Handle<v8::Context> GetDebugEventContext() {
- Handle<Context> context = Debug::debugger_entry()->GetContext();
- // Top::context() may have been NULL when "script collected" event occured.
- if (*context == NULL) {
- return v8::Local<v8::Context>();
- }
+static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
+ Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
+ // Isolate::context() may have been NULL when "script collected" event
+ // occured.
+ if (context.is_null()) return v8::Local<v8::Context>();
Handle<Context> global_context(context->global_context());
return v8::Utils::ToLocal(global_context);
}
@@ -535,11 +561,6 @@ void BreakLocationIterator::RinfoNext() {
}
-bool Debug::has_break_points_ = false;
-ScriptCache* Debug::script_cache_ = NULL;
-DebugInfoListNode* Debug::debug_info_list_ = NULL;
-
-
// Threading support.
void Debug::ThreadInit() {
thread_local_.break_count_ = 0;
@@ -552,16 +573,13 @@ void Debug::ThreadInit() {
thread_local_.step_into_fp_ = 0;
thread_local_.step_out_fp_ = 0;
thread_local_.after_break_target_ = 0;
+ // TODO(isolates): frames_are_dropped_?
thread_local_.debugger_entry_ = NULL;
thread_local_.pending_interrupts_ = 0;
thread_local_.restarter_frame_function_pointer_ = NULL;
}
-JSCallerSavedBuffer Debug::registers_;
-Debug::ThreadLocal Debug::thread_local_;
-
-
char* Debug::ArchiveDebug(char* storage) {
char* to = storage;
memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
@@ -584,7 +602,7 @@ char* Debug::RestoreDebug(char* storage) {
int Debug::ArchiveSpacePerThread() {
- return sizeof(ThreadLocal) + sizeof(registers_);
+ return sizeof(ThreadLocal) + sizeof(JSCallerSavedBuffer);
}
@@ -614,22 +632,8 @@ Object** Debug::SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
const int Debug::kFrameDropperFrameSize = 4;
-
-
-
-// Default break enabled.
-bool Debug::disable_break_ = false;
-
-// Default call debugger on uncaught exception.
-bool Debug::break_on_exception_ = false;
-bool Debug::break_on_uncaught_exception_ = false;
-
-Handle<Context> Debug::debug_context_ = Handle<Context>();
-Code* Debug::debug_break_return_ = NULL;
-Code* Debug::debug_break_slot_ = NULL;
-
-
void ScriptCache::Add(Handle<Script> script) {
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
// Create an entry in the hash map for the script.
int id = Smi::cast(script->id())->value();
HashMap::Entry* entry =
@@ -642,15 +646,18 @@ void ScriptCache::Add(Handle<Script> script) {
// Globalize the script object, make it weak and use the location of the
// global handle as the value in the hash map.
Handle<Script> script_ =
- Handle<Script>::cast((GlobalHandles::Create(*script)));
- GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
- this, ScriptCache::HandleWeakScript);
+ Handle<Script>::cast(
+ (global_handles->Create(*script)));
+ global_handles->MakeWeak(
+ reinterpret_cast<Object**>(script_.location()),
+ this,
+ ScriptCache::HandleWeakScript);
entry->value = script_.location();
}
Handle<FixedArray> ScriptCache::GetScripts() {
- Handle<FixedArray> instances = Factory::NewFixedArray(occupancy());
+ Handle<FixedArray> instances = FACTORY->NewFixedArray(occupancy());
int count = 0;
for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
ASSERT(entry->value != NULL);
@@ -664,21 +671,23 @@ Handle<FixedArray> ScriptCache::GetScripts() {
void ScriptCache::ProcessCollectedScripts() {
+ Debugger* debugger = Isolate::Current()->debugger();
for (int i = 0; i < collected_scripts_.length(); i++) {
- Debugger::OnScriptCollected(collected_scripts_[i]);
+ debugger->OnScriptCollected(collected_scripts_[i]);
}
collected_scripts_.Clear();
}
void ScriptCache::Clear() {
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
// Iterate the script cache to get rid of all the weak handles.
for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
ASSERT(entry != NULL);
Object** location = reinterpret_cast<Object**>(entry->value);
ASSERT((*location)->IsScript());
- GlobalHandles::ClearWeakness(location);
- GlobalHandles::Destroy(location);
+ global_handles->ClearWeakness(location);
+ global_handles->Destroy(location);
}
// Clear the content of the hash map.
HashMap::Clear();
@@ -708,17 +717,18 @@ void Debug::Setup(bool create_heap_objects) {
if (create_heap_objects) {
// Get code to handle debug break on return.
debug_break_return_ =
- Builtins::builtin(Builtins::Return_DebugBreak);
+ isolate_->builtins()->builtin(Builtins::kReturn_DebugBreak);
ASSERT(debug_break_return_->IsCode());
// Get code to handle debug break in debug break slots.
debug_break_slot_ =
- Builtins::builtin(Builtins::Slot_DebugBreak);
+ isolate_->builtins()->builtin(Builtins::kSlot_DebugBreak);
ASSERT(debug_break_slot_->IsCode());
}
}
void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
+ Debug* debug = Isolate::Current()->debug();
DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
// We need to clear all breakpoints associated with the function to restore
// original code and avoid patching the code twice later because
@@ -726,9 +736,9 @@ void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
// Runtime::FindSharedFunctionInfoInScript.
BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
it.ClearAllDebugBreak();
- RemoveDebugInfo(node->debug_info());
+ debug->RemoveDebugInfo(node->debug_info());
#ifdef DEBUG
- node = Debug::debug_info_list_;
+ node = debug->debug_info_list_;
while (node != NULL) {
ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
node = node->next();
@@ -738,20 +748,27 @@ void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
// Globalize the request debug info object and make it weak.
- debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
- GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
- this, Debug::HandleWeakDebugInfo);
+ debug_info_ = Handle<DebugInfo>::cast(
+ (global_handles->Create(debug_info)));
+ global_handles->MakeWeak(
+ reinterpret_cast<Object**>(debug_info_.location()),
+ this,
+ Debug::HandleWeakDebugInfo);
}
DebugInfoListNode::~DebugInfoListNode() {
- GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
+ Isolate::Current()->global_handles()->Destroy(
+ reinterpret_cast<Object**>(debug_info_.location()));
}
bool Debug::CompileDebuggerScript(int index) {
- HandleScope scope;
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope scope(isolate);
// Bail out if the index is invalid.
if (index == -1) {
@@ -759,33 +776,31 @@ bool Debug::CompileDebuggerScript(int index) {
}
// Find source and name for the requested script.
- Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
+ Handle<String> source_code =
+ isolate->bootstrapper()->NativesSourceLookup(index);
Vector<const char> name = Natives::GetScriptName(index);
- Handle<String> script_name = Factory::NewStringFromAscii(name);
+ Handle<String> script_name = factory->NewStringFromAscii(name);
// Compile the script.
- bool allow_natives_syntax = FLAG_allow_natives_syntax;
- FLAG_allow_natives_syntax = true;
Handle<SharedFunctionInfo> function_info;
function_info = Compiler::Compile(source_code,
script_name,
0, 0, NULL, NULL,
Handle<String>::null(),
NATIVES_CODE);
- FLAG_allow_natives_syntax = allow_natives_syntax;
// Silently ignore stack overflows during compilation.
if (function_info.is_null()) {
- ASSERT(Top::has_pending_exception());
- Top::clear_pending_exception();
+ ASSERT(isolate->has_pending_exception());
+ isolate->clear_pending_exception();
return false;
}
// Execute the shared function in the debugger context.
- Handle<Context> context = Top::global_context();
+ Handle<Context> context = isolate->global_context();
bool caught_exception = false;
Handle<JSFunction> function =
- Factory::NewFunctionFromSharedFunctionInfo(function_info, context);
+ factory->NewFunctionFromSharedFunctionInfo(function_info, context);
Handle<Object> result =
Execution::TryCall(function, Handle<Object>(context->global()),
0, NULL, &caught_exception);
@@ -810,38 +825,44 @@ bool Debug::Load() {
// Return if debugger is already loaded.
if (IsLoaded()) return true;
+ ASSERT(Isolate::Current() == isolate_);
+ Debugger* debugger = isolate_->debugger();
+
// Bail out if we're already in the process of compiling the native
// JavaScript source code for the debugger.
- if (Debugger::compiling_natives() || Debugger::is_loading_debugger())
+ if (debugger->compiling_natives() ||
+ debugger->is_loading_debugger())
return false;
- Debugger::set_loading_debugger(true);
+ debugger->set_loading_debugger(true);
// Disable breakpoints and interrupts while compiling and running the
// debugger scripts including the context creation code.
DisableBreak disable(true);
- PostponeInterruptsScope postpone;
+ PostponeInterruptsScope postpone(isolate_);
// Create the debugger context.
- HandleScope scope;
+ HandleScope scope(isolate_);
Handle<Context> context =
- Bootstrapper::CreateEnvironment(Handle<Object>::null(),
- v8::Handle<ObjectTemplate>(),
- NULL);
+ isolate_->bootstrapper()->CreateEnvironment(
+ Handle<Object>::null(),
+ v8::Handle<ObjectTemplate>(),
+ NULL);
// Use the debugger context.
- SaveContext save;
- Top::set_context(*context);
+ SaveContext save(isolate_);
+ isolate_->set_context(*context);
// Expose the builtins object in the debugger context.
- Handle<String> key = Factory::LookupAsciiSymbol("builtins");
+ Handle<String> key = isolate_->factory()->LookupAsciiSymbol("builtins");
Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate_,
SetProperty(global, key, Handle<Object>(global->builtins()),
NONE, kNonStrictMode),
false);
// Compile the JavaScript for the debugger in the debugger context.
- Debugger::set_compiling_natives(true);
+ debugger->set_compiling_natives(true);
bool caught_exception =
!CompileDebuggerScript(Natives::GetIndex("mirror")) ||
!CompileDebuggerScript(Natives::GetIndex("debug"));
@@ -851,11 +872,11 @@ bool Debug::Load() {
!CompileDebuggerScript(Natives::GetIndex("liveedit"));
}
- Debugger::set_compiling_natives(false);
+ debugger->set_compiling_natives(false);
// Make sure we mark the debugger as not loading before we might
// return.
- Debugger::set_loading_debugger(false);
+ debugger->set_loading_debugger(false);
// Check for caught exceptions.
if (caught_exception) return false;
@@ -877,7 +898,8 @@ void Debug::Unload() {
DestroyScriptCache();
// Clear debugger context global handle.
- GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
+ Isolate::Current()->global_handles()->Destroy(
+ reinterpret_cast<Object**>(debug_context_.location()));
debug_context_ = Handle<Context>();
}
@@ -895,30 +917,35 @@ void Debug::Iterate(ObjectVisitor* v) {
}
-Object* Debug::Break(Arguments args) {
- HandleScope scope;
+// This remains a static method so that generated code can call it.
+Object* Debug::Break(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+
+ Debug* debug = isolate->debug();
+ Heap* heap = isolate->heap();
+ HandleScope scope(isolate);
ASSERT(args.length() == 0);
- thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
+ debug->thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
// Get the top-most JavaScript frame.
JavaScriptFrameIterator it;
JavaScriptFrame* frame = it.frame();
// Just continue if breaks are disabled or debugger cannot be loaded.
- if (disable_break() || !Load()) {
- SetAfterBreakTarget(frame);
- return Heap::undefined_value();
+ if (debug->disable_break() || !debug->Load()) {
+ debug->SetAfterBreakTarget(frame);
+ return heap->undefined_value();
}
// Enter the debugger.
EnterDebugger debugger;
if (debugger.FailedToEnter()) {
- return Heap::undefined_value();
+ return heap->undefined_value();
}
// Postpone interrupt during breakpoint processing.
- PostponeInterruptsScope postpone;
+ PostponeInterruptsScope postpone(isolate);
// Get the debug info (create it if it does not exist).
Handle<SharedFunctionInfo> shared =
@@ -931,71 +958,76 @@ Object* Debug::Break(Arguments args) {
break_location_iterator.FindBreakLocationFromAddress(frame->pc());
// Check whether step next reached a new statement.
- if (!StepNextContinue(&break_location_iterator, frame)) {
+ if (!debug->StepNextContinue(&break_location_iterator, frame)) {
// Decrease steps left if performing multiple steps.
- if (thread_local_.step_count_ > 0) {
- thread_local_.step_count_--;
+ if (debug->thread_local_.step_count_ > 0) {
+ debug->thread_local_.step_count_--;
}
}
// If there is one or more real break points check whether any of these are
// triggered.
- Handle<Object> break_points_hit(Heap::undefined_value());
+ Handle<Object> break_points_hit(heap->undefined_value());
if (break_location_iterator.HasBreakPoint()) {
Handle<Object> break_point_objects =
Handle<Object>(break_location_iterator.BreakPointObjects());
- break_points_hit = CheckBreakPoints(break_point_objects);
+ break_points_hit = debug->CheckBreakPoints(break_point_objects);
}
// If step out is active skip everything until the frame where we need to step
// out to is reached, unless real breakpoint is hit.
- if (Debug::StepOutActive() && frame->fp() != Debug::step_out_fp() &&
+ if (debug->StepOutActive() && frame->fp() != debug->step_out_fp() &&
break_points_hit->IsUndefined() ) {
// Step count should always be 0 for StepOut.
- ASSERT(thread_local_.step_count_ == 0);
+ ASSERT(debug->thread_local_.step_count_ == 0);
} else if (!break_points_hit->IsUndefined() ||
- (thread_local_.last_step_action_ != StepNone &&
- thread_local_.step_count_ == 0)) {
+ (debug->thread_local_.last_step_action_ != StepNone &&
+ debug->thread_local_.step_count_ == 0)) {
// Notify debugger if a real break point is triggered or if performing
// single stepping with no more steps to perform. Otherwise do another step.
// Clear all current stepping setup.
- ClearStepping();
+ debug->ClearStepping();
// Notify the debug event listeners.
- Debugger::OnDebugBreak(break_points_hit, false);
- } else if (thread_local_.last_step_action_ != StepNone) {
+ isolate->debugger()->OnDebugBreak(break_points_hit, false);
+ } else if (debug->thread_local_.last_step_action_ != StepNone) {
// Hold on to last step action as it is cleared by the call to
// ClearStepping.
- StepAction step_action = thread_local_.last_step_action_;
- int step_count = thread_local_.step_count_;
+ StepAction step_action = debug->thread_local_.last_step_action_;
+ int step_count = debug->thread_local_.step_count_;
// Clear all current stepping setup.
- ClearStepping();
+ debug->ClearStepping();
// Set up for the remaining steps.
- PrepareStep(step_action, step_count);
+ debug->PrepareStep(step_action, step_count);
}
- if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
- SetAfterBreakTarget(frame);
- } else if (thread_local_.frame_drop_mode_ == FRAME_DROPPED_IN_IC_CALL) {
+ if (debug->thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
+ debug->SetAfterBreakTarget(frame);
+ } else if (debug->thread_local_.frame_drop_mode_ ==
+ FRAME_DROPPED_IN_IC_CALL) {
// We must have been calling IC stub. Do not go there anymore.
- Code* plain_return = Builtins::builtin(Builtins::PlainReturn_LiveEdit);
- thread_local_.after_break_target_ = plain_return->entry();
- } else if (thread_local_.frame_drop_mode_ ==
+ Code* plain_return =
+ Isolate::Current()->builtins()->builtin(
+ Builtins::kPlainReturn_LiveEdit);
+ debug->thread_local_.after_break_target_ = plain_return->entry();
+ } else if (debug->thread_local_.frame_drop_mode_ ==
FRAME_DROPPED_IN_DEBUG_SLOT_CALL) {
// Debug break slot stub does not return normally, instead it manually
// cleans the stack and jumps. We should patch the jump address.
- Code* plain_return = Builtins::builtin(Builtins::FrameDropper_LiveEdit);
- thread_local_.after_break_target_ = plain_return->entry();
- } else if (thread_local_.frame_drop_mode_ == FRAME_DROPPED_IN_DIRECT_CALL) {
+ Code* plain_return = Isolate::Current()->builtins()->builtin(
+ Builtins::kFrameDropper_LiveEdit);
+ debug->thread_local_.after_break_target_ = plain_return->entry();
+ } else if (debug->thread_local_.frame_drop_mode_ ==
+ FRAME_DROPPED_IN_DIRECT_CALL) {
// Nothing to do, after_break_target is not used here.
} else {
UNREACHABLE();
}
- return Heap::undefined_value();
+ return heap->undefined_value();
}
@@ -1003,56 +1035,59 @@ Object* Debug::Break(Arguments args) {
// triggered. This function returns a JSArray with the break point objects
// which is triggered.
Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
- int break_points_hit_count = 0;
- Handle<JSArray> break_points_hit = Factory::NewJSArray(1);
+ Factory* factory = isolate_->factory();
- // If there are multiple break points they are in a FixedArray.
+ // Count the number of break points hit. If there are multiple break points
+ // they are in a FixedArray.
+ Handle<FixedArray> break_points_hit;
+ int break_points_hit_count = 0;
ASSERT(!break_point_objects->IsUndefined());
if (break_point_objects->IsFixedArray()) {
Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
+ break_points_hit = factory->NewFixedArray(array->length());
for (int i = 0; i < array->length(); i++) {
Handle<Object> o(array->get(i));
if (CheckBreakPoint(o)) {
- SetElement(break_points_hit,
- break_points_hit_count++,
- o,
- kNonStrictMode);
+ break_points_hit->set(break_points_hit_count++, *o);
}
}
} else {
+ break_points_hit = factory->NewFixedArray(1);
if (CheckBreakPoint(break_point_objects)) {
- SetElement(break_points_hit,
- break_points_hit_count++,
- break_point_objects,
- kNonStrictMode);
+ break_points_hit->set(break_points_hit_count++, *break_point_objects);
}
}
// Return undefined if no break points were triggered.
if (break_points_hit_count == 0) {
- return Factory::undefined_value();
+ return factory->undefined_value();
}
- return break_points_hit;
+ // Return break points hit as a JSArray.
+ Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
+ result->set_length(Smi::FromInt(break_points_hit_count));
+ return result;
}
// Check whether a single break point object is triggered.
bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ Factory* factory = isolate_->factory();
+ HandleScope scope(isolate_);
// Ignore check if break point object is not a JSObject.
if (!break_point_object->IsJSObject()) return true;
- // Get the function CheckBreakPoint (defined in debug.js).
+ // Get the function IsBreakPointTriggered (defined in debug-debugger.js).
Handle<String> is_break_point_triggered_symbol =
- Factory::LookupAsciiSymbol("IsBreakPointTriggered");
+ factory->LookupAsciiSymbol("IsBreakPointTriggered");
Handle<JSFunction> check_break_point =
Handle<JSFunction>(JSFunction::cast(
debug_context()->global()->GetPropertyNoExceptionThrown(
*is_break_point_triggered_symbol)));
// Get the break id as an object.
- Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
+ Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
// Call HandleBreakPointx.
bool caught_exception = false;
@@ -1062,8 +1097,7 @@ bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
reinterpret_cast<Object**>(break_point_object.location())
};
Handle<Object> result = Execution::TryCall(check_break_point,
- Top::builtins(), argc, argv,
- &caught_exception);
+ isolate_->js_builtins_object(), argc, argv, &caught_exception);
// If exception or non boolean result handle as not triggered
if (caught_exception || !result->IsBoolean()) {
@@ -1071,7 +1105,8 @@ bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
}
// Return whether the break point is triggered.
- return *result == Heap::true_value();
+ ASSERT(!result.is_null());
+ return (*result)->IsTrue();
}
@@ -1092,7 +1127,7 @@ Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
Handle<Object> break_point_object,
int* source_position) {
- HandleScope scope;
+ HandleScope scope(isolate_);
if (!EnsureDebugInfo(shared)) {
// Return if retrieving debug info failed.
@@ -1116,7 +1151,7 @@ void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
- HandleScope scope;
+ HandleScope scope(isolate_);
DebugInfoListNode* node = debug_info_list_;
while (node != NULL) {
@@ -1222,7 +1257,8 @@ bool Debug::IsBreakOnException(ExceptionBreakType type) {
void Debug::PrepareStep(StepAction step_action, int step_count) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
ASSERT(Debug::InDebugger());
// Remember this step action and count.
@@ -1370,8 +1406,10 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
// Reverse lookup required as the minor key cannot be retrieved
// from the code object.
Handle<Object> obj(
- Heap::code_stubs()->SlowReverseLookup(*call_function_stub));
- ASSERT(*obj != Heap::undefined_value());
+ isolate_->heap()->code_stubs()->SlowReverseLookup(
+ *call_function_stub));
+ ASSERT(!obj.is_null());
+ ASSERT(!(*obj)->IsUndefined());
ASSERT(obj->IsSmi());
// Get the STUB key and extract major and minor key.
uint32_t key = Smi::cast(*obj)->value();
@@ -1489,18 +1527,16 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
return ComputeCallDebugBreak(code->arguments_count(), code->kind());
case Code::LOAD_IC:
- return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
+ return Isolate::Current()->builtins()->LoadIC_DebugBreak();
case Code::STORE_IC:
- return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
+ return Isolate::Current()->builtins()->StoreIC_DebugBreak();
case Code::KEYED_LOAD_IC:
- return Handle<Code>(
- Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
+ return Isolate::Current()->builtins()->KeyedLoadIC_DebugBreak();
case Code::KEYED_STORE_IC:
- return Handle<Code>(
- Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
+ return Isolate::Current()->builtins()->KeyedStoreIC_DebugBreak();
default:
UNREACHABLE();
@@ -1508,13 +1544,13 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
}
if (RelocInfo::IsConstructCall(mode)) {
Handle<Code> result =
- Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
+ Isolate::Current()->builtins()->ConstructCall_DebugBreak();
return result;
}
if (code->kind() == Code::STUB) {
ASSERT(code->major_key() == CodeStub::CallFunction);
Handle<Code> result =
- Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
+ Isolate::Current()->builtins()->StubNoRegisters_DebugBreak();
return result;
}
@@ -1526,13 +1562,15 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
// Simple function for returning the source positions for active break points.
Handle<Object> Debug::GetSourceBreakLocations(
Handle<SharedFunctionInfo> shared) {
- if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value());
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+ if (!HasDebugInfo(shared)) return Handle<Object>(heap->undefined_value());
Handle<DebugInfo> debug_info = GetDebugInfo(shared);
if (debug_info->GetBreakPointCount() == 0) {
- return Handle<Object>(Heap::undefined_value());
+ return Handle<Object>(heap->undefined_value());
}
Handle<FixedArray> locations =
- Factory::NewFixedArray(debug_info->GetBreakPointCount());
+ isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
int count = 0;
for (int i = 0; i < debug_info->break_points()->length(); i++) {
if (!debug_info->break_points()->get(i)->IsUndefined()) {
@@ -1578,13 +1616,13 @@ void Debug::HandleStepIn(Handle<JSFunction> function,
// Flood the function with one-shot break points if it is called from where
// step into was requested.
- if (fp == Debug::step_in_fp()) {
+ if (fp == step_in_fp()) {
// Don't allow step into functions in the native context.
if (!function->IsBuiltin()) {
if (function->shared()->code() ==
- Builtins::builtin(Builtins::FunctionApply) ||
+ Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply) ||
function->shared()->code() ==
- Builtins::builtin(Builtins::FunctionCall)) {
+ Isolate::Current()->builtins()->builtin(Builtins::kFunctionCall)) {
// Handle function.apply and function.call separately to flood the
// function to be called and not the code for Builtins::FunctionApply or
// Builtins::FunctionCall. The receiver of call/apply is the target
@@ -1678,7 +1716,7 @@ bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
}
// Create the debug info object.
- Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared);
+ Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared);
// Add debug info to the list.
DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
@@ -1705,7 +1743,8 @@ void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
} else {
prev->set_next(current->next());
}
- current->debug_info()->shared()->set_debug_info(Heap::undefined_value());
+ current->debug_info()->shared()->set_debug_info(
+ isolate_->heap()->undefined_value());
delete current;
// If there are no more debug info objects there are not more break
@@ -1723,7 +1762,8 @@ void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
// Get the executing function in which the debug break occurred.
Handle<SharedFunctionInfo> shared =
@@ -1737,7 +1777,7 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
Handle<Code> original_code(debug_info->original_code());
#ifdef DEBUG
// Get the code which is actually executing.
- Handle<Code> frame_code(frame->code());
+ Handle<Code> frame_code(frame->LookupCode(isolate_));
ASSERT(frame_code.is_identical_to(code));
#endif
@@ -1806,7 +1846,7 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
- HandleScope scope;
+ HandleScope scope(isolate_);
// Get the executing function in which the debug break occurred.
Handle<SharedFunctionInfo> shared =
@@ -1819,7 +1859,7 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
Handle<Code> code(debug_info->code());
#ifdef DEBUG
// Get the code which is actually executing.
- Handle<Code> frame_code(frame->code());
+ Handle<Code> frame_code(frame->LookupCode(Isolate::Current()));
ASSERT(frame_code.is_identical_to(code));
#endif
@@ -1850,19 +1890,20 @@ void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
bool Debug::IsDebugGlobal(GlobalObject* global) {
- return IsLoaded() && global == Debug::debug_context()->global();
+ return IsLoaded() && global == debug_context()->global();
}
void Debug::ClearMirrorCache() {
- PostponeInterruptsScope postpone;
- HandleScope scope;
- ASSERT(Top::context() == *Debug::debug_context());
+ ASSERT(Isolate::Current() == isolate_);
+ PostponeInterruptsScope postpone(isolate_);
+ HandleScope scope(isolate_);
+ ASSERT(isolate_->context() == *Debug::debug_context());
// Clear the mirror cache.
Handle<String> function_name =
- Factory::LookupSymbol(CStrVector("ClearMirrorCache"));
- Handle<Object> fun(Top::global()->GetPropertyNoExceptionThrown(
+ isolate_->factory()->LookupSymbol(CStrVector("ClearMirrorCache"));
+ Handle<Object> fun(Isolate::Current()->global()->GetPropertyNoExceptionThrown(
*function_name));
ASSERT(fun->IsJSFunction());
bool caught_exception;
@@ -1874,13 +1915,15 @@ void Debug::ClearMirrorCache() {
void Debug::CreateScriptCache() {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ Heap* heap = isolate_->heap();
+ HandleScope scope(isolate_);
// Perform two GCs to get rid of all unreferenced scripts. The first GC gets
// rid of all the cached script wrappers and the second gets rid of the
// scripts which are no longer referenced.
- Heap::CollectAllGarbage(false);
- Heap::CollectAllGarbage(false);
+ heap->CollectAllGarbage(false);
+ heap->CollectAllGarbage(false);
ASSERT(script_cache_ == NULL);
script_cache_ = new ScriptCache();
@@ -1914,6 +1957,7 @@ void Debug::AddScriptToScriptCache(Handle<Script> script) {
Handle<FixedArray> Debug::GetLoadedScripts() {
+ ASSERT(Isolate::Current() == isolate_);
// Create and fill the script cache when the loaded scripts is requested for
// the first time.
if (script_cache_ == NULL) {
@@ -1923,12 +1967,12 @@ Handle<FixedArray> Debug::GetLoadedScripts() {
// If the script cache is not active just return an empty array.
ASSERT(script_cache_ != NULL);
if (script_cache_ == NULL) {
- Factory::NewFixedArray(0);
+ isolate_->factory()->NewFixedArray(0);
}
// Perform GC to get unreferenced scripts evicted from the cache before
// returning the content.
- Heap::CollectAllGarbage(false);
+ isolate_->heap()->CollectAllGarbage(false);
// Get the scripts from the cache.
return script_cache_->GetScripts();
@@ -1943,51 +1987,66 @@ void Debug::AfterGarbageCollection() {
}
-Mutex* Debugger::debugger_access_ = OS::CreateMutex();
-Handle<Object> Debugger::event_listener_ = Handle<Object>();
-Handle<Object> Debugger::event_listener_data_ = Handle<Object>();
-bool Debugger::compiling_natives_ = false;
-bool Debugger::is_loading_debugger_ = false;
-bool Debugger::never_unload_debugger_ = false;
-v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL;
-bool Debugger::debugger_unload_pending_ = false;
-v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
-Mutex* Debugger::dispatch_handler_access_ = OS::CreateMutex();
-v8::Debug::DebugMessageDispatchHandler
- Debugger::debug_message_dispatch_handler_ = NULL;
-MessageDispatchHelperThread* Debugger::message_dispatch_helper_thread_ = NULL;
-int Debugger::host_dispatch_micros_ = 100 * 1000;
-DebuggerAgent* Debugger::agent_ = NULL;
-LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize);
-Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0);
-LockingCommandMessageQueue Debugger::event_command_queue_(kQueueInitialSize);
+Debugger::Debugger()
+ : debugger_access_(OS::CreateMutex()),
+ event_listener_(Handle<Object>()),
+ event_listener_data_(Handle<Object>()),
+ compiling_natives_(false),
+ is_loading_debugger_(false),
+ never_unload_debugger_(false),
+ message_handler_(NULL),
+ debugger_unload_pending_(false),
+ host_dispatch_handler_(NULL),
+ dispatch_handler_access_(OS::CreateMutex()),
+ debug_message_dispatch_handler_(NULL),
+ message_dispatch_helper_thread_(NULL),
+ host_dispatch_micros_(100 * 1000),
+ agent_(NULL),
+ command_queue_(kQueueInitialSize),
+ command_received_(OS::CreateSemaphore(0)),
+ event_command_queue_(kQueueInitialSize) {
+}
+
+
+Debugger::~Debugger() {
+ delete debugger_access_;
+ debugger_access_ = 0;
+ delete dispatch_handler_access_;
+ dispatch_handler_access_ = 0;
+ delete command_received_;
+ command_received_ = 0;
+}
Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
int argc, Object*** argv,
bool* caught_exception) {
- ASSERT(Top::context() == *Debug::debug_context());
+ ASSERT(Isolate::Current() == isolate_);
+ ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
// Create the execution state object.
- Handle<String> constructor_str = Factory::LookupSymbol(constructor_name);
- Handle<Object> constructor(Top::global()->GetPropertyNoExceptionThrown(
- *constructor_str));
+ Handle<String> constructor_str =
+ isolate_->factory()->LookupSymbol(constructor_name);
+ Handle<Object> constructor(
+ isolate_->global()->GetPropertyNoExceptionThrown(*constructor_str));
ASSERT(constructor->IsJSFunction());
if (!constructor->IsJSFunction()) {
*caught_exception = true;
- return Factory::undefined_value();
+ return isolate_->factory()->undefined_value();
}
Handle<Object> js_object = Execution::TryCall(
Handle<JSFunction>::cast(constructor),
- Handle<JSObject>(Debug::debug_context()->global()), argc, argv,
- caught_exception);
+ Handle<JSObject>(isolate_->debug()->debug_context()->global()),
+ argc, argv, caught_exception);
return js_object;
}
Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
+ ASSERT(Isolate::Current() == isolate_);
// Create the execution state object.
- Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
+ Handle<Object> break_id = isolate_->factory()->NewNumberFromInt(
+ isolate_->debug()->break_id());
const int argc = 1;
Object** argv[argc] = { break_id.location() };
return MakeJSObject(CStrVector("MakeExecutionState"),
@@ -1998,6 +2057,7 @@ Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
Handle<Object> break_points_hit,
bool* caught_exception) {
+ ASSERT(Isolate::Current() == isolate_);
// Create the new break event object.
const int argc = 2;
Object** argv[argc] = { exec_state.location(),
@@ -2013,12 +2073,14 @@ Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
Handle<Object> exception,
bool uncaught,
bool* caught_exception) {
+ ASSERT(Isolate::Current() == isolate_);
+ Factory* factory = isolate_->factory();
// Create the new exception event object.
const int argc = 3;
Object** argv[argc] = { exec_state.location(),
exception.location(),
- uncaught ? Factory::true_value().location() :
- Factory::false_value().location()};
+ uncaught ? factory->true_value().location() :
+ factory->false_value().location()};
return MakeJSObject(CStrVector("MakeExceptionEvent"),
argc, argv, caught_exception);
}
@@ -2026,6 +2088,7 @@ Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
bool* caught_exception) {
+ ASSERT(Isolate::Current() == isolate_);
// Create the new function event object.
const int argc = 1;
Object** argv[argc] = { function.location() };
@@ -2037,14 +2100,16 @@ Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
bool before,
bool* caught_exception) {
+ ASSERT(Isolate::Current() == isolate_);
+ Factory* factory = isolate_->factory();
// Create the compile event object.
Handle<Object> exec_state = MakeExecutionState(caught_exception);
Handle<Object> script_wrapper = GetScriptWrapper(script);
const int argc = 3;
Object** argv[argc] = { exec_state.location(),
script_wrapper.location(),
- before ? Factory::true_value().location() :
- Factory::false_value().location() };
+ before ? factory->true_value().location() :
+ factory->false_value().location() };
return MakeJSObject(CStrVector("MakeCompileEvent"),
argc,
@@ -2055,6 +2120,7 @@ Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
bool* caught_exception) {
+ ASSERT(Isolate::Current() == isolate_);
// Create the script collected event object.
Handle<Object> exec_state = MakeExecutionState(caught_exception);
Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
@@ -2069,20 +2135,22 @@ Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
void Debugger::OnException(Handle<Object> exception, bool uncaught) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
+ Debug* debug = isolate_->debug();
// Bail out based on state or if there is no listener for this event
- if (Debug::InDebugger()) return;
+ if (debug->InDebugger()) return;
if (!Debugger::EventActive(v8::Exception)) return;
// Bail out if exception breaks are not active
if (uncaught) {
// Uncaught exceptions are reported by either flags.
- if (!(Debug::break_on_uncaught_exception() ||
- Debug::break_on_exception())) return;
+ if (!(debug->break_on_uncaught_exception() ||
+ debug->break_on_exception())) return;
} else {
// Caught exceptions are reported is activated.
- if (!Debug::break_on_exception()) return;
+ if (!debug->break_on_exception()) return;
}
// Enter the debugger.
@@ -2090,7 +2158,7 @@ void Debugger::OnException(Handle<Object> exception, bool uncaught) {
if (debugger.FailedToEnter()) return;
// Clear all current stepping setup.
- Debug::ClearStepping();
+ debug->ClearStepping();
// Create the event data object.
bool caught_exception = false;
Handle<Object> exec_state = MakeExecutionState(&caught_exception);
@@ -2112,16 +2180,17 @@ void Debugger::OnException(Handle<Object> exception, bool uncaught) {
void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
bool auto_continue) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
// Debugger has already been entered by caller.
- ASSERT(Top::context() == *Debug::debug_context());
+ ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
// Bail out if there is no listener for this event
if (!Debugger::EventActive(v8::Break)) return;
// Debugger must be entered in advance.
- ASSERT(Top::context() == *Debug::debug_context());
+ ASSERT(Isolate::Current()->context() == *isolate_->debug()->debug_context());
// Create the event data object.
bool caught_exception = false;
@@ -2144,10 +2213,11 @@ void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
void Debugger::OnBeforeCompile(Handle<Script> script) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
// Bail out based on state or if there is no listener for this event
- if (Debug::InDebugger()) return;
+ if (isolate_->debug()->InDebugger()) return;
if (compiling_natives()) return;
if (!EventActive(v8::BeforeCompile)) return;
@@ -2173,10 +2243,12 @@ void Debugger::OnBeforeCompile(Handle<Script> script) {
// Handle debugger actions when a new script is compiled.
void Debugger::OnAfterCompile(Handle<Script> script,
AfterCompileFlags after_compile_flags) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
+ Debug* debug = isolate_->debug();
// Add the newly compiled script to the script cache.
- Debug::AddScriptToScriptCache(script);
+ debug->AddScriptToScriptCache(script);
// No more to do if not debugging.
if (!IsDebuggerActive()) return;
@@ -2185,7 +2257,7 @@ void Debugger::OnAfterCompile(Handle<Script> script,
if (compiling_natives()) return;
// Store whether in debugger before entering debugger.
- bool in_debugger = Debug::InDebugger();
+ bool in_debugger = debug->InDebugger();
// Enter the debugger.
EnterDebugger debugger;
@@ -2196,9 +2268,9 @@ void Debugger::OnAfterCompile(Handle<Script> script,
// Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
Handle<String> update_script_break_points_symbol =
- Factory::LookupAsciiSymbol("UpdateScriptBreakPoints");
+ isolate_->factory()->LookupAsciiSymbol("UpdateScriptBreakPoints");
Handle<Object> update_script_break_points =
- Handle<Object>(Debug::debug_context()->global()->
+ Handle<Object>(debug->debug_context()->global()->
GetPropertyNoExceptionThrown(*update_script_break_points_symbol));
if (!update_script_break_points->IsJSFunction()) {
return;
@@ -2215,7 +2287,7 @@ void Debugger::OnAfterCompile(Handle<Script> script,
Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
Handle<Object> result = Execution::TryCall(
Handle<JSFunction>::cast(update_script_break_points),
- Top::builtins(), argc, argv,
+ Isolate::Current()->js_builtins_object(), argc, argv,
&caught_exception);
if (caught_exception) {
return;
@@ -2240,7 +2312,8 @@ void Debugger::OnAfterCompile(Handle<Script> script,
void Debugger::OnScriptCollected(int id) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
// No more to do if not debugging.
if (!IsDebuggerActive()) return;
@@ -2269,11 +2342,12 @@ void Debugger::OnScriptCollected(int id) {
void Debugger::ProcessDebugEvent(v8::DebugEvent event,
Handle<JSObject> event_data,
bool auto_continue) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
// Clear any pending debug break if this is a real break.
if (!auto_continue) {
- Debug::clear_interrupt_pending(DEBUGBREAK);
+ isolate_->debug()->clear_interrupt_pending(DEBUGBREAK);
}
// Create the execution state.
@@ -2344,6 +2418,7 @@ void Debugger::CallJSEventCallback(v8::DebugEvent event,
Handle<Object> exec_state,
Handle<Object> event_data) {
ASSERT(event_listener_->IsJSFunction());
+ ASSERT(Isolate::Current() == isolate_);
Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
// Invoke the JavaScript debug event listener.
@@ -2353,25 +2428,29 @@ void Debugger::CallJSEventCallback(v8::DebugEvent event,
Handle<Object>::cast(event_data).location(),
event_listener_data_.location() };
bool caught_exception = false;
- Execution::TryCall(fun, Top::global(), argc, argv, &caught_exception);
+ Execution::TryCall(fun, isolate_->global(), argc, argv, &caught_exception);
// Silently ignore exceptions from debug event listeners.
}
Handle<Context> Debugger::GetDebugContext() {
- never_unload_debugger_ = true;
- EnterDebugger debugger;
- return Debug::debug_context();
+ ASSERT(Isolate::Current() == isolate_);
+ never_unload_debugger_ = true;
+ EnterDebugger debugger;
+ return isolate_->debug()->debug_context();
}
void Debugger::UnloadDebugger() {
+ ASSERT(Isolate::Current() == isolate_);
+ Debug* debug = isolate_->debug();
+
// Make sure that there are no breakpoints left.
- Debug::ClearAllBreakPoints();
+ debug->ClearAllBreakPoints();
// Unload the debugger if feasible.
if (!never_unload_debugger_) {
- Debug::Unload();
+ debug->Unload();
}
// Clear the flag indicating that the debugger should be unloaded.
@@ -2383,9 +2462,10 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
Handle<JSObject> exec_state,
Handle<JSObject> event_data,
bool auto_continue) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
- if (!Debug::Load()) return;
+ if (!isolate_->debug()->Load()) return;
// Process the individual events.
bool sendEventMessage = false;
@@ -2414,8 +2494,8 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
// The debug command interrupt flag might have been set when the command was
// added. It should be enough to clear the flag only once while we are in the
// debugger.
- ASSERT(Debug::InDebugger());
- StackGuard::Continue(DEBUGCOMMAND);
+ ASSERT(isolate_->debug()->InDebugger());
+ isolate_->stack_guard()->Continue(DEBUGCOMMAND);
// Notify the debugger that a debug event has occurred unless auto continue is
// active in which case no event is send.
@@ -2478,7 +2558,7 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
// Get the command from the queue.
CommandMessage command = command_queue_.Get();
- Logger::DebugTag("Got request from command queue, in interactive loop.");
+ LOGGER->DebugTag("Got request from command queue, in interactive loop.");
if (!Debugger::IsDebuggerActive()) {
// Delete command text and user data.
command.Dispose();
@@ -2552,17 +2632,19 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
void Debugger::SetEventListener(Handle<Object> callback,
Handle<Object> data) {
- HandleScope scope;
+ ASSERT(Isolate::Current() == isolate_);
+ HandleScope scope(isolate_);
+ GlobalHandles* global_handles = isolate_->global_handles();
// Clear the global handles for the event listener and the event listener data
// object.
if (!event_listener_.is_null()) {
- GlobalHandles::Destroy(
+ global_handles->Destroy(
reinterpret_cast<Object**>(event_listener_.location()));
event_listener_ = Handle<Object>();
}
if (!event_listener_data_.is_null()) {
- GlobalHandles::Destroy(
+ global_handles->Destroy(
reinterpret_cast<Object**>(event_listener_data_.location()));
event_listener_data_ = Handle<Object>();
}
@@ -2570,11 +2652,13 @@ void Debugger::SetEventListener(Handle<Object> callback,
// If there is a new debug event listener register it together with its data
// object.
if (!callback->IsUndefined() && !callback->IsNull()) {
- event_listener_ = Handle<Object>::cast(GlobalHandles::Create(*callback));
+ event_listener_ = Handle<Object>::cast(
+ global_handles->Create(*callback));
if (data.is_null()) {
- data = Factory::undefined_value();
+ data = isolate_->factory()->undefined_value();
}
- event_listener_data_ = Handle<Object>::cast(GlobalHandles::Create(*data));
+ event_listener_data_ = Handle<Object>::cast(
+ global_handles->Create(*data));
}
ListenersChanged();
@@ -2582,6 +2666,7 @@ void Debugger::SetEventListener(Handle<Object> callback,
void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
+ ASSERT(Isolate::Current() == isolate_);
ScopedLock with(debugger_access_);
message_handler_ = handler;
@@ -2589,7 +2674,7 @@ void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
if (handler == NULL) {
// Send an empty command to the debugger if in a break to make JavaScript
// run again if the debugger is closed.
- if (Debug::InDebugger()) {
+ if (isolate_->debug()->InDebugger()) {
ProcessCommand(Vector<const uint16_t>::empty());
}
}
@@ -2597,12 +2682,13 @@ void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
void Debugger::ListenersChanged() {
+ ASSERT(Isolate::Current() == isolate_);
if (IsDebuggerActive()) {
// Disable the compilation cache when the debugger is active.
- CompilationCache::Disable();
+ isolate_->compilation_cache()->Disable();
debugger_unload_pending_ = false;
} else {
- CompilationCache::Enable();
+ isolate_->compilation_cache()->Enable();
// Unload the debugger if event listener and message handler cleared.
// Schedule this for later, because we may be in non-V8 thread.
debugger_unload_pending_ = true;
@@ -2612,6 +2698,7 @@ void Debugger::ListenersChanged() {
void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
int period) {
+ ASSERT(Isolate::Current() == isolate_);
host_dispatch_handler_ = handler;
host_dispatch_micros_ = period * 1000;
}
@@ -2619,11 +2706,12 @@ void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
void Debugger::SetDebugMessageDispatchHandler(
v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
+ ASSERT(Isolate::Current() == isolate_);
ScopedLock with(dispatch_handler_access_);
debug_message_dispatch_handler_ = handler;
if (provide_locker && message_dispatch_helper_thread_ == NULL) {
- message_dispatch_helper_thread_ = new MessageDispatchHelperThread;
+ message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_);
message_dispatch_helper_thread_->Start();
}
}
@@ -2632,6 +2720,7 @@ void Debugger::SetDebugMessageDispatchHandler(
// Calls the registered debug message handler. This callback is part of the
// public API.
void Debugger::InvokeMessageHandler(MessageImpl message) {
+ ASSERT(Isolate::Current() == isolate_);
ScopedLock with(debugger_access_);
if (message_handler_ != NULL) {
@@ -2646,18 +2735,19 @@ void Debugger::InvokeMessageHandler(MessageImpl message) {
// by the API client thread.
void Debugger::ProcessCommand(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data) {
+ ASSERT(Isolate::Current() == isolate_);
// Need to cast away const.
CommandMessage message = CommandMessage::New(
Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
command.length()),
client_data);
- Logger::DebugTag("Put command on command_queue.");
+ LOGGER->DebugTag("Put command on command_queue.");
command_queue_.Put(message);
command_received_->Signal();
// Set the debug command break flag to have the command processed.
- if (!Debug::InDebugger()) {
- StackGuard::DebugCommand();
+ if (!isolate_->debug()->InDebugger()) {
+ isolate_->stack_guard()->DebugCommand();
}
MessageDispatchHelperThread* dispatch_thread;
@@ -2675,22 +2765,25 @@ void Debugger::ProcessCommand(Vector<const uint16_t> command,
bool Debugger::HasCommands() {
+ ASSERT(Isolate::Current() == isolate_);
return !command_queue_.IsEmpty();
}
void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
+ ASSERT(Isolate::Current() == isolate_);
CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data);
event_command_queue_.Put(message);
// Set the debug command break flag to have the command processed.
- if (!Debug::InDebugger()) {
- StackGuard::DebugCommand();
+ if (!isolate_->debug()->InDebugger()) {
+ isolate_->stack_guard()->DebugCommand();
}
}
bool Debugger::IsDebuggerActive() {
+ ASSERT(Isolate::Current() == isolate_);
ScopedLock with(debugger_access_);
return message_handler_ != NULL || !event_listener_.is_null();
@@ -2700,27 +2793,28 @@ bool Debugger::IsDebuggerActive() {
Handle<Object> Debugger::Call(Handle<JSFunction> fun,
Handle<Object> data,
bool* pending_exception) {
+ ASSERT(Isolate::Current() == isolate_);
// When calling functions in the debugger prevent it from beeing unloaded.
Debugger::never_unload_debugger_ = true;
// Enter the debugger.
EnterDebugger debugger;
if (debugger.FailedToEnter()) {
- return Factory::undefined_value();
+ return isolate_->factory()->undefined_value();
}
// Create the execution state.
bool caught_exception = false;
Handle<Object> exec_state = MakeExecutionState(&caught_exception);
if (caught_exception) {
- return Factory::undefined_value();
+ return isolate_->factory()->undefined_value();
}
static const int kArgc = 2;
Object** argv[kArgc] = { exec_state.location(), data.location() };
Handle<Object> result = Execution::Call(
fun,
- Handle<Object>(Debug::debug_context_->global_proxy()),
+ Handle<Object>(isolate_->debug()->debug_context_->global_proxy()),
kArgc,
argv,
pending_exception);
@@ -2735,6 +2829,7 @@ static void StubMessageHandler2(const v8::Debug::Message& message) {
bool Debugger::StartAgent(const char* name, int port,
bool wait_for_connection) {
+ ASSERT(Isolate::Current() == isolate_);
if (wait_for_connection) {
// Suspend V8 if it is already running or set V8 to suspend whenever
// it starts.
@@ -2748,7 +2843,7 @@ bool Debugger::StartAgent(const char* name, int port,
if (Socket::Setup()) {
if (agent_ == NULL) {
- agent_ = new DebuggerAgent(name, port);
+ agent_ = new DebuggerAgent(isolate_, name, port);
agent_->Start();
}
return true;
@@ -2759,6 +2854,7 @@ bool Debugger::StartAgent(const char* name, int port,
void Debugger::StopAgent() {
+ ASSERT(Isolate::Current() == isolate_);
if (agent_ != NULL) {
agent_->Shutdown();
agent_->Join();
@@ -2769,12 +2865,14 @@ void Debugger::StopAgent() {
void Debugger::WaitForAgent() {
+ ASSERT(Isolate::Current() == isolate_);
if (agent_ != NULL)
agent_->WaitUntilListening();
}
void Debugger::CallMessageDispatchHandler() {
+ ASSERT(Isolate::Current() == isolate_);
v8::Debug::DebugMessageDispatchHandler handler;
{
ScopedLock with(dispatch_handler_access_);
@@ -2878,10 +2976,11 @@ v8::Handle<v8::String> MessageImpl::GetJSON() const {
v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
- v8::Handle<v8::Context> context = GetDebugEventContext();
- // Top::context() may be NULL when "script collected" event occures.
+ Isolate* isolate = Isolate::Current();
+ v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
+ // Isolate::context() may be NULL when "script collected" event occures.
ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
- return GetDebugEventContext();
+ return GetDebugEventContext(isolate);
}
@@ -2918,7 +3017,7 @@ v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
- return GetDebugEventContext();
+ return GetDebugEventContext(Isolate::Current());
}
@@ -3027,7 +3126,7 @@ bool LockingCommandMessageQueue::IsEmpty() const {
CommandMessage LockingCommandMessageQueue::Get() {
ScopedLock sl(lock_);
CommandMessage result = queue_.Get();
- Logger::DebugEvent("Get", result.text());
+ LOGGER->DebugEvent("Get", result.text());
return result;
}
@@ -3035,7 +3134,7 @@ CommandMessage LockingCommandMessageQueue::Get() {
void LockingCommandMessageQueue::Put(const CommandMessage& message) {
ScopedLock sl(lock_);
queue_.Put(message);
- Logger::DebugEvent("Put", message.text());
+ LOGGER->DebugEvent("Put", message.text());
}
@@ -3045,8 +3144,8 @@ void LockingCommandMessageQueue::Clear() {
}
-MessageDispatchHelperThread::MessageDispatchHelperThread()
- : Thread("v8:MsgDispHelpr"),
+MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
+ : Thread(isolate, "v8:MsgDispHelpr"),
sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
already_signalled_(false) {
}
@@ -3079,7 +3178,7 @@ void MessageDispatchHelperThread::Run() {
}
{
Locker locker;
- Debugger::CallMessageDispatchHandler();
+ Isolate::Current()->debugger()->CallMessageDispatchHandler();
}
}
}
diff --git a/src/debug.h b/src/debug.h
index 85c4d534..d5125956 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -28,6 +28,7 @@
#ifndef V8_DEBUG_H_
#define V8_DEBUG_H_
+#include "arguments.h"
#include "assembler.h"
#include "debug-agent.h"
#include "execution.h"
@@ -210,7 +211,6 @@ class DebugInfoListNode {
DebugInfoListNode* next_;
};
-
// This class contains the debugger support. The main purpose is to handle
// setting break points in the code.
//
@@ -220,33 +220,33 @@ class DebugInfoListNode {
// DebugInfo.
class Debug {
public:
- static void Setup(bool create_heap_objects);
- static bool Load();
- static void Unload();
- static bool IsLoaded() { return !debug_context_.is_null(); }
- static bool InDebugger() { return thread_local_.debugger_entry_ != NULL; }
- static void PreemptionWhileInDebugger();
- static void Iterate(ObjectVisitor* v);
-
- static Object* Break(Arguments args);
- static void SetBreakPoint(Handle<SharedFunctionInfo> shared,
- Handle<Object> break_point_object,
- int* source_position);
- static void ClearBreakPoint(Handle<Object> break_point_object);
- static void ClearAllBreakPoints();
- static void FloodWithOneShot(Handle<SharedFunctionInfo> shared);
- static void FloodHandlerWithOneShot();
- static void ChangeBreakOnException(ExceptionBreakType type, bool enable);
- static bool IsBreakOnException(ExceptionBreakType type);
- static void PrepareStep(StepAction step_action, int step_count);
- static void ClearStepping();
- static bool StepNextContinue(BreakLocationIterator* break_location_iterator,
- JavaScriptFrame* frame);
+ void Setup(bool create_heap_objects);
+ bool Load();
+ void Unload();
+ bool IsLoaded() { return !debug_context_.is_null(); }
+ bool InDebugger() { return thread_local_.debugger_entry_ != NULL; }
+ void PreemptionWhileInDebugger();
+ void Iterate(ObjectVisitor* v);
+
+ static Object* Break(RUNTIME_CALLING_CONVENTION);
+ void SetBreakPoint(Handle<SharedFunctionInfo> shared,
+ Handle<Object> break_point_object,
+ int* source_position);
+ void ClearBreakPoint(Handle<Object> break_point_object);
+ void ClearAllBreakPoints();
+ void FloodWithOneShot(Handle<SharedFunctionInfo> shared);
+ void FloodHandlerWithOneShot();
+ void ChangeBreakOnException(ExceptionBreakType type, bool enable);
+ bool IsBreakOnException(ExceptionBreakType type);
+ void PrepareStep(StepAction step_action, int step_count);
+ void ClearStepping();
+ bool StepNextContinue(BreakLocationIterator* break_location_iterator,
+ JavaScriptFrame* frame);
static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
// Returns whether the operation succeeded.
- static bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
+ bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
// Returns true if the current stub call is patched to call the debugger.
static bool IsDebugBreak(Address addr);
@@ -266,66 +266,66 @@ class Debug {
Handle<SharedFunctionInfo> shared);
// Getter for the debug_context.
- inline static Handle<Context> debug_context() { return debug_context_; }
+ inline Handle<Context> debug_context() { return debug_context_; }
// Check whether a global object is the debug global object.
- static bool IsDebugGlobal(GlobalObject* global);
+ bool IsDebugGlobal(GlobalObject* global);
// Check whether this frame is just about to return.
- static bool IsBreakAtReturn(JavaScriptFrame* frame);
+ bool IsBreakAtReturn(JavaScriptFrame* frame);
// Fast check to see if any break points are active.
- inline static bool has_break_points() { return has_break_points_; }
+ inline bool has_break_points() { return has_break_points_; }
- static void NewBreak(StackFrame::Id break_frame_id);
- static void SetBreak(StackFrame::Id break_frame_id, int break_id);
- static StackFrame::Id break_frame_id() {
+ void NewBreak(StackFrame::Id break_frame_id);
+ void SetBreak(StackFrame::Id break_frame_id, int break_id);
+ StackFrame::Id break_frame_id() {
return thread_local_.break_frame_id_;
}
- static int break_id() { return thread_local_.break_id_; }
+ int break_id() { return thread_local_.break_id_; }
- static bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
- static void HandleStepIn(Handle<JSFunction> function,
- Handle<Object> holder,
- Address fp,
- bool is_constructor);
- static Address step_in_fp() { return thread_local_.step_into_fp_; }
- static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; }
+ bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
+ void HandleStepIn(Handle<JSFunction> function,
+ Handle<Object> holder,
+ Address fp,
+ bool is_constructor);
+ Address step_in_fp() { return thread_local_.step_into_fp_; }
+ Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; }
- static bool StepOutActive() { return thread_local_.step_out_fp_ != 0; }
- static Address step_out_fp() { return thread_local_.step_out_fp_; }
+ bool StepOutActive() { return thread_local_.step_out_fp_ != 0; }
+ Address step_out_fp() { return thread_local_.step_out_fp_; }
- static EnterDebugger* debugger_entry() {
+ EnterDebugger* debugger_entry() {
return thread_local_.debugger_entry_;
}
- static void set_debugger_entry(EnterDebugger* entry) {
+ void set_debugger_entry(EnterDebugger* entry) {
thread_local_.debugger_entry_ = entry;
}
// Check whether any of the specified interrupts are pending.
- static bool is_interrupt_pending(InterruptFlag what) {
+ bool is_interrupt_pending(InterruptFlag what) {
return (thread_local_.pending_interrupts_ & what) != 0;
}
// Set specified interrupts as pending.
- static void set_interrupts_pending(InterruptFlag what) {
+ void set_interrupts_pending(InterruptFlag what) {
thread_local_.pending_interrupts_ |= what;
}
// Clear specified interrupts from pending.
- static void clear_interrupt_pending(InterruptFlag what) {
+ void clear_interrupt_pending(InterruptFlag what) {
thread_local_.pending_interrupts_ &= ~static_cast<int>(what);
}
// Getter and setter for the disable break state.
- static bool disable_break() { return disable_break_; }
- static void set_disable_break(bool disable_break) {
+ bool disable_break() { return disable_break_; }
+ void set_disable_break(bool disable_break) {
disable_break_ = disable_break;
}
// Getters for the current exception break state.
- static bool break_on_exception() { return break_on_exception_; }
- static bool break_on_uncaught_exception() {
+ bool break_on_exception() { return break_on_exception_; }
+ bool break_on_uncaught_exception() {
return break_on_uncaught_exception_;
}
@@ -337,34 +337,35 @@ class Debug {
};
// Support for setting the address to jump to when returning from break point.
- static Address* after_break_target_address() {
+ Address* after_break_target_address() {
return reinterpret_cast<Address*>(&thread_local_.after_break_target_);
}
- static Address* restarter_frame_function_pointer_address() {
+ Address* restarter_frame_function_pointer_address() {
Object*** address = &thread_local_.restarter_frame_function_pointer_;
return reinterpret_cast<Address*>(address);
}
// Support for saving/restoring registers when handling debug break calls.
- static Object** register_address(int r) {
+ Object** register_address(int r) {
return &registers_[r];
}
// Access to the debug break on return code.
- static Code* debug_break_return() { return debug_break_return_; }
- static Code** debug_break_return_address() {
+ Code* debug_break_return() { return debug_break_return_; }
+ Code** debug_break_return_address() {
return &debug_break_return_;
}
// Access to the debug break in debug break slot code.
- static Code* debug_break_slot() { return debug_break_slot_; }
- static Code** debug_break_slot_address() {
+ Code* debug_break_slot() { return debug_break_slot_; }
+ Code** debug_break_slot_address() {
return &debug_break_slot_;
}
static const int kEstimatedNofDebugInfoEntries = 16;
static const int kEstimatedNofBreakPointsInFunction = 16;
+ // Passed to MakeWeak.
static void HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data);
friend class Debugger;
@@ -372,22 +373,22 @@ class Debug {
friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc
// Threading support.
- static char* ArchiveDebug(char* to);
- static char* RestoreDebug(char* from);
+ char* ArchiveDebug(char* to);
+ char* RestoreDebug(char* from);
static int ArchiveSpacePerThread();
- static void FreeThreadResources() { }
+ void FreeThreadResources() { }
// Mirror cache handling.
- static void ClearMirrorCache();
+ void ClearMirrorCache();
// Script cache handling.
- static void CreateScriptCache();
- static void DestroyScriptCache();
- static void AddScriptToScriptCache(Handle<Script> script);
- static Handle<FixedArray> GetLoadedScripts();
+ void CreateScriptCache();
+ void DestroyScriptCache();
+ void AddScriptToScriptCache(Handle<Script> script);
+ Handle<FixedArray> GetLoadedScripts();
// Garbage collection notifications.
- static void AfterGarbageCollection();
+ void AfterGarbageCollection();
// Code generator routines.
static void GenerateSlot(MacroAssembler* masm);
@@ -424,7 +425,7 @@ class Debug {
FRAME_DROPPED_IN_DIRECT_CALL
};
- static void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
+ void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
FrameDropMode mode,
Object** restarter_frame_function_pointer);
@@ -445,35 +446,38 @@ class Debug {
static const bool kFrameDropperSupported;
private:
+ explicit Debug(Isolate* isolate);
+ ~Debug();
+
static bool CompileDebuggerScript(int index);
- static void ClearOneShot();
- static void ActivateStepIn(StackFrame* frame);
- static void ClearStepIn();
- static void ActivateStepOut(StackFrame* frame);
- static void ClearStepOut();
- static void ClearStepNext();
+ void ClearOneShot();
+ void ActivateStepIn(StackFrame* frame);
+ void ClearStepIn();
+ void ActivateStepOut(StackFrame* frame);
+ void ClearStepOut();
+ void ClearStepNext();
// Returns whether the compile succeeded.
- static void RemoveDebugInfo(Handle<DebugInfo> debug_info);
- static void SetAfterBreakTarget(JavaScriptFrame* frame);
- static Handle<Object> CheckBreakPoints(Handle<Object> break_point);
- static bool CheckBreakPoint(Handle<Object> break_point_object);
+ void RemoveDebugInfo(Handle<DebugInfo> debug_info);
+ void SetAfterBreakTarget(JavaScriptFrame* frame);
+ Handle<Object> CheckBreakPoints(Handle<Object> break_point);
+ bool CheckBreakPoint(Handle<Object> break_point_object);
// Global handle to debug context where all the debugger JavaScript code is
// loaded.
- static Handle<Context> debug_context_;
+ Handle<Context> debug_context_;
// Boolean state indicating whether any break points are set.
- static bool has_break_points_;
+ bool has_break_points_;
// Cache of all scripts in the heap.
- static ScriptCache* script_cache_;
+ ScriptCache* script_cache_;
// List of active debug info objects.
- static DebugInfoListNode* debug_info_list_;
+ DebugInfoListNode* debug_info_list_;
- static bool disable_break_;
- static bool break_on_exception_;
- static bool break_on_uncaught_exception_;
+ bool disable_break_;
+ bool break_on_exception_;
+ bool break_on_uncaught_exception_;
// Per-thread data.
class ThreadLocal {
@@ -526,15 +530,19 @@ class Debug {
};
// Storage location for registers when handling debug break calls
- static JSCallerSavedBuffer registers_;
- static ThreadLocal thread_local_;
- static void ThreadInit();
+ JSCallerSavedBuffer registers_;
+ ThreadLocal thread_local_;
+ void ThreadInit();
// Code to call for handling debug break on return.
- static Code* debug_break_return_;
+ Code* debug_break_return_;
// Code to call for handling debug break in debug break slots.
- static Code* debug_break_slot_;
+ Code* debug_break_slot_;
+
+ Isolate* isolate_;
+
+ friend class Isolate;
DISALLOW_COPY_AND_ASSIGN(Debug);
};
@@ -680,95 +688,97 @@ class LockingCommandMessageQueue BASE_EMBEDDED {
class Debugger {
public:
- static void DebugRequest(const uint16_t* json_request, int length);
-
- static Handle<Object> MakeJSObject(Vector<const char> constructor_name,
- int argc, Object*** argv,
- bool* caught_exception);
- static Handle<Object> MakeExecutionState(bool* caught_exception);
- static Handle<Object> MakeBreakEvent(Handle<Object> exec_state,
- Handle<Object> break_points_hit,
- bool* caught_exception);
- static Handle<Object> MakeExceptionEvent(Handle<Object> exec_state,
- Handle<Object> exception,
- bool uncaught,
- bool* caught_exception);
- static Handle<Object> MakeNewFunctionEvent(Handle<Object> func,
- bool* caught_exception);
- static Handle<Object> MakeCompileEvent(Handle<Script> script,
- bool before,
- bool* caught_exception);
- static Handle<Object> MakeScriptCollectedEvent(int id,
- bool* caught_exception);
- static void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
- static void OnException(Handle<Object> exception, bool uncaught);
- static void OnBeforeCompile(Handle<Script> script);
+ ~Debugger();
+
+ void DebugRequest(const uint16_t* json_request, int length);
+
+ Handle<Object> MakeJSObject(Vector<const char> constructor_name,
+ int argc, Object*** argv,
+ bool* caught_exception);
+ Handle<Object> MakeExecutionState(bool* caught_exception);
+ Handle<Object> MakeBreakEvent(Handle<Object> exec_state,
+ Handle<Object> break_points_hit,
+ bool* caught_exception);
+ Handle<Object> MakeExceptionEvent(Handle<Object> exec_state,
+ Handle<Object> exception,
+ bool uncaught,
+ bool* caught_exception);
+ Handle<Object> MakeNewFunctionEvent(Handle<Object> func,
+ bool* caught_exception);
+ Handle<Object> MakeCompileEvent(Handle<Script> script,
+ bool before,
+ bool* caught_exception);
+ Handle<Object> MakeScriptCollectedEvent(int id,
+ bool* caught_exception);
+ void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
+ void OnException(Handle<Object> exception, bool uncaught);
+ void OnBeforeCompile(Handle<Script> script);
enum AfterCompileFlags {
NO_AFTER_COMPILE_FLAGS,
SEND_WHEN_DEBUGGING
};
- static void OnAfterCompile(Handle<Script> script,
- AfterCompileFlags after_compile_flags);
- static void OnNewFunction(Handle<JSFunction> fun);
- static void OnScriptCollected(int id);
- static void ProcessDebugEvent(v8::DebugEvent event,
- Handle<JSObject> event_data,
- bool auto_continue);
- static void NotifyMessageHandler(v8::DebugEvent event,
- Handle<JSObject> exec_state,
- Handle<JSObject> event_data,
- bool auto_continue);
- static void SetEventListener(Handle<Object> callback, Handle<Object> data);
- static void SetMessageHandler(v8::Debug::MessageHandler2 handler);
- static void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
- int period);
- static void SetDebugMessageDispatchHandler(
+ void OnAfterCompile(Handle<Script> script,
+ AfterCompileFlags after_compile_flags);
+ void OnNewFunction(Handle<JSFunction> fun);
+ void OnScriptCollected(int id);
+ void ProcessDebugEvent(v8::DebugEvent event,
+ Handle<JSObject> event_data,
+ bool auto_continue);
+ void NotifyMessageHandler(v8::DebugEvent event,
+ Handle<JSObject> exec_state,
+ Handle<JSObject> event_data,
+ bool auto_continue);
+ void SetEventListener(Handle<Object> callback, Handle<Object> data);
+ void SetMessageHandler(v8::Debug::MessageHandler2 handler);
+ void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
+ int period);
+ void SetDebugMessageDispatchHandler(
v8::Debug::DebugMessageDispatchHandler handler,
bool provide_locker);
// Invoke the message handler function.
- static void InvokeMessageHandler(MessageImpl message);
+ void InvokeMessageHandler(MessageImpl message);
// Add a debugger command to the command queue.
- static void ProcessCommand(Vector<const uint16_t> command,
- v8::Debug::ClientData* client_data = NULL);
+ void ProcessCommand(Vector<const uint16_t> command,
+ v8::Debug::ClientData* client_data = NULL);
// Check whether there are commands in the command queue.
- static bool HasCommands();
+ bool HasCommands();
// Enqueue a debugger command to the command queue for event listeners.
- static void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL);
+ void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL);
- static Handle<Object> Call(Handle<JSFunction> fun,
- Handle<Object> data,
- bool* pending_exception);
+ Handle<Object> Call(Handle<JSFunction> fun,
+ Handle<Object> data,
+ bool* pending_exception);
// Start the debugger agent listening on the provided port.
- static bool StartAgent(const char* name, int port,
- bool wait_for_connection = false);
+ bool StartAgent(const char* name, int port,
+ bool wait_for_connection = false);
// Stop the debugger agent.
- static void StopAgent();
+ void StopAgent();
// Blocks until the agent has started listening for connections
- static void WaitForAgent();
+ void WaitForAgent();
- static void CallMessageDispatchHandler();
+ void CallMessageDispatchHandler();
- static Handle<Context> GetDebugContext();
+ Handle<Context> GetDebugContext();
// Unload the debugger if possible. Only called when no debugger is currently
// active.
- static void UnloadDebugger();
+ void UnloadDebugger();
friend void ForceUnloadDebugger(); // In test-debug.cc
- inline static bool EventActive(v8::DebugEvent event) {
+ inline bool EventActive(v8::DebugEvent event) {
ScopedLock with(debugger_access_);
// Check whether the message handler was been cleared.
if (debugger_unload_pending_) {
- if (Debug::debugger_entry() == NULL) {
+ if (isolate_->debug()->debugger_entry() == NULL) {
UnloadDebugger();
}
}
@@ -786,52 +796,58 @@ class Debugger {
return !compiling_natives_ && Debugger::IsDebuggerActive();
}
- static void set_compiling_natives(bool compiling_natives) {
+ void set_compiling_natives(bool compiling_natives) {
Debugger::compiling_natives_ = compiling_natives;
}
- static bool compiling_natives() { return Debugger::compiling_natives_; }
- static void set_loading_debugger(bool v) { is_loading_debugger_ = v; }
- static bool is_loading_debugger() { return Debugger::is_loading_debugger_; }
+ bool compiling_natives() const { return compiling_natives_; }
+ void set_loading_debugger(bool v) { is_loading_debugger_ = v; }
+ bool is_loading_debugger() const { return is_loading_debugger_; }
- static bool IsDebuggerActive();
+ bool IsDebuggerActive();
private:
- static void CallEventCallback(v8::DebugEvent event,
- Handle<Object> exec_state,
- Handle<Object> event_data,
- v8::Debug::ClientData* client_data);
- static void CallCEventCallback(v8::DebugEvent event,
- Handle<Object> exec_state,
- Handle<Object> event_data,
- v8::Debug::ClientData* client_data);
- static void CallJSEventCallback(v8::DebugEvent event,
- Handle<Object> exec_state,
- Handle<Object> event_data);
- static void ListenersChanged();
-
- static Mutex* debugger_access_; // Mutex guarding debugger variables.
- static Handle<Object> event_listener_; // Global handle to listener.
- static Handle<Object> event_listener_data_;
- static bool compiling_natives_; // Are we compiling natives?
- static bool is_loading_debugger_; // Are we loading the debugger?
- static bool never_unload_debugger_; // Can we unload the debugger?
- static v8::Debug::MessageHandler2 message_handler_;
- static bool debugger_unload_pending_; // Was message handler cleared?
- static v8::Debug::HostDispatchHandler host_dispatch_handler_;
- static Mutex* dispatch_handler_access_; // Mutex guarding dispatch handler.
- static v8::Debug::DebugMessageDispatchHandler debug_message_dispatch_handler_;
- static MessageDispatchHelperThread* message_dispatch_helper_thread_;
- static int host_dispatch_micros_;
-
- static DebuggerAgent* agent_;
+ Debugger();
+
+ void CallEventCallback(v8::DebugEvent event,
+ Handle<Object> exec_state,
+ Handle<Object> event_data,
+ v8::Debug::ClientData* client_data);
+ void CallCEventCallback(v8::DebugEvent event,
+ Handle<Object> exec_state,
+ Handle<Object> event_data,
+ v8::Debug::ClientData* client_data);
+ void CallJSEventCallback(v8::DebugEvent event,
+ Handle<Object> exec_state,
+ Handle<Object> event_data);
+ void ListenersChanged();
+
+ Mutex* debugger_access_; // Mutex guarding debugger variables.
+ Handle<Object> event_listener_; // Global handle to listener.
+ Handle<Object> event_listener_data_;
+ bool compiling_natives_; // Are we compiling natives?
+ bool is_loading_debugger_; // Are we loading the debugger?
+ bool never_unload_debugger_; // Can we unload the debugger?
+ v8::Debug::MessageHandler2 message_handler_;
+ bool debugger_unload_pending_; // Was message handler cleared?
+ v8::Debug::HostDispatchHandler host_dispatch_handler_;
+ Mutex* dispatch_handler_access_; // Mutex guarding dispatch handler.
+ v8::Debug::DebugMessageDispatchHandler debug_message_dispatch_handler_;
+ MessageDispatchHelperThread* message_dispatch_helper_thread_;
+ int host_dispatch_micros_;
+
+ DebuggerAgent* agent_;
static const int kQueueInitialSize = 4;
- static LockingCommandMessageQueue command_queue_;
- static Semaphore* command_received_; // Signaled for each command received.
+ LockingCommandMessageQueue command_queue_;
+ Semaphore* command_received_; // Signaled for each command received.
+ LockingCommandMessageQueue event_command_queue_;
- static LockingCommandMessageQueue event_command_queue_;
+ Isolate* isolate_;
friend class EnterDebugger;
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(Debugger);
};
@@ -842,38 +858,44 @@ class Debugger {
class EnterDebugger BASE_EMBEDDED {
public:
EnterDebugger()
- : prev_(Debug::debugger_entry()),
- has_js_frames_(!it_.done()) {
- ASSERT(prev_ != NULL || !Debug::is_interrupt_pending(PREEMPT));
- ASSERT(prev_ != NULL || !Debug::is_interrupt_pending(DEBUGBREAK));
+ : isolate_(Isolate::Current()),
+ prev_(isolate_->debug()->debugger_entry()),
+ has_js_frames_(!it_.done()),
+ save_(isolate_) {
+ Debug* debug = isolate_->debug();
+ ASSERT(prev_ != NULL || !debug->is_interrupt_pending(PREEMPT));
+ ASSERT(prev_ != NULL || !debug->is_interrupt_pending(DEBUGBREAK));
// Link recursive debugger entry.
- Debug::set_debugger_entry(this);
+ debug->set_debugger_entry(this);
// Store the previous break id and frame id.
- break_id_ = Debug::break_id();
- break_frame_id_ = Debug::break_frame_id();
+ break_id_ = debug->break_id();
+ break_frame_id_ = debug->break_frame_id();
// Create the new break info. If there is no JavaScript frames there is no
// break frame id.
if (has_js_frames_) {
- Debug::NewBreak(it_.frame()->id());
+ debug->NewBreak(it_.frame()->id());
} else {
- Debug::NewBreak(StackFrame::NO_ID);
+ debug->NewBreak(StackFrame::NO_ID);
}
// Make sure that debugger is loaded and enter the debugger context.
- load_failed_ = !Debug::Load();
+ load_failed_ = !debug->Load();
if (!load_failed_) {
// NOTE the member variable save which saves the previous context before
// this change.
- Top::set_context(*Debug::debug_context());
+ isolate_->set_context(*debug->debug_context());
}
}
~EnterDebugger() {
+ ASSERT(Isolate::Current() == isolate_);
+ Debug* debug = isolate_->debug();
+
// Restore to the previous break state.
- Debug::SetBreak(break_frame_id_, break_id_);
+ debug->SetBreak(break_frame_id_, break_id_);
// Check for leaving the debugger.
if (prev_ == NULL) {
@@ -881,43 +903,43 @@ class EnterDebugger BASE_EMBEDDED {
// pending exception as clearing the mirror cache calls back into
// JavaScript. This can happen if the v8::Debug::Call is used in which
// case the exception should end up in the calling code.
- if (!Top::has_pending_exception()) {
+ if (!isolate_->has_pending_exception()) {
// Try to avoid any pending debug break breaking in the clear mirror
// cache JavaScript code.
- if (StackGuard::IsDebugBreak()) {
- Debug::set_interrupts_pending(DEBUGBREAK);
- StackGuard::Continue(DEBUGBREAK);
+ if (isolate_->stack_guard()->IsDebugBreak()) {
+ debug->set_interrupts_pending(DEBUGBREAK);
+ isolate_->stack_guard()->Continue(DEBUGBREAK);
}
- Debug::ClearMirrorCache();
+ debug->ClearMirrorCache();
}
// Request preemption and debug break when leaving the last debugger entry
// if any of these where recorded while debugging.
- if (Debug::is_interrupt_pending(PREEMPT)) {
+ if (debug->is_interrupt_pending(PREEMPT)) {
// This re-scheduling of preemption is to avoid starvation in some
// debugging scenarios.
- Debug::clear_interrupt_pending(PREEMPT);
- StackGuard::Preempt();
+ debug->clear_interrupt_pending(PREEMPT);
+ isolate_->stack_guard()->Preempt();
}
- if (Debug::is_interrupt_pending(DEBUGBREAK)) {
- Debug::clear_interrupt_pending(DEBUGBREAK);
- StackGuard::DebugBreak();
+ if (debug->is_interrupt_pending(DEBUGBREAK)) {
+ debug->clear_interrupt_pending(DEBUGBREAK);
+ isolate_->stack_guard()->DebugBreak();
}
// If there are commands in the queue when leaving the debugger request
// that these commands are processed.
- if (Debugger::HasCommands()) {
- StackGuard::DebugCommand();
+ if (isolate_->debugger()->HasCommands()) {
+ isolate_->stack_guard()->DebugCommand();
}
// If leaving the debugger with the debugger no longer active unload it.
- if (!Debugger::IsDebuggerActive()) {
- Debugger::UnloadDebugger();
+ if (!isolate_->debugger()->IsDebuggerActive()) {
+ isolate_->debugger()->UnloadDebugger();
}
}
// Leaving this debugger entry.
- Debug::set_debugger_entry(prev_);
+ debug->set_debugger_entry(prev_);
}
// Check whether the debugger could be entered.
@@ -930,6 +952,7 @@ class EnterDebugger BASE_EMBEDDED {
inline Handle<Context> GetContext() { return save_.context(); }
private:
+ Isolate* isolate_;
EnterDebugger* prev_; // Previous debugger entry if entered recursively.
JavaScriptFrameIterator it_;
const bool has_js_frames_; // Were there any JavaScript frames?
@@ -943,15 +966,17 @@ class EnterDebugger BASE_EMBEDDED {
// Stack allocated class for disabling break.
class DisableBreak BASE_EMBEDDED {
public:
- explicit DisableBreak(bool disable_break) {
- prev_disable_break_ = Debug::disable_break();
- Debug::set_disable_break(disable_break);
+ explicit DisableBreak(bool disable_break) : isolate_(Isolate::Current()) {
+ prev_disable_break_ = isolate_->debug()->disable_break();
+ isolate_->debug()->set_disable_break(disable_break);
}
~DisableBreak() {
- Debug::set_disable_break(prev_disable_break_);
+ ASSERT(Isolate::Current() == isolate_);
+ isolate_->debug()->set_disable_break(prev_disable_break_);
}
private:
+ Isolate* isolate_;
// The previous state of the disable break used to restore the value when this
// object is destructed.
bool prev_disable_break_;
@@ -976,17 +1001,18 @@ class Debug_Address {
return Debug_Address(Debug::k_restarter_frame_function_pointer);
}
- Address address() const {
+ Address address(Isolate* isolate) const {
+ Debug* debug = isolate->debug();
switch (id_) {
case Debug::k_after_break_target_address:
- return reinterpret_cast<Address>(Debug::after_break_target_address());
+ return reinterpret_cast<Address>(debug->after_break_target_address());
case Debug::k_debug_break_return_address:
- return reinterpret_cast<Address>(Debug::debug_break_return_address());
+ return reinterpret_cast<Address>(debug->debug_break_return_address());
case Debug::k_debug_break_slot_address:
- return reinterpret_cast<Address>(Debug::debug_break_slot_address());
+ return reinterpret_cast<Address>(debug->debug_break_slot_address());
case Debug::k_restarter_frame_function_pointer:
return reinterpret_cast<Address>(
- Debug::restarter_frame_function_pointer_address());
+ debug->restarter_frame_function_pointer_address());
default:
UNREACHABLE();
return NULL;
@@ -1002,7 +1028,7 @@ class Debug_Address {
// to do this via v8::Debug::HostDispatchHandler
class MessageDispatchHelperThread: public Thread {
public:
- MessageDispatchHelperThread();
+ explicit MessageDispatchHelperThread(Isolate* isolate);
~MessageDispatchHelperThread();
void Schedule();
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index af2f42e4..4372af03 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -39,30 +39,50 @@
namespace v8 {
namespace internal {
-LargeObjectChunk* Deoptimizer::eager_deoptimization_entry_code_ = NULL;
-LargeObjectChunk* Deoptimizer::lazy_deoptimization_entry_code_ = NULL;
-Deoptimizer* Deoptimizer::current_ = NULL;
-DeoptimizingCodeListNode* Deoptimizer::deoptimizing_code_list_ = NULL;
+DeoptimizerData::DeoptimizerData() {
+ eager_deoptimization_entry_code_ = NULL;
+ lazy_deoptimization_entry_code_ = NULL;
+ current_ = NULL;
+ deoptimizing_code_list_ = NULL;
+}
+DeoptimizerData::~DeoptimizerData() {
+ if (eager_deoptimization_entry_code_ != NULL) {
+ eager_deoptimization_entry_code_->Free(EXECUTABLE);
+ eager_deoptimization_entry_code_ = NULL;
+ }
+ if (lazy_deoptimization_entry_code_ != NULL) {
+ lazy_deoptimization_entry_code_->Free(EXECUTABLE);
+ lazy_deoptimization_entry_code_ = NULL;
+ }
+}
+
Deoptimizer* Deoptimizer::New(JSFunction* function,
BailoutType type,
unsigned bailout_id,
Address from,
- int fp_to_sp_delta) {
- Deoptimizer* deoptimizer =
- new Deoptimizer(function, type, bailout_id, from, fp_to_sp_delta);
- ASSERT(current_ == NULL);
- current_ = deoptimizer;
+ int fp_to_sp_delta,
+ Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ Deoptimizer* deoptimizer = new Deoptimizer(isolate,
+ function,
+ type,
+ bailout_id,
+ from,
+ fp_to_sp_delta);
+ ASSERT(isolate->deoptimizer_data()->current_ == NULL);
+ isolate->deoptimizer_data()->current_ = deoptimizer;
return deoptimizer;
}
-Deoptimizer* Deoptimizer::Grab() {
- Deoptimizer* result = current_;
+Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ Deoptimizer* result = isolate->deoptimizer_data()->current_;
ASSERT(result != NULL);
result->DeleteFrameDescriptions();
- current_ = NULL;
+ isolate->deoptimizer_data()->current_ = NULL;
return result;
}
@@ -155,7 +175,7 @@ void Deoptimizer::VisitAllOptimizedFunctions(
AssertNoAllocation no_allocation;
// Run through the list of all global contexts and deoptimize.
- Object* global = Heap::global_contexts_list();
+ Object* global = Isolate::Current()->heap()->global_contexts_list();
while (!global->IsUndefined()) {
VisitAllOptimizedFunctionsForGlobalObject(Context::cast(global)->global(),
visitor);
@@ -170,7 +190,7 @@ void Deoptimizer::HandleWeakDeoptimizedCode(
reinterpret_cast<DeoptimizingCodeListNode*>(data);
RemoveDeoptimizingCode(*node->code());
#ifdef DEBUG
- node = Deoptimizer::deoptimizing_code_list_;
+ node = Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
while (node != NULL) {
ASSERT(node != reinterpret_cast<DeoptimizingCodeListNode*>(data));
node = node->next();
@@ -179,17 +199,20 @@ void Deoptimizer::HandleWeakDeoptimizedCode(
}
-void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
+void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer,
+ Isolate* isolate) {
deoptimizer->DoComputeOutputFrames();
}
-Deoptimizer::Deoptimizer(JSFunction* function,
+Deoptimizer::Deoptimizer(Isolate* isolate,
+ JSFunction* function,
BailoutType type,
unsigned bailout_id,
Address from,
int fp_to_sp_delta)
- : function_(function),
+ : isolate_(isolate),
+ function_(function),
bailout_id_(bailout_id),
bailout_type_(type),
from_(from),
@@ -228,7 +251,7 @@ Deoptimizer::Deoptimizer(JSFunction* function,
ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
ASSERT(!optimized_code_->contains(from));
}
- ASSERT(Heap::allow_allocation(false));
+ ASSERT(HEAP->allow_allocation(false));
unsigned size = ComputeInputFrameSize();
input_ = new(size) FrameDescription(size, function);
}
@@ -249,7 +272,7 @@ void Deoptimizer::DeleteFrameDescriptions() {
delete[] output_;
input_ = NULL;
output_ = NULL;
- ASSERT(!Heap::allow_allocation(true));
+ ASSERT(!HEAP->allow_allocation(true));
}
@@ -257,16 +280,17 @@ Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
ASSERT(id >= 0);
if (id >= kNumberOfEntries) return NULL;
LargeObjectChunk* base = NULL;
+ DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
if (type == EAGER) {
- if (eager_deoptimization_entry_code_ == NULL) {
- eager_deoptimization_entry_code_ = CreateCode(type);
+ if (data->eager_deoptimization_entry_code_ == NULL) {
+ data->eager_deoptimization_entry_code_ = CreateCode(type);
}
- base = eager_deoptimization_entry_code_;
+ base = data->eager_deoptimization_entry_code_;
} else {
- if (lazy_deoptimization_entry_code_ == NULL) {
- lazy_deoptimization_entry_code_ = CreateCode(type);
+ if (data->lazy_deoptimization_entry_code_ == NULL) {
+ data->lazy_deoptimization_entry_code_ = CreateCode(type);
}
- base = lazy_deoptimization_entry_code_;
+ base = data->lazy_deoptimization_entry_code_;
}
return
static_cast<Address>(base->GetStartAddress()) + (id * table_entry_size_);
@@ -275,10 +299,11 @@ Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
LargeObjectChunk* base = NULL;
+ DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
if (type == EAGER) {
- base = eager_deoptimization_entry_code_;
+ base = data->eager_deoptimization_entry_code_;
} else {
- base = lazy_deoptimization_entry_code_;
+ base = data->lazy_deoptimization_entry_code_;
}
if (base == NULL ||
addr < base->GetStartAddress() ||
@@ -292,23 +317,6 @@ int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
}
-void Deoptimizer::Setup() {
- // Do nothing yet.
-}
-
-
-void Deoptimizer::TearDown() {
- if (eager_deoptimization_entry_code_ != NULL) {
- eager_deoptimization_entry_code_->Free(EXECUTABLE);
- eager_deoptimization_entry_code_ = NULL;
- }
- if (lazy_deoptimization_entry_code_ != NULL) {
- lazy_deoptimization_entry_code_->Free(EXECUTABLE);
- lazy_deoptimization_entry_code_ = NULL;
- }
-}
-
-
int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
unsigned id,
SharedFunctionInfo* shared) {
@@ -335,9 +343,10 @@ int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
}
-int Deoptimizer::GetDeoptimizedCodeCount() {
+int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
int length = 0;
- DeoptimizingCodeListNode* node = Deoptimizer::deoptimizing_code_list_;
+ DeoptimizingCodeListNode* node =
+ isolate->deoptimizer_data()->deoptimizing_code_list_;
while (node != NULL) {
length++;
node = node->next();
@@ -445,7 +454,7 @@ void Deoptimizer::InsertHeapNumberValue(JavaScriptFrame* frame,
int tos_index = stack_index + extra_slot_count;
int index = (frame->ComputeExpressionsCount() - 1) - tos_index;
if (FLAG_trace_deopt) PrintF("Allocating a new heap number: %e\n", val);
- Handle<Object> num = Factory::NewNumber(val);
+ Handle<Object> num = isolate_->factory()->NewNumber(val);
frame->SetExpression(index, *num);
}
@@ -625,10 +634,11 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
output_[frame_index]->GetTop() + output_offset,
output_offset);
- Heap::arguments_marker()->ShortPrint();
+ isolate_->heap()->arguments_marker()->ShortPrint();
PrintF(" ; arguments object\n");
}
- intptr_t value = reinterpret_cast<intptr_t>(Heap::arguments_marker());
+ intptr_t value = reinterpret_cast<intptr_t>(
+ isolate_->heap()->arguments_marker());
output_[frame_index]->SetFrameSlot(output_offset, value);
return;
}
@@ -923,10 +933,9 @@ LargeObjectChunk* Deoptimizer::CreateCode(BailoutType type) {
// references. This is fine because the deoptimizer's code section
// isn't meant to be serialized at all.
ASSERT(!Serializer::enabled());
- bool old_debug_code = FLAG_debug_code;
- FLAG_debug_code = false;
MacroAssembler masm(NULL, 16 * KB);
+ masm.set_emit_debug_code(false);
GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
CodeDesc desc;
masm.GetCode(&desc);
@@ -935,13 +944,13 @@ LargeObjectChunk* Deoptimizer::CreateCode(BailoutType type) {
LargeObjectChunk* chunk = LargeObjectChunk::New(desc.instr_size, EXECUTABLE);
memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size);
CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size);
- FLAG_debug_code = old_debug_code;
return chunk;
}
Code* Deoptimizer::FindDeoptimizingCodeFromAddress(Address addr) {
- DeoptimizingCodeListNode* node = Deoptimizer::deoptimizing_code_list_;
+ DeoptimizingCodeListNode* node =
+ Isolate::Current()->deoptimizer_data()->deoptimizing_code_list_;
while (node != NULL) {
if (node->code()->contains(addr)) return *node->code();
node = node->next();
@@ -951,15 +960,16 @@ Code* Deoptimizer::FindDeoptimizingCodeFromAddress(Address addr) {
void Deoptimizer::RemoveDeoptimizingCode(Code* code) {
- ASSERT(deoptimizing_code_list_ != NULL);
+ DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
+ ASSERT(data->deoptimizing_code_list_ != NULL);
// Run through the code objects to find this one and remove it.
DeoptimizingCodeListNode* prev = NULL;
- DeoptimizingCodeListNode* current = deoptimizing_code_list_;
+ DeoptimizingCodeListNode* current = data->deoptimizing_code_list_;
while (current != NULL) {
if (*current->code() == code) {
// Unlink from list. If prev is NULL we are looking at the first element.
if (prev == NULL) {
- deoptimizing_code_list_ = current->next();
+ data->deoptimizing_code_list_ = current->next();
} else {
prev->set_next(current->next());
}
@@ -1046,7 +1056,8 @@ int32_t TranslationIterator::Next() {
Handle<ByteArray> TranslationBuffer::CreateByteArray() {
int length = contents_.length();
- Handle<ByteArray> result = Factory::NewByteArray(length, TENURED);
+ Handle<ByteArray> result =
+ Isolate::Current()->factory()->NewByteArray(length, TENURED);
memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
return result;
}
@@ -1169,16 +1180,18 @@ const char* Translation::StringFor(Opcode opcode) {
DeoptimizingCodeListNode::DeoptimizingCodeListNode(Code* code): next_(NULL) {
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
// Globalize the code object and make it weak.
- code_ = Handle<Code>::cast((GlobalHandles::Create(code)));
- GlobalHandles::MakeWeak(reinterpret_cast<Object**>(code_.location()),
- this,
- Deoptimizer::HandleWeakDeoptimizedCode);
+ code_ = Handle<Code>::cast(global_handles->Create(code));
+ global_handles->MakeWeak(reinterpret_cast<Object**>(code_.location()),
+ this,
+ Deoptimizer::HandleWeakDeoptimizedCode);
}
DeoptimizingCodeListNode::~DeoptimizingCodeListNode() {
- GlobalHandles::Destroy(reinterpret_cast<Object**>(code_.location()));
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
+ global_handles->Destroy(reinterpret_cast<Object**>(code_.location()));
}
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 1d4f4770..a53de3da 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -93,6 +93,31 @@ class OptimizedFunctionVisitor BASE_EMBEDDED {
};
+class Deoptimizer;
+
+
+class DeoptimizerData {
+ public:
+ DeoptimizerData();
+ ~DeoptimizerData();
+
+ private:
+ LargeObjectChunk* eager_deoptimization_entry_code_;
+ LargeObjectChunk* lazy_deoptimization_entry_code_;
+ Deoptimizer* current_;
+
+ // List of deoptimized code which still have references from active stack
+ // frames. These code objects are needed by the deoptimizer when deoptimizing
+ // a frame for which the code object for the function function has been
+ // changed from the code present when deoptimizing was done.
+ DeoptimizingCodeListNode* deoptimizing_code_list_;
+
+ friend class Deoptimizer;
+
+ DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
+};
+
+
class Deoptimizer : public Malloced {
public:
enum BailoutType {
@@ -107,8 +132,16 @@ class Deoptimizer : public Malloced {
BailoutType type,
unsigned bailout_id,
Address from,
- int fp_to_sp_delta);
- static Deoptimizer* Grab();
+ int fp_to_sp_delta,
+ Isolate* isolate);
+ static Deoptimizer* Grab(Isolate* isolate);
+
+ // Makes sure that there is enough room in the relocation
+ // information of a code object to perform lazy deoptimization
+ // patching. If there is not enough room a new relocation
+ // information object is allocated and comments are added until it
+ // is big enough.
+ static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code);
// Deoptimize the function now. Its current optimized code will never be run
// again and any activations of the optimized code will get deoptimized when
@@ -159,7 +192,7 @@ class Deoptimizer : public Malloced {
void InsertHeapNumberValues(int index, JavaScriptFrame* frame);
- static void ComputeOutputFrames(Deoptimizer* deoptimizer);
+ static void ComputeOutputFrames(Deoptimizer* deoptimizer, Isolate* isolate);
static Address GetDeoptimizationEntry(int id, BailoutType type);
static int GetDeoptimizationId(Address addr, BailoutType type);
@@ -167,9 +200,6 @@ class Deoptimizer : public Malloced {
unsigned node_id,
SharedFunctionInfo* shared);
- static void Setup();
- static void TearDown();
-
// Code generation support.
static int input_offset() { return OFFSET_OF(Deoptimizer, input_); }
static int output_count_offset() {
@@ -177,7 +207,7 @@ class Deoptimizer : public Malloced {
}
static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
- static int GetDeoptimizedCodeCount();
+ static int GetDeoptimizedCodeCount(Isolate* isolate);
static const int kNotDeoptimizationEntry = -1;
@@ -218,7 +248,8 @@ class Deoptimizer : public Malloced {
private:
static const int kNumberOfEntries = 4096;
- Deoptimizer(JSFunction* function,
+ Deoptimizer(Isolate* isolate,
+ JSFunction* function,
BailoutType type,
unsigned bailout_id,
Address from,
@@ -264,16 +295,7 @@ class Deoptimizer : public Malloced {
static Code* FindDeoptimizingCodeFromAddress(Address addr);
static void RemoveDeoptimizingCode(Code* code);
- static LargeObjectChunk* eager_deoptimization_entry_code_;
- static LargeObjectChunk* lazy_deoptimization_entry_code_;
- static Deoptimizer* current_;
-
- // List of deoptimized code which still have references from active stack
- // frames. These code objects are needed by the deoptimizer when deoptimizing
- // a frame for which the code object for the function function has been
- // changed from the code present when deoptimizing was done.
- static DeoptimizingCodeListNode* deoptimizing_code_list_;
-
+ Isolate* isolate_;
JSFunction* function_;
Code* optimized_code_;
unsigned bailout_id_;
@@ -304,7 +326,9 @@ class FrameDescription {
JSFunction* function);
void* operator new(size_t size, uint32_t frame_size) {
- return malloc(size + frame_size);
+ // Subtracts kPointerSize, as the member frame_content_ already supplies
+ // the first element of the area to store the frame.
+ return malloc(size + frame_size - kPointerSize);
}
void operator delete(void* description) {
@@ -388,7 +412,7 @@ class FrameDescription {
}
static int frame_content_offset() {
- return sizeof(FrameDescription);
+ return OFFSET_OF(FrameDescription, frame_content_);
}
private:
@@ -407,6 +431,10 @@ class FrameDescription {
// deoptimizing.
intptr_t continuation_;
+ // This must be at the end of the object as the object is allocated larger
+ // than it's definition indicate to extend this array.
+ intptr_t frame_content_[1];
+
intptr_t* GetFrameSlotPointer(unsigned offset) {
ASSERT(offset < frame_size_);
return reinterpret_cast<intptr_t*>(
diff --git a/src/disasm.h b/src/disasm.h
index 6ecd1c8f..f7f2d412 100644
--- a/src/disasm.h
+++ b/src/disasm.h
@@ -44,6 +44,9 @@ class NameConverter {
virtual const char* NameOfAddress(byte* addr) const;
virtual const char* NameOfConstant(byte* addr) const;
virtual const char* NameInCode(byte* addr) const;
+
+ protected:
+ v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
};
diff --git a/src/disassembler.cc b/src/disassembler.cc
index 243abf07..d142ef6a 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -65,24 +65,24 @@ class V8NameConverter: public disasm::NameConverter {
Code* code() const { return code_; }
private:
Code* code_;
+
+ EmbeddedVector<char, 128> v8_buffer_;
};
const char* V8NameConverter::NameOfAddress(byte* pc) const {
- static v8::internal::EmbeddedVector<char, 128> buffer;
-
- const char* name = Builtins::Lookup(pc);
+ const char* name = Isolate::Current()->builtins()->Lookup(pc);
if (name != NULL) {
- OS::SNPrintF(buffer, "%s (%p)", name, pc);
- return buffer.start();
+ OS::SNPrintF(v8_buffer_, "%s (%p)", name, pc);
+ return v8_buffer_.start();
}
if (code_ != NULL) {
int offs = static_cast<int>(pc - code_->instruction_start());
// print as code offset, if it seems reasonable
if (0 <= offs && offs < code_->instruction_size()) {
- OS::SNPrintF(buffer, "%d (%p)", offs, pc);
- return buffer.start();
+ OS::SNPrintF(v8_buffer_, "%d (%p)", offs, pc);
+ return v8_buffer_.start();
}
}
@@ -115,6 +115,7 @@ static int DecodeIt(FILE* f,
NoHandleAllocation ha;
AssertNoAllocation no_alloc;
ExternalReferenceEncoder ref_encoder;
+ Heap* heap = HEAP;
v8::internal::EmbeddedVector<char, 128> decode_buffer;
v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
@@ -256,8 +257,8 @@ static int DecodeIt(FILE* f,
} else if (kind == Code::STUB) {
// Reverse lookup required as the minor key cannot be retrieved
// from the code object.
- Object* obj = Heap::code_stubs()->SlowReverseLookup(code);
- if (obj != Heap::undefined_value()) {
+ Object* obj = heap->code_stubs()->SlowReverseLookup(code);
+ if (obj != heap->undefined_value()) {
ASSERT(obj->IsSmi());
// Get the STUB key and extract major and minor key.
uint32_t key = Smi::cast(obj)->value();
diff --git a/src/execution.cc b/src/execution.cc
index de8f0a46..98c8b680 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -42,14 +42,39 @@ namespace v8 {
namespace internal {
+StackGuard::StackGuard()
+ : isolate_(NULL) {
+}
+
+
+void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
+ ASSERT(isolate_ != NULL);
+ // Ignore attempts to interrupt when interrupts are postponed.
+ if (should_postpone_interrupts(lock)) return;
+ thread_local_.jslimit_ = kInterruptLimit;
+ thread_local_.climit_ = kInterruptLimit;
+ isolate_->heap()->SetStackLimits();
+}
+
+
+void StackGuard::reset_limits(const ExecutionAccess& lock) {
+ ASSERT(isolate_ != NULL);
+ thread_local_.jslimit_ = thread_local_.real_jslimit_;
+ thread_local_.climit_ = thread_local_.real_climit_;
+ isolate_->heap()->SetStackLimits();
+}
+
+
static Handle<Object> Invoke(bool construct,
Handle<JSFunction> func,
Handle<Object> receiver,
int argc,
Object*** args,
bool* has_pending_exception) {
+ Isolate* isolate = func->GetIsolate();
+
// Entering JavaScript.
- VMState state(JS);
+ VMState state(isolate, JS);
// Placeholder for return value.
MaybeObject* value = reinterpret_cast<Object*>(kZapValue);
@@ -85,7 +110,7 @@ static Handle<Object> Invoke(bool construct,
{
// Save and restore context around invocation and block the
// allocation of handles without explicit handle scopes.
- SaveContext save;
+ SaveContext save(isolate);
NoHandleAllocation na;
JSEntryFunction entry = FUNCTION_CAST<JSEntryFunction>(code->entry());
@@ -103,20 +128,20 @@ static Handle<Object> Invoke(bool construct,
// Update the pending exception flag and return the value.
*has_pending_exception = value->IsException();
- ASSERT(*has_pending_exception == Top::has_pending_exception());
+ ASSERT(*has_pending_exception == Isolate::Current()->has_pending_exception());
if (*has_pending_exception) {
- Top::ReportPendingMessages();
- if (Top::pending_exception() == Failure::OutOfMemoryException()) {
- if (!HandleScopeImplementer::instance()->ignore_out_of_memory()) {
+ isolate->ReportPendingMessages();
+ if (isolate->pending_exception() == Failure::OutOfMemoryException()) {
+ if (!isolate->handle_scope_implementer()->ignore_out_of_memory()) {
V8::FatalProcessOutOfMemory("JS", true);
}
}
return Handle<Object>();
} else {
- Top::clear_pending_message();
+ isolate->clear_pending_message();
}
- return Handle<Object>(value->ToObjectUnchecked());
+ return Handle<Object>(value->ToObjectUnchecked(), isolate);
}
@@ -131,7 +156,8 @@ Handle<Object> Execution::Call(Handle<JSFunction> func,
Handle<Object> Execution::New(Handle<JSFunction> func, int argc,
Object*** args, bool* pending_exception) {
- return Invoke(true, func, Top::global(), argc, args, pending_exception);
+ return Invoke(true, func, Isolate::Current()->global(), argc, args,
+ pending_exception);
}
@@ -153,18 +179,20 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func,
if (*caught_exception) {
ASSERT(catcher.HasCaught());
- ASSERT(Top::has_pending_exception());
- ASSERT(Top::external_caught_exception());
- if (Top::pending_exception() == Heap::termination_exception()) {
- result = Factory::termination_exception();
+ Isolate* isolate = Isolate::Current();
+ ASSERT(isolate->has_pending_exception());
+ ASSERT(isolate->external_caught_exception());
+ if (isolate->pending_exception() ==
+ isolate->heap()->termination_exception()) {
+ result = isolate->factory()->termination_exception();
} else {
result = v8::Utils::OpenHandle(*catcher.Exception());
}
- Top::OptionalRescheduleException(true);
+ isolate->OptionalRescheduleException(true);
}
- ASSERT(!Top::has_pending_exception());
- ASSERT(!Top::external_caught_exception());
+ ASSERT(!Isolate::Current()->has_pending_exception());
+ ASSERT(!Isolate::Current()->external_caught_exception());
return result;
}
@@ -178,7 +206,7 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
// Regular expressions can be called as functions in both Firefox
// and Safari so we allow it too.
if (object->IsJSRegExp()) {
- Handle<String> exec = Factory::exec_symbol();
+ Handle<String> exec = FACTORY->exec_symbol();
// TODO(lrn): Bug 617. We should use the default function here, not the
// one on the RegExp object.
Object* exec_function;
@@ -186,7 +214,7 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
// This can lose an exception, but the alternative is to put a failure
// object in a handle, which is not GC safe.
if (!maybe_exec_function->ToObject(&exec_function)) {
- return Factory::undefined_value();
+ return FACTORY->undefined_value();
}
}
return Handle<Object>(exec_function);
@@ -197,10 +225,10 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
if (object->IsHeapObject() &&
HeapObject::cast(*object)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
- Top::global_context()->call_as_function_delegate());
+ Isolate::Current()->global_context()->call_as_function_delegate());
}
- return Factory::undefined_value();
+ return FACTORY->undefined_value();
}
@@ -215,26 +243,22 @@ Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
if (object->IsHeapObject() &&
HeapObject::cast(*object)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
- Top::global_context()->call_as_constructor_delegate());
+ Isolate::Current()->global_context()->call_as_constructor_delegate());
}
- return Factory::undefined_value();
+ return FACTORY->undefined_value();
}
-// Static state for stack guards.
-StackGuard::ThreadLocal StackGuard::thread_local_;
-
-
bool StackGuard::IsStackOverflow() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
return (thread_local_.jslimit_ != kInterruptLimit &&
thread_local_.climit_ != kInterruptLimit);
}
void StackGuard::EnableInterrupts() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
if (has_pending_interrupts(access)) {
set_interrupt_limits(access);
}
@@ -242,7 +266,7 @@ void StackGuard::EnableInterrupts() {
void StackGuard::SetStackLimit(uintptr_t limit) {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
// If the current limits are special (eg due to a pending interrupt) then
// leave them alone.
uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(limit);
@@ -258,92 +282,92 @@ void StackGuard::SetStackLimit(uintptr_t limit) {
void StackGuard::DisableInterrupts() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
reset_limits(access);
}
bool StackGuard::IsInterrupted() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & INTERRUPT;
}
void StackGuard::Interrupt() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
thread_local_.interrupt_flags_ |= INTERRUPT;
set_interrupt_limits(access);
}
bool StackGuard::IsPreempted() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & PREEMPT;
}
void StackGuard::Preempt() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
thread_local_.interrupt_flags_ |= PREEMPT;
set_interrupt_limits(access);
}
bool StackGuard::IsTerminateExecution() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & TERMINATE;
}
void StackGuard::TerminateExecution() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
thread_local_.interrupt_flags_ |= TERMINATE;
set_interrupt_limits(access);
}
bool StackGuard::IsRuntimeProfilerTick() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & RUNTIME_PROFILER_TICK;
}
void StackGuard::RequestRuntimeProfilerTick() {
// Ignore calls if we're not optimizing or if we can't get the lock.
- if (FLAG_opt && ExecutionAccess::TryLock()) {
+ if (FLAG_opt && ExecutionAccess::TryLock(isolate_)) {
thread_local_.interrupt_flags_ |= RUNTIME_PROFILER_TICK;
if (thread_local_.postpone_interrupts_nesting_ == 0) {
thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit;
- Heap::SetStackLimits();
+ isolate_->heap()->SetStackLimits();
}
- ExecutionAccess::Unlock();
+ ExecutionAccess::Unlock(isolate_);
}
}
#ifdef ENABLE_DEBUGGER_SUPPORT
bool StackGuard::IsDebugBreak() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & DEBUGBREAK;
}
void StackGuard::DebugBreak() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
thread_local_.interrupt_flags_ |= DEBUGBREAK;
set_interrupt_limits(access);
}
bool StackGuard::IsDebugCommand() {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & DEBUGCOMMAND;
}
void StackGuard::DebugCommand() {
if (FLAG_debugger_auto_break) {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
thread_local_.interrupt_flags_ |= DEBUGCOMMAND;
set_interrupt_limits(access);
}
@@ -351,7 +375,7 @@ void StackGuard::DebugCommand() {
#endif
void StackGuard::Continue(InterruptFlag after_what) {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what);
if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) {
reset_limits(access);
@@ -359,36 +383,34 @@ void StackGuard::Continue(InterruptFlag after_what) {
}
-int StackGuard::ArchiveSpacePerThread() {
- return sizeof(ThreadLocal);
-}
-
-
char* StackGuard::ArchiveStackGuard(char* to) {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
ThreadLocal blank;
+
+ // Set the stack limits using the old thread_local_.
+ // TODO(isolates): This was the old semantics of constructing a ThreadLocal
+ // (as the ctor called SetStackLimits, which looked at the
+ // current thread_local_ from StackGuard)-- but is this
+ // really what was intended?
+ isolate_->heap()->SetStackLimits();
thread_local_ = blank;
+
return to + sizeof(ThreadLocal);
}
char* StackGuard::RestoreStackGuard(char* from) {
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
- Heap::SetStackLimits();
+ isolate_->heap()->SetStackLimits();
return from + sizeof(ThreadLocal);
}
-static internal::Thread::LocalStorageKey stack_limit_key =
- internal::Thread::CreateThreadLocalKey();
-
-
void StackGuard::FreeThreadResources() {
- Thread::SetThreadLocal(
- stack_limit_key,
- reinterpret_cast<void*>(thread_local_.real_climit_));
+ Isolate::CurrentPerIsolateThreadData()->set_stack_limit(
+ thread_local_.real_climit_);
}
@@ -400,11 +422,11 @@ void StackGuard::ThreadLocal::Clear() {
nesting_ = 0;
postpone_interrupts_nesting_ = 0;
interrupt_flags_ = 0;
- Heap::SetStackLimits();
}
-void StackGuard::ThreadLocal::Initialize() {
+bool StackGuard::ThreadLocal::Initialize() {
+ bool should_set_stack_limits = false;
if (real_climit_ == kIllegalLimit) {
// Takes the address of the limit variable in order to find out where
// the top of stack is right now.
@@ -415,37 +437,41 @@ void StackGuard::ThreadLocal::Initialize() {
jslimit_ = SimulatorStack::JsLimitFromCLimit(limit);
real_climit_ = limit;
climit_ = limit;
- Heap::SetStackLimits();
+ should_set_stack_limits = true;
}
nesting_ = 0;
postpone_interrupts_nesting_ = 0;
interrupt_flags_ = 0;
+ return should_set_stack_limits;
}
void StackGuard::ClearThread(const ExecutionAccess& lock) {
thread_local_.Clear();
+ isolate_->heap()->SetStackLimits();
}
void StackGuard::InitThread(const ExecutionAccess& lock) {
- thread_local_.Initialize();
- void* stored_limit = Thread::GetThreadLocal(stack_limit_key);
+ if (thread_local_.Initialize()) isolate_->heap()->SetStackLimits();
+ uintptr_t stored_limit =
+ Isolate::CurrentPerIsolateThreadData()->stack_limit();
// You should hold the ExecutionAccess lock when you call this.
- if (stored_limit != NULL) {
- StackGuard::SetStackLimit(reinterpret_cast<intptr_t>(stored_limit));
+ if (stored_limit != 0) {
+ StackGuard::SetStackLimit(stored_limit);
}
}
// --- C a l l s t o n a t i v e s ---
-#define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \
- do { \
- Object** args[argc] = argv; \
- ASSERT(has_pending_exception != NULL); \
- return Call(Top::name##_fun(), Top::builtins(), argc, args, \
- has_pending_exception); \
+#define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \
+ do { \
+ Object** args[argc] = argv; \
+ ASSERT(has_pending_exception != NULL); \
+ return Call(Isolate::Current()->name##_fun(), \
+ Isolate::Current()->js_builtins_object(), argc, args, \
+ has_pending_exception); \
} while (false)
@@ -461,7 +487,7 @@ Handle<Object> Execution::ToBoolean(Handle<Object> obj) {
double value = obj->Number();
result = !((value == 0) || isnan(value));
}
- return Handle<Object>(Heap::ToBoolean(result));
+ return Handle<Object>(HEAP->ToBoolean(result));
}
@@ -502,7 +528,7 @@ Handle<Object> Execution::ToInt32(Handle<Object> obj, bool* exc) {
Handle<Object> Execution::NewDate(double time, bool* exc) {
- Handle<Object> time_obj = Factory::NewNumber(time);
+ Handle<Object> time_obj = FACTORY->NewNumber(time);
RETURN_NATIVE_CALL(create_date, 1, { time_obj.location() }, exc);
}
@@ -513,11 +539,10 @@ Handle<Object> Execution::NewDate(double time, bool* exc) {
Handle<JSRegExp> Execution::NewJSRegExp(Handle<String> pattern,
Handle<String> flags,
bool* exc) {
+ Handle<JSFunction> function = Handle<JSFunction>(
+ pattern->GetIsolate()->global_context()->regexp_function());
Handle<Object> re_obj = RegExpImpl::CreateRegExpLiteral(
- Handle<JSFunction>(Top::global_context()->regexp_function()),
- pattern,
- flags,
- exc);
+ function, pattern, flags, exc);
if (*exc) return Handle<JSRegExp>();
return Handle<JSRegExp>::cast(re_obj);
}
@@ -526,17 +551,18 @@ Handle<JSRegExp> Execution::NewJSRegExp(Handle<String> pattern,
Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) {
int int_index = static_cast<int>(index);
if (int_index < 0 || int_index >= string->length()) {
- return Factory::undefined_value();
+ return FACTORY->undefined_value();
}
Handle<Object> char_at =
- GetProperty(Top::builtins(), Factory::char_at_symbol());
+ GetProperty(Isolate::Current()->js_builtins_object(),
+ FACTORY->char_at_symbol());
if (!char_at->IsJSFunction()) {
- return Factory::undefined_value();
+ return FACTORY->undefined_value();
}
bool caught_exception;
- Handle<Object> index_object = Factory::NewNumberFromInt(int_index);
+ Handle<Object> index_object = FACTORY->NewNumberFromInt(int_index);
Object** index_arg[] = { index_object.location() };
Handle<Object> result = TryCall(Handle<JSFunction>::cast(char_at),
string,
@@ -544,7 +570,7 @@ Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) {
index_arg,
&caught_exception);
if (caught_exception) {
- return Factory::undefined_value();
+ return FACTORY->undefined_value();
}
return result;
}
@@ -554,13 +580,15 @@ Handle<JSFunction> Execution::InstantiateFunction(
Handle<FunctionTemplateInfo> data, bool* exc) {
// Fast case: see if the function has already been instantiated
int serial_number = Smi::cast(data->serial_number())->value();
- Object* elm = Top::global_context()->function_cache()->
- GetElementNoExceptionThrown(serial_number);
+ Object* elm =
+ Isolate::Current()->global_context()->function_cache()->
+ GetElementNoExceptionThrown(serial_number);
if (elm->IsJSFunction()) return Handle<JSFunction>(JSFunction::cast(elm));
// The function has not yet been instantiated in this context; do it.
Object** args[1] = { Handle<Object>::cast(data).location() };
Handle<Object> result =
- Call(Top::instantiate_fun(), Top::builtins(), 1, args, exc);
+ Call(Isolate::Current()->instantiate_fun(),
+ Isolate::Current()->js_builtins_object(), 1, args, exc);
if (*exc) return Handle<JSFunction>::null();
return Handle<JSFunction>::cast(result);
}
@@ -588,7 +616,8 @@ Handle<JSObject> Execution::InstantiateObject(Handle<ObjectTemplateInfo> data,
} else {
Object** args[1] = { Handle<Object>::cast(data).location() };
Handle<Object> result =
- Call(Top::instantiate_fun(), Top::builtins(), 1, args, exc);
+ Call(Isolate::Current()->instantiate_fun(),
+ Isolate::Current()->js_builtins_object(), 1, args, exc);
if (*exc) return Handle<JSObject>::null();
return Handle<JSObject>::cast(result);
}
@@ -599,7 +628,8 @@ void Execution::ConfigureInstance(Handle<Object> instance,
Handle<Object> instance_template,
bool* exc) {
Object** args[2] = { instance.location(), instance_template.location() };
- Execution::Call(Top::configure_instance_fun(), Top::builtins(), 2, args, exc);
+ Execution::Call(Isolate::Current()->configure_instance_fun(),
+ Isolate::Current()->js_builtins_object(), 2, args, exc);
}
@@ -613,50 +643,57 @@ Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
pos.location(),
is_global.location() };
bool caught_exception = false;
- Handle<Object> result = TryCall(Top::get_stack_trace_line_fun(),
- Top::builtins(), argc, args,
- &caught_exception);
- if (caught_exception || !result->IsString()) return Factory::empty_symbol();
+ Handle<Object> result =
+ TryCall(Isolate::Current()->get_stack_trace_line_fun(),
+ Isolate::Current()->js_builtins_object(), argc, args,
+ &caught_exception);
+ if (caught_exception || !result->IsString()) return FACTORY->empty_symbol();
return Handle<String>::cast(result);
}
static Object* RuntimePreempt() {
+ Isolate* isolate = Isolate::Current();
+
// Clear the preempt request flag.
- StackGuard::Continue(PREEMPT);
+ isolate->stack_guard()->Continue(PREEMPT);
ContextSwitcher::PreemptionReceived();
#ifdef ENABLE_DEBUGGER_SUPPORT
- if (Debug::InDebugger()) {
+ if (isolate->debug()->InDebugger()) {
// If currently in the debugger don't do any actual preemption but record
// that preemption occoured while in the debugger.
- Debug::PreemptionWhileInDebugger();
+ isolate->debug()->PreemptionWhileInDebugger();
} else {
// Perform preemption.
v8::Unlocker unlocker;
Thread::YieldCPU();
}
#else
- // Perform preemption.
- v8::Unlocker unlocker;
- Thread::YieldCPU();
+ { // NOLINT
+ // Perform preemption.
+ v8::Unlocker unlocker;
+ Thread::YieldCPU();
+ }
#endif
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
#ifdef ENABLE_DEBUGGER_SUPPORT
Object* Execution::DebugBreakHelper() {
+ Isolate* isolate = Isolate::Current();
+
// Just continue if breaks are disabled.
- if (Debug::disable_break()) {
- return Heap::undefined_value();
+ if (isolate->debug()->disable_break()) {
+ return isolate->heap()->undefined_value();
}
// Ignore debug break during bootstrapping.
- if (Bootstrapper::IsActive()) {
- return Heap::undefined_value();
+ if (isolate->bootstrapper()->IsActive()) {
+ return isolate->heap()->undefined_value();
}
{
@@ -666,32 +703,33 @@ Object* Execution::DebugBreakHelper() {
if (fun && fun->IsJSFunction()) {
// Don't stop in builtin functions.
if (JSFunction::cast(fun)->IsBuiltin()) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
GlobalObject* global = JSFunction::cast(fun)->context()->global();
// Don't stop in debugger functions.
- if (Debug::IsDebugGlobal(global)) {
- return Heap::undefined_value();
+ if (isolate->debug()->IsDebugGlobal(global)) {
+ return isolate->heap()->undefined_value();
}
}
}
// Collect the break state before clearing the flags.
bool debug_command_only =
- StackGuard::IsDebugCommand() && !StackGuard::IsDebugBreak();
+ isolate->stack_guard()->IsDebugCommand() &&
+ !isolate->stack_guard()->IsDebugBreak();
// Clear the debug break request flag.
- StackGuard::Continue(DEBUGBREAK);
+ isolate->stack_guard()->Continue(DEBUGBREAK);
ProcessDebugMesssages(debug_command_only);
// Return to continue execution.
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
void Execution::ProcessDebugMesssages(bool debug_command_only) {
// Clear the debug command request flag.
- StackGuard::Continue(DEBUGCOMMAND);
+ Isolate::Current()->stack_guard()->Continue(DEBUGCOMMAND);
HandleScope scope;
// Enter the debugger. Just continue if we fail to enter the debugger.
@@ -702,34 +740,37 @@ void Execution::ProcessDebugMesssages(bool debug_command_only) {
// Notify the debug event listeners. Indicate auto continue if the break was
// a debug command break.
- Debugger::OnDebugBreak(Factory::undefined_value(), debug_command_only);
+ Isolate::Current()->debugger()->OnDebugBreak(FACTORY->undefined_value(),
+ debug_command_only);
}
#endif
MaybeObject* Execution::HandleStackGuardInterrupt() {
- Counters::stack_interrupts.Increment();
- if (StackGuard::IsRuntimeProfilerTick()) {
- Counters::runtime_profiler_ticks.Increment();
- StackGuard::Continue(RUNTIME_PROFILER_TICK);
- RuntimeProfiler::OptimizeNow();
+ Isolate* isolate = Isolate::Current();
+ StackGuard* stack_guard = isolate->stack_guard();
+ isolate->counters()->stack_interrupts()->Increment();
+ if (stack_guard->IsRuntimeProfilerTick()) {
+ isolate->counters()->runtime_profiler_ticks()->Increment();
+ stack_guard->Continue(RUNTIME_PROFILER_TICK);
+ isolate->runtime_profiler()->OptimizeNow();
}
#ifdef ENABLE_DEBUGGER_SUPPORT
- if (StackGuard::IsDebugBreak() || StackGuard::IsDebugCommand()) {
+ if (stack_guard->IsDebugBreak() || stack_guard->IsDebugCommand()) {
DebugBreakHelper();
}
#endif
- if (StackGuard::IsPreempted()) RuntimePreempt();
- if (StackGuard::IsTerminateExecution()) {
- StackGuard::Continue(TERMINATE);
- return Top::TerminateExecution();
+ if (stack_guard->IsPreempted()) RuntimePreempt();
+ if (stack_guard->IsTerminateExecution()) {
+ stack_guard->Continue(TERMINATE);
+ return isolate->TerminateExecution();
}
- if (StackGuard::IsInterrupted()) {
- StackGuard::Continue(INTERRUPT);
- return Top::StackOverflow();
+ if (stack_guard->IsInterrupted()) {
+ stack_guard->Continue(INTERRUPT);
+ return isolate->StackOverflow();
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
} } // namespace v8::internal
diff --git a/src/execution.h b/src/execution.h
index cb07807c..d4b80d27 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -146,71 +146,74 @@ class Execution : public AllStatic {
class ExecutionAccess;
+class Isolate;
// StackGuard contains the handling of the limits that are used to limit the
// number of nested invocations of JavaScript and the stack size used in each
// invocation.
-class StackGuard : public AllStatic {
+class StackGuard {
public:
// Pass the address beyond which the stack should not grow. The stack
// is assumed to grow downwards.
- static void SetStackLimit(uintptr_t limit);
+ void SetStackLimit(uintptr_t limit);
// Threading support.
- static char* ArchiveStackGuard(char* to);
- static char* RestoreStackGuard(char* from);
- static int ArchiveSpacePerThread();
- static void FreeThreadResources();
+ char* ArchiveStackGuard(char* to);
+ char* RestoreStackGuard(char* from);
+ static int ArchiveSpacePerThread() { return sizeof(ThreadLocal); }
+ void FreeThreadResources();
// Sets up the default stack guard for this thread if it has not
// already been set up.
- static void InitThread(const ExecutionAccess& lock);
+ void InitThread(const ExecutionAccess& lock);
// Clears the stack guard for this thread so it does not look as if
// it has been set up.
- static void ClearThread(const ExecutionAccess& lock);
-
- static bool IsStackOverflow();
- static bool IsPreempted();
- static void Preempt();
- static bool IsInterrupted();
- static void Interrupt();
- static bool IsTerminateExecution();
- static void TerminateExecution();
- static bool IsRuntimeProfilerTick();
- static void RequestRuntimeProfilerTick();
+ void ClearThread(const ExecutionAccess& lock);
+
+ bool IsStackOverflow();
+ bool IsPreempted();
+ void Preempt();
+ bool IsInterrupted();
+ void Interrupt();
+ bool IsTerminateExecution();
+ void TerminateExecution();
+ bool IsRuntimeProfilerTick();
+ void RequestRuntimeProfilerTick();
#ifdef ENABLE_DEBUGGER_SUPPORT
- static bool IsDebugBreak();
- static void DebugBreak();
- static bool IsDebugCommand();
- static void DebugCommand();
+ bool IsDebugBreak();
+ void DebugBreak();
+ bool IsDebugCommand();
+ void DebugCommand();
#endif
- static void Continue(InterruptFlag after_what);
+ void Continue(InterruptFlag after_what);
// This provides an asynchronous read of the stack limits for the current
// thread. There are no locks protecting this, but it is assumed that you
// have the global V8 lock if you are using multiple V8 threads.
- static uintptr_t climit() {
+ uintptr_t climit() {
return thread_local_.climit_;
}
- static uintptr_t real_climit() {
+ uintptr_t real_climit() {
return thread_local_.real_climit_;
}
- static uintptr_t jslimit() {
+ uintptr_t jslimit() {
return thread_local_.jslimit_;
}
- static uintptr_t real_jslimit() {
+ uintptr_t real_jslimit() {
return thread_local_.real_jslimit_;
}
- static Address address_of_jslimit() {
+ Address address_of_jslimit() {
return reinterpret_cast<Address>(&thread_local_.jslimit_);
}
- static Address address_of_real_jslimit() {
+ Address address_of_real_jslimit() {
return reinterpret_cast<Address>(&thread_local_.real_jslimit_);
}
private:
+ StackGuard();
+
// You should hold the ExecutionAccess lock when calling this method.
- static bool has_pending_interrupts(const ExecutionAccess& lock) {
+ bool has_pending_interrupts(const ExecutionAccess& lock) {
// Sanity check: We shouldn't be asking about pending interrupts
// unless we're not postponing them anymore.
ASSERT(!should_postpone_interrupts(lock));
@@ -218,30 +221,20 @@ class StackGuard : public AllStatic {
}
// You should hold the ExecutionAccess lock when calling this method.
- static bool should_postpone_interrupts(const ExecutionAccess& lock) {
+ bool should_postpone_interrupts(const ExecutionAccess& lock) {
return thread_local_.postpone_interrupts_nesting_ > 0;
}
// You should hold the ExecutionAccess lock when calling this method.
- static void set_interrupt_limits(const ExecutionAccess& lock) {
- // Ignore attempts to interrupt when interrupts are postponed.
- if (should_postpone_interrupts(lock)) return;
- thread_local_.jslimit_ = kInterruptLimit;
- thread_local_.climit_ = kInterruptLimit;
- Heap::SetStackLimits();
- }
+ inline void set_interrupt_limits(const ExecutionAccess& lock);
// Reset limits to actual values. For example after handling interrupt.
// You should hold the ExecutionAccess lock when calling this method.
- static void reset_limits(const ExecutionAccess& lock) {
- thread_local_.jslimit_ = thread_local_.real_jslimit_;
- thread_local_.climit_ = thread_local_.real_climit_;
- Heap::SetStackLimits();
- }
+ inline void reset_limits(const ExecutionAccess& lock);
// Enable or disable interrupts.
- static void EnableInterrupts();
- static void DisableInterrupts();
+ void EnableInterrupts();
+ void DisableInterrupts();
#ifdef V8_TARGET_ARCH_X64
static const uintptr_t kInterruptLimit = V8_UINT64_C(0xfffffffffffffffe);
@@ -256,9 +249,11 @@ class StackGuard : public AllStatic {
ThreadLocal() { Clear(); }
// You should hold the ExecutionAccess lock when you call Initialize or
// Clear.
- void Initialize();
void Clear();
+ // Returns true if the heap's stack limits should be set, false if not.
+ bool Initialize();
+
// The stack limit is split into a JavaScript and a C++ stack limit. These
// two are the same except when running on a simulator where the C++ and
// JavaScript stacks are separate. Each of the two stack limits have two
@@ -278,45 +273,19 @@ class StackGuard : public AllStatic {
int interrupt_flags_;
};
- static ThreadLocal thread_local_;
+ // TODO(isolates): Technically this could be calculated directly from a
+ // pointer to StackGuard.
+ Isolate* isolate_;
+ ThreadLocal thread_local_;
+ friend class Isolate;
friend class StackLimitCheck;
friend class PostponeInterruptsScope;
-};
-
-// Support for checking for stack-overflows in C++ code.
-class StackLimitCheck BASE_EMBEDDED {
- public:
- bool HasOverflowed() const {
- // Stack has overflowed in C++ code only if stack pointer exceeds the C++
- // stack guard and the limits are not set to interrupt values.
- // TODO(214): Stack overflows are ignored if a interrupt is pending. This
- // code should probably always use the initial C++ limit.
- return (reinterpret_cast<uintptr_t>(this) < StackGuard::climit()) &&
- StackGuard::IsStackOverflow();
- }
+ DISALLOW_COPY_AND_ASSIGN(StackGuard);
};
-// Support for temporarily postponing interrupts. When the outermost
-// postpone scope is left the interrupts will be re-enabled and any
-// interrupts that occurred while in the scope will be taken into
-// account.
-class PostponeInterruptsScope BASE_EMBEDDED {
- public:
- PostponeInterruptsScope() {
- StackGuard::thread_local_.postpone_interrupts_nesting_++;
- StackGuard::DisableInterrupts();
- }
-
- ~PostponeInterruptsScope() {
- if (--StackGuard::thread_local_.postpone_interrupts_nesting_ == 0) {
- StackGuard::EnableInterrupts();
- }
- }
-};
-
} } // namespace v8::internal
#endif // V8_EXECUTION_H_
diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc
index 8b4bdbd8..b3f83fe9 100644
--- a/src/extensions/externalize-string-extension.cc
+++ b/src/extensions/externalize-string-extension.cc
@@ -100,7 +100,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
data, string->length());
result = string->MakeExternal(resource);
if (result && !string->IsSymbol()) {
- i::ExternalStringTable::AddString(*string);
+ HEAP->external_string_table()->AddString(*string);
}
if (!result) delete resource;
} else {
@@ -110,7 +110,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
data, string->length());
result = string->MakeExternal(resource);
if (result && !string->IsSymbol()) {
- i::ExternalStringTable::AddString(*string);
+ HEAP->external_string_table()->AddString(*string);
}
if (!result) delete resource;
}
diff --git a/src/extensions/gc-extension.cc b/src/extensions/gc-extension.cc
index 63daa05b..3740c27a 100644
--- a/src/extensions/gc-extension.cc
+++ b/src/extensions/gc-extension.cc
@@ -45,7 +45,7 @@ v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) {
if (args.Length() >= 1 && args[0]->IsBoolean()) {
compact = args[0]->BooleanValue();
}
- Heap::CollectAllGarbage(compact);
+ HEAP->CollectAllGarbage(compact);
return v8::Undefined();
}
diff --git a/src/factory.cc b/src/factory.cc
index 96c757a3..7dee66f6 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -41,35 +41,43 @@ namespace internal {
Handle<FixedArray> Factory::NewFixedArray(int size, PretenureFlag pretenure) {
ASSERT(0 <= size);
- CALL_HEAP_FUNCTION(Heap::AllocateFixedArray(size, pretenure), FixedArray);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateFixedArray(size, pretenure),
+ FixedArray);
}
Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size,
PretenureFlag pretenure) {
ASSERT(0 <= size);
- CALL_HEAP_FUNCTION(Heap::AllocateFixedArrayWithHoles(size, pretenure),
- FixedArray);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateFixedArrayWithHoles(size, pretenure),
+ FixedArray);
}
Handle<StringDictionary> Factory::NewStringDictionary(int at_least_space_for) {
ASSERT(0 <= at_least_space_for);
- CALL_HEAP_FUNCTION(StringDictionary::Allocate(at_least_space_for),
+ CALL_HEAP_FUNCTION(isolate(),
+ StringDictionary::Allocate(at_least_space_for),
StringDictionary);
}
Handle<NumberDictionary> Factory::NewNumberDictionary(int at_least_space_for) {
ASSERT(0 <= at_least_space_for);
- CALL_HEAP_FUNCTION(NumberDictionary::Allocate(at_least_space_for),
+ CALL_HEAP_FUNCTION(isolate(),
+ NumberDictionary::Allocate(at_least_space_for),
NumberDictionary);
}
Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors) {
ASSERT(0 <= number_of_descriptors);
- CALL_HEAP_FUNCTION(DescriptorArray::Allocate(number_of_descriptors),
+ CALL_HEAP_FUNCTION(isolate(),
+ DescriptorArray::Allocate(number_of_descriptors),
DescriptorArray);
}
@@ -78,7 +86,8 @@ Handle<DeoptimizationInputData> Factory::NewDeoptimizationInputData(
int deopt_entry_count,
PretenureFlag pretenure) {
ASSERT(deopt_entry_count > 0);
- CALL_HEAP_FUNCTION(DeoptimizationInputData::Allocate(deopt_entry_count,
+ CALL_HEAP_FUNCTION(isolate(),
+ DeoptimizationInputData::Allocate(deopt_entry_count,
pretenure),
DeoptimizationInputData);
}
@@ -88,7 +97,8 @@ Handle<DeoptimizationOutputData> Factory::NewDeoptimizationOutputData(
int deopt_entry_count,
PretenureFlag pretenure) {
ASSERT(deopt_entry_count > 0);
- CALL_HEAP_FUNCTION(DeoptimizationOutputData::Allocate(deopt_entry_count,
+ CALL_HEAP_FUNCTION(isolate(),
+ DeoptimizationOutputData::Allocate(deopt_entry_count,
pretenure),
DeoptimizationOutputData);
}
@@ -96,96 +106,137 @@ Handle<DeoptimizationOutputData> Factory::NewDeoptimizationOutputData(
// Symbols are created in the old generation (data space).
Handle<String> Factory::LookupSymbol(Vector<const char> string) {
- CALL_HEAP_FUNCTION(Heap::LookupSymbol(string), String);
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->LookupSymbol(string),
+ String);
}
Handle<String> Factory::LookupAsciiSymbol(Vector<const char> string) {
- CALL_HEAP_FUNCTION(Heap::LookupAsciiSymbol(string), String);
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->LookupAsciiSymbol(string),
+ String);
}
Handle<String> Factory::LookupTwoByteSymbol(Vector<const uc16> string) {
- CALL_HEAP_FUNCTION(Heap::LookupTwoByteSymbol(string), String);
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->LookupTwoByteSymbol(string),
+ String);
}
Handle<String> Factory::NewStringFromAscii(Vector<const char> string,
PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(Heap::AllocateStringFromAscii(string, pretenure), String);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateStringFromAscii(string, pretenure),
+ String);
}
Handle<String> Factory::NewStringFromUtf8(Vector<const char> string,
PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(Heap::AllocateStringFromUtf8(string, pretenure), String);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateStringFromUtf8(string, pretenure),
+ String);
}
Handle<String> Factory::NewStringFromTwoByte(Vector<const uc16> string,
PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(Heap::AllocateStringFromTwoByte(string, pretenure),
- String);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateStringFromTwoByte(string, pretenure),
+ String);
}
Handle<String> Factory::NewRawAsciiString(int length,
PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(length, pretenure), String);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateRawAsciiString(length, pretenure),
+ String);
}
Handle<String> Factory::NewRawTwoByteString(int length,
PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(length, pretenure), String);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateRawTwoByteString(length, pretenure),
+ String);
}
Handle<String> Factory::NewConsString(Handle<String> first,
Handle<String> second) {
- CALL_HEAP_FUNCTION(Heap::AllocateConsString(*first, *second), String);
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateConsString(*first, *second),
+ String);
}
Handle<String> Factory::NewSubString(Handle<String> str,
int begin,
int end) {
- CALL_HEAP_FUNCTION(str->SubString(begin, end), String);
+ CALL_HEAP_FUNCTION(isolate(),
+ str->SubString(begin, end),
+ String);
}
Handle<String> Factory::NewExternalStringFromAscii(
ExternalAsciiString::Resource* resource) {
- CALL_HEAP_FUNCTION(Heap::AllocateExternalStringFromAscii(resource), String);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateExternalStringFromAscii(resource),
+ String);
}
Handle<String> Factory::NewExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource) {
- CALL_HEAP_FUNCTION(Heap::AllocateExternalStringFromTwoByte(resource), String);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateExternalStringFromTwoByte(resource),
+ String);
}
Handle<Context> Factory::NewGlobalContext() {
- CALL_HEAP_FUNCTION(Heap::AllocateGlobalContext(), Context);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateGlobalContext(),
+ Context);
}
Handle<Context> Factory::NewFunctionContext(int length,
Handle<JSFunction> closure) {
- CALL_HEAP_FUNCTION(Heap::AllocateFunctionContext(length, *closure), Context);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateFunctionContext(length, *closure),
+ Context);
}
Handle<Context> Factory::NewWithContext(Handle<Context> previous,
Handle<JSObject> extension,
bool is_catch_context) {
- CALL_HEAP_FUNCTION(Heap::AllocateWithContext(*previous,
- *extension,
- is_catch_context),
- Context);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateWithContext(*previous,
+ *extension,
+ is_catch_context),
+ Context);
}
Handle<Struct> Factory::NewStruct(InstanceType type) {
- CALL_HEAP_FUNCTION(Heap::AllocateStruct(type), Struct);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateStruct(type),
+ Struct);
}
@@ -200,34 +251,35 @@ Handle<AccessorInfo> Factory::NewAccessorInfo() {
Handle<Script> Factory::NewScript(Handle<String> source) {
// Generate id for this script.
int id;
- if (Heap::last_script_id()->IsUndefined()) {
+ Heap* heap = isolate()->heap();
+ if (heap->last_script_id()->IsUndefined()) {
// Script ids start from one.
id = 1;
} else {
// Increment id, wrap when positive smi is exhausted.
- id = Smi::cast(Heap::last_script_id())->value();
+ id = Smi::cast(heap->last_script_id())->value();
id++;
if (!Smi::IsValid(id)) {
id = 0;
}
}
- Heap::SetLastScriptId(Smi::FromInt(id));
+ heap->SetLastScriptId(Smi::FromInt(id));
// Create and initialize script object.
- Handle<Proxy> wrapper = Factory::NewProxy(0, TENURED);
+ Handle<Proxy> wrapper = NewProxy(0, TENURED);
Handle<Script> script = Handle<Script>::cast(NewStruct(SCRIPT_TYPE));
script->set_source(*source);
- script->set_name(Heap::undefined_value());
- script->set_id(Heap::last_script_id());
+ script->set_name(heap->undefined_value());
+ script->set_id(heap->last_script_id());
script->set_line_offset(Smi::FromInt(0));
script->set_column_offset(Smi::FromInt(0));
- script->set_data(Heap::undefined_value());
- script->set_context_data(Heap::undefined_value());
+ script->set_data(heap->undefined_value());
+ script->set_context_data(heap->undefined_value());
script->set_type(Smi::FromInt(Script::TYPE_NORMAL));
script->set_compilation_type(Smi::FromInt(Script::COMPILATION_TYPE_HOST));
script->set_wrapper(*wrapper);
- script->set_line_ends(Heap::undefined_value());
- script->set_eval_from_shared(Heap::undefined_value());
+ script->set_line_ends(heap->undefined_value());
+ script->set_eval_from_shared(heap->undefined_value());
script->set_eval_from_instructions_offset(Smi::FromInt(0));
return script;
@@ -235,7 +287,9 @@ Handle<Script> Factory::NewScript(Handle<String> source) {
Handle<Proxy> Factory::NewProxy(Address addr, PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(Heap::AllocateProxy(addr, pretenure), Proxy);
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateProxy(addr, pretenure),
+ Proxy);
}
@@ -246,17 +300,10 @@ Handle<Proxy> Factory::NewProxy(const AccessorDescriptor* desc) {
Handle<ByteArray> Factory::NewByteArray(int length, PretenureFlag pretenure) {
ASSERT(0 <= length);
- CALL_HEAP_FUNCTION(Heap::AllocateByteArray(length, pretenure), ByteArray);
-}
-
-
-Handle<PixelArray> Factory::NewPixelArray(int length,
- uint8_t* external_pointer,
- PretenureFlag pretenure) {
- ASSERT(0 <= length);
- CALL_HEAP_FUNCTION(Heap::AllocatePixelArray(length,
- external_pointer,
- pretenure), PixelArray);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateByteArray(length, pretenure),
+ ByteArray);
}
@@ -265,32 +312,43 @@ Handle<ExternalArray> Factory::NewExternalArray(int length,
void* external_pointer,
PretenureFlag pretenure) {
ASSERT(0 <= length);
- CALL_HEAP_FUNCTION(Heap::AllocateExternalArray(length,
- array_type,
- external_pointer,
- pretenure), ExternalArray);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateExternalArray(length,
+ array_type,
+ external_pointer,
+ pretenure),
+ ExternalArray);
}
Handle<JSGlobalPropertyCell> Factory::NewJSGlobalPropertyCell(
Handle<Object> value) {
- CALL_HEAP_FUNCTION(Heap::AllocateJSGlobalPropertyCell(*value),
- JSGlobalPropertyCell);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateJSGlobalPropertyCell(*value),
+ JSGlobalPropertyCell);
}
Handle<Map> Factory::NewMap(InstanceType type, int instance_size) {
- CALL_HEAP_FUNCTION(Heap::AllocateMap(type, instance_size), Map);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateMap(type, instance_size),
+ Map);
}
Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) {
- CALL_HEAP_FUNCTION(Heap::AllocateFunctionPrototype(*function), JSObject);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateFunctionPrototype(*function),
+ JSObject);
}
Handle<Map> Factory::CopyMapDropDescriptors(Handle<Map> src) {
- CALL_HEAP_FUNCTION(src->CopyDropDescriptors(), Map);
+ CALL_HEAP_FUNCTION(isolate(), src->CopyDropDescriptors(), Map);
}
@@ -320,27 +378,33 @@ Handle<Map> Factory::CopyMap(Handle<Map> src,
Handle<Map> Factory::CopyMapDropTransitions(Handle<Map> src) {
- CALL_HEAP_FUNCTION(src->CopyDropTransitions(), Map);
+ CALL_HEAP_FUNCTION(isolate(), src->CopyDropTransitions(), Map);
}
Handle<Map> Factory::GetFastElementsMap(Handle<Map> src) {
- CALL_HEAP_FUNCTION(src->GetFastElementsMap(), Map);
+ CALL_HEAP_FUNCTION(isolate(), src->GetFastElementsMap(), Map);
}
Handle<Map> Factory::GetSlowElementsMap(Handle<Map> src) {
- CALL_HEAP_FUNCTION(src->GetSlowElementsMap(), Map);
+ CALL_HEAP_FUNCTION(isolate(), src->GetSlowElementsMap(), Map);
}
-Handle<Map> Factory::GetPixelArrayElementsMap(Handle<Map> src) {
- CALL_HEAP_FUNCTION(src->GetPixelArrayElementsMap(), Map);
+Handle<Map> Factory::GetExternalArrayElementsMap(
+ Handle<Map> src,
+ ExternalArrayType array_type,
+ bool safe_to_add_transition) {
+ CALL_HEAP_FUNCTION(isolate(),
+ src->GetExternalArrayElementsMap(array_type,
+ safe_to_add_transition),
+ Map);
}
Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
- CALL_HEAP_FUNCTION(array->Copy(), FixedArray);
+ CALL_HEAP_FUNCTION(isolate(), array->Copy(), FixedArray);
}
@@ -348,10 +412,12 @@ Handle<JSFunction> Factory::BaseNewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> function_info,
Handle<Map> function_map,
PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(Heap::AllocateFunction(*function_map,
- *function_info,
- Heap::the_hole_value(),
- pretenure),
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateFunction(*function_map,
+ *function_info,
+ isolate()->heap()->the_hole_value(),
+ pretenure),
JSFunction);
}
@@ -361,11 +427,15 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
Handle<Context> context,
PretenureFlag pretenure) {
Handle<JSFunction> result = BaseNewFunctionFromSharedFunctionInfo(
- function_info, Top::function_map(), pretenure);
+ function_info,
+ function_info->strict_mode()
+ ? isolate()->strict_mode_function_map()
+ : isolate()->function_map(),
+ pretenure);
+
result->set_context(*context);
int number_of_literals = function_info->num_literals();
- Handle<FixedArray> literals =
- Factory::NewFixedArray(number_of_literals, pretenure);
+ Handle<FixedArray> literals = NewFixedArray(number_of_literals, pretenure);
if (number_of_literals > 0) {
// Store the object, regexp and array functions in the literals
// array prefix. These functions will be used when creating
@@ -374,7 +444,7 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
context->global_context());
}
result->set_literals(*literals);
- result->set_next_function_link(Heap::undefined_value());
+ result->set_next_function_link(isolate()->heap()->undefined_value());
if (V8::UseCrankshaft() &&
FLAG_always_opt &&
@@ -389,23 +459,32 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
Handle<Object> Factory::NewNumber(double value,
PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(Heap::NumberFromDouble(value, pretenure), Object);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->NumberFromDouble(value, pretenure), Object);
}
Handle<Object> Factory::NewNumberFromInt(int value) {
- CALL_HEAP_FUNCTION(Heap::NumberFromInt32(value), Object);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->NumberFromInt32(value), Object);
}
Handle<Object> Factory::NewNumberFromUint(uint32_t value) {
- CALL_HEAP_FUNCTION(Heap::NumberFromUint32(value), Object);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->NumberFromUint32(value), Object);
}
Handle<JSObject> Factory::NewNeanderObject() {
- CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(Heap::neander_map()),
- JSObject);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateJSObjectFromMap(
+ isolate()->heap()->neander_map()),
+ JSObject);
}
@@ -455,11 +534,11 @@ Handle<Object> Factory::NewReferenceError(Handle<String> message) {
Handle<Object> Factory::NewError(const char* maker, const char* type,
Vector< Handle<Object> > args) {
v8::HandleScope scope; // Instantiate a closeable HandleScope for EscapeFrom.
- Handle<FixedArray> array = Factory::NewFixedArray(args.length());
+ Handle<FixedArray> array = NewFixedArray(args.length());
for (int i = 0; i < args.length(); i++) {
array->set(i, *args[i]);
}
- Handle<JSArray> object = Factory::NewJSArrayWithElements(array);
+ Handle<JSArray> object = NewJSArrayWithElements(array);
Handle<Object> result = NewError(maker, type, object);
return result.EscapeFrom(&scope);
}
@@ -480,15 +559,15 @@ Handle<Object> Factory::NewError(const char* type,
Handle<Object> Factory::NewError(const char* maker,
const char* type,
Handle<JSArray> args) {
- Handle<String> make_str = Factory::LookupAsciiSymbol(maker);
- Handle<Object> fun_obj(Top::builtins()->GetPropertyNoExceptionThrown(
- *make_str));
+ Handle<String> make_str = LookupAsciiSymbol(maker);
+ Handle<Object> fun_obj(
+ isolate()->js_builtins_object()->GetPropertyNoExceptionThrown(*make_str));
// If the builtins haven't been properly configured yet this error
// constructor may not have been defined. Bail out.
if (!fun_obj->IsJSFunction())
- return Factory::undefined_value();
+ return undefined_value();
Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj);
- Handle<Object> type_obj = Factory::LookupAsciiSymbol(type);
+ Handle<Object> type_obj = LookupAsciiSymbol(type);
Object** argv[2] = { type_obj.location(),
Handle<Object>::cast(args).location() };
@@ -496,10 +575,7 @@ Handle<Object> Factory::NewError(const char* maker,
// running the factory method, use the exception as the result.
bool caught_exception;
Handle<Object> result = Execution::TryCall(fun,
- Top::builtins(),
- 2,
- argv,
- &caught_exception);
+ isolate()->js_builtins_object(), 2, argv, &caught_exception);
return result;
}
@@ -511,21 +587,17 @@ Handle<Object> Factory::NewError(Handle<String> message) {
Handle<Object> Factory::NewError(const char* constructor,
Handle<String> message) {
- Handle<String> constr = Factory::LookupAsciiSymbol(constructor);
- Handle<JSFunction> fun =
- Handle<JSFunction>(
- JSFunction::cast(
- Top::builtins()->GetPropertyNoExceptionThrown(*constr)));
+ Handle<String> constr = LookupAsciiSymbol(constructor);
+ Handle<JSFunction> fun = Handle<JSFunction>(
+ JSFunction::cast(isolate()->js_builtins_object()->
+ GetPropertyNoExceptionThrown(*constr)));
Object** argv[1] = { Handle<Object>::cast(message).location() };
// Invoke the JavaScript factory method. If an exception is thrown while
// running the factory method, use the exception as the result.
bool caught_exception;
Handle<Object> result = Execution::TryCall(fun,
- Top::builtins(),
- 1,
- argv,
- &caught_exception);
+ isolate()->js_builtins_object(), 1, argv, &caught_exception);
return result;
}
@@ -586,15 +658,15 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
// property that refers to the function.
SetPrototypeProperty(function, prototype);
// Currently safe because it is only invoked from Genesis.
- SetLocalPropertyNoThrow(
- prototype, Factory::constructor_symbol(), function, DONT_ENUM);
+ SetLocalPropertyNoThrow(prototype, constructor_symbol(), function, DONT_ENUM);
return function;
}
Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
Handle<Code> code) {
- Handle<JSFunction> function = NewFunctionWithoutPrototype(name);
+ Handle<JSFunction> function = NewFunctionWithoutPrototype(name,
+ kNonStrictMode);
function->shared()->set_code(*code);
function->set_code(*code);
ASSERT(!function->has_initial_map());
@@ -605,18 +677,26 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
Handle<Code> Factory::NewCode(const CodeDesc& desc,
Code::Flags flags,
- Handle<Object> self_ref) {
- CALL_HEAP_FUNCTION(Heap::CreateCode(desc, flags, self_ref), Code);
+ Handle<Object> self_ref,
+ bool immovable) {
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->CreateCode(
+ desc, flags, self_ref, immovable),
+ Code);
}
Handle<Code> Factory::CopyCode(Handle<Code> code) {
- CALL_HEAP_FUNCTION(Heap::CopyCode(*code), Code);
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->CopyCode(*code),
+ Code);
}
Handle<Code> Factory::CopyCode(Handle<Code> code, Vector<byte> reloc_info) {
- CALL_HEAP_FUNCTION(Heap::CopyCode(*code, reloc_info), Code);
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->CopyCode(*code, reloc_info),
+ Code);
}
@@ -637,13 +717,15 @@ Handle<DescriptorArray> Factory::CopyAppendProxyDescriptor(
Handle<String> key,
Handle<Object> value,
PropertyAttributes attributes) {
- CALL_HEAP_FUNCTION(DoCopyInsert(*array, *key, *value, attributes),
+ CALL_HEAP_FUNCTION(isolate(),
+ DoCopyInsert(*array, *key, *value, attributes),
DescriptorArray);
}
Handle<String> Factory::SymbolFromString(Handle<String> value) {
- CALL_HEAP_FUNCTION(Heap::LookupSymbol(*value), String);
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->LookupSymbol(*value), String);
}
@@ -708,35 +790,43 @@ Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
Handle<JSObject> Factory::NewJSObject(Handle<JSFunction> constructor,
PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(Heap::AllocateJSObject(*constructor, pretenure), JSObject);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateJSObject(*constructor, pretenure), JSObject);
}
Handle<GlobalObject> Factory::NewGlobalObject(
Handle<JSFunction> constructor) {
- CALL_HEAP_FUNCTION(Heap::AllocateGlobalObject(*constructor),
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateGlobalObject(*constructor),
GlobalObject);
}
Handle<JSObject> Factory::NewJSObjectFromMap(Handle<Map> map) {
- CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(*map, NOT_TENURED),
- JSObject);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateJSObjectFromMap(*map, NOT_TENURED),
+ JSObject);
}
-Handle<JSArray> Factory::NewJSArray(int length,
+Handle<JSArray> Factory::NewJSArray(int capacity,
PretenureFlag pretenure) {
- Handle<JSObject> obj = NewJSObject(Top::array_function(), pretenure);
- CALL_HEAP_FUNCTION(Handle<JSArray>::cast(obj)->Initialize(length), JSArray);
+ Handle<JSObject> obj = NewJSObject(isolate()->array_function(), pretenure);
+ CALL_HEAP_FUNCTION(isolate(),
+ Handle<JSArray>::cast(obj)->Initialize(capacity),
+ JSArray);
}
Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArray> elements,
PretenureFlag pretenure) {
Handle<JSArray> result =
- Handle<JSArray>::cast(NewJSObject(Top::array_function(), pretenure));
+ Handle<JSArray>::cast(NewJSObject(isolate()->array_function(),
+ pretenure));
result->SetContent(*elements);
return result;
}
@@ -770,24 +860,27 @@ Handle<JSMessageObject> Factory::NewJSMessageObject(
Handle<Object> script,
Handle<Object> stack_trace,
Handle<Object> stack_frames) {
- CALL_HEAP_FUNCTION(Heap::AllocateJSMessageObject(*type,
- *arguments,
- start_position,
- end_position,
- *script,
- *stack_trace,
- *stack_frames),
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateJSMessageObject(*type,
+ *arguments,
+ start_position,
+ end_position,
+ *script,
+ *stack_trace,
+ *stack_frames),
JSMessageObject);
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) {
- CALL_HEAP_FUNCTION(Heap::AllocateSharedFunctionInfo(*name),
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateSharedFunctionInfo(*name),
SharedFunctionInfo);
}
Handle<String> Factory::NumberToString(Handle<Object> number) {
- CALL_HEAP_FUNCTION(Heap::NumberToString(*number), String);
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->NumberToString(*number), String);
}
@@ -795,54 +888,65 @@ Handle<NumberDictionary> Factory::DictionaryAtNumberPut(
Handle<NumberDictionary> dictionary,
uint32_t key,
Handle<Object> value) {
- CALL_HEAP_FUNCTION(dictionary->AtNumberPut(key, *value), NumberDictionary);
+ CALL_HEAP_FUNCTION(isolate(),
+ dictionary->AtNumberPut(key, *value),
+ NumberDictionary);
}
Handle<JSFunction> Factory::NewFunctionHelper(Handle<String> name,
Handle<Object> prototype) {
Handle<SharedFunctionInfo> function_share = NewSharedFunctionInfo(name);
- CALL_HEAP_FUNCTION(Heap::AllocateFunction(*Top::function_map(),
- *function_share,
- *prototype),
- JSFunction);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateFunction(*isolate()->function_map(),
+ *function_share,
+ *prototype),
+ JSFunction);
}
Handle<JSFunction> Factory::NewFunction(Handle<String> name,
Handle<Object> prototype) {
Handle<JSFunction> fun = NewFunctionHelper(name, prototype);
- fun->set_context(Top::context()->global_context());
+ fun->set_context(isolate()->context()->global_context());
return fun;
}
Handle<JSFunction> Factory::NewFunctionWithoutPrototypeHelper(
- Handle<String> name) {
+ Handle<String> name,
+ StrictModeFlag strict_mode) {
Handle<SharedFunctionInfo> function_share = NewSharedFunctionInfo(name);
- CALL_HEAP_FUNCTION(Heap::AllocateFunction(
- *Top::function_without_prototype_map(),
+ Handle<Map> map = strict_mode == kStrictMode
+ ? isolate()->strict_mode_function_without_prototype_map()
+ : isolate()->function_without_prototype_map();
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateFunction(
+ *map,
*function_share,
*the_hole_value()),
JSFunction);
}
-Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name) {
- Handle<JSFunction> fun = NewFunctionWithoutPrototypeHelper(name);
- fun->set_context(Top::context()->global_context());
+Handle<JSFunction> Factory::NewFunctionWithoutPrototype(
+ Handle<String> name,
+ StrictModeFlag strict_mode) {
+ Handle<JSFunction> fun = NewFunctionWithoutPrototypeHelper(name, strict_mode);
+ fun->set_context(isolate()->context()->global_context());
return fun;
}
Handle<Object> Factory::ToObject(Handle<Object> object) {
- CALL_HEAP_FUNCTION(object->ToObject(), Object);
+ CALL_HEAP_FUNCTION(isolate(), object->ToObject(), Object);
}
Handle<Object> Factory::ToObject(Handle<Object> object,
Handle<Context> global_context) {
- CALL_HEAP_FUNCTION(object->ToObject(*global_context), Object);
+ CALL_HEAP_FUNCTION(isolate(), object->ToObject(*global_context), Object);
}
@@ -859,13 +963,13 @@ Handle<DebugInfo> Factory::NewDebugInfo(Handle<SharedFunctionInfo> shared) {
// debug info object to avoid allocation while setting up the debug info
// object.
Handle<FixedArray> break_points(
- Factory::NewFixedArray(Debug::kEstimatedNofBreakPointsInFunction));
+ NewFixedArray(Debug::kEstimatedNofBreakPointsInFunction));
// Create and set up the debug info object. Debug info contains function, a
// copy of the original code, the executing code and initial fixed array for
// active break points.
Handle<DebugInfo> debug_info =
- Handle<DebugInfo>::cast(Factory::NewStruct(DEBUG_INFO_TYPE));
+ Handle<DebugInfo>::cast(NewStruct(DEBUG_INFO_TYPE));
debug_info->set_shared(*shared);
debug_info->set_original_code(*original_code);
debug_info->set_code(*code);
@@ -881,15 +985,16 @@ Handle<DebugInfo> Factory::NewDebugInfo(Handle<SharedFunctionInfo> shared) {
Handle<JSObject> Factory::NewArgumentsObject(Handle<Object> callee,
int length) {
- CALL_HEAP_FUNCTION(Heap::AllocateArgumentsObject(*callee, length), JSObject);
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateArgumentsObject(*callee, length), JSObject);
}
Handle<JSFunction> Factory::CreateApiFunction(
Handle<FunctionTemplateInfo> obj, ApiInstanceType instance_type) {
- Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::HandleApiCall));
- Handle<Code> construct_stub =
- Handle<Code>(Builtins::builtin(Builtins::JSConstructStubApi));
+ Handle<Code> code = isolate()->builtins()->HandleApiCall();
+ Handle<Code> construct_stub = isolate()->builtins()->JSConstructStubApi();
int internal_field_count = 0;
if (!obj->instance_template()->IsUndefined()) {
@@ -921,11 +1026,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
ASSERT(type != INVALID_TYPE);
Handle<JSFunction> result =
- Factory::NewFunction(Factory::empty_symbol(),
- type,
- instance_size,
- code,
- true);
+ NewFunction(Factory::empty_symbol(),
+ type,
+ instance_size,
+ code,
+ true);
// Set class name.
Handle<Object> class_name = Handle<Object>(obj->class_name());
if (class_name->IsString()) {
@@ -973,7 +1078,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
while (true) {
Handle<Object> props = Handle<Object>(obj->property_accessors());
if (!props->IsUndefined()) {
- array = Factory::CopyAppendCallbackDescriptors(array, props);
+ array = CopyAppendCallbackDescriptors(array, props);
}
Handle<Object> parent = Handle<Object>(obj->parent_template());
if (parent->IsUndefined()) break;
@@ -989,7 +1094,8 @@ Handle<JSFunction> Factory::CreateApiFunction(
Handle<MapCache> Factory::NewMapCache(int at_least_space_for) {
- CALL_HEAP_FUNCTION(MapCache::Allocate(at_least_space_for), MapCache);
+ CALL_HEAP_FUNCTION(isolate(),
+ MapCache::Allocate(at_least_space_for), MapCache);
}
@@ -1009,7 +1115,8 @@ MUST_USE_RESULT static MaybeObject* UpdateMapCacheWith(Context* context,
Handle<MapCache> Factory::AddToMapCache(Handle<Context> context,
Handle<FixedArray> keys,
Handle<Map> map) {
- CALL_HEAP_FUNCTION(UpdateMapCacheWith(*context, *keys, *map), MapCache);
+ CALL_HEAP_FUNCTION(isolate(),
+ UpdateMapCacheWith(*context, *keys, *map), MapCache);
}
@@ -1058,8 +1165,8 @@ void Factory::SetRegExpIrregexpData(Handle<JSRegExp> regexp,
store->set(JSRegExp::kTagIndex, Smi::FromInt(type));
store->set(JSRegExp::kSourceIndex, *source);
store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags.value()));
- store->set(JSRegExp::kIrregexpASCIICodeIndex, Heap::the_hole_value());
- store->set(JSRegExp::kIrregexpUC16CodeIndex, Heap::the_hole_value());
+ store->set(JSRegExp::kIrregexpASCIICodeIndex, HEAP->the_hole_value());
+ store->set(JSRegExp::kIrregexpUC16CodeIndex, HEAP->the_hole_value());
store->set(JSRegExp::kIrregexpMaxRegisterCountIndex, Smi::FromInt(0));
store->set(JSRegExp::kIrregexpCaptureCountIndex,
Smi::FromInt(capture_count));
diff --git a/src/factory.h b/src/factory.h
index 7547f7c4..71bfdc4c 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -29,6 +29,7 @@
#define V8_FACTORY_H_
#include "globals.h"
+#include "handles.h"
#include "heap.h"
namespace v8 {
@@ -36,34 +37,34 @@ namespace internal {
// Interface for handle based allocation.
-class Factory : public AllStatic {
+class Factory {
public:
// Allocate a new fixed array with undefined entries.
- static Handle<FixedArray> NewFixedArray(
+ Handle<FixedArray> NewFixedArray(
int size,
PretenureFlag pretenure = NOT_TENURED);
// Allocate a new fixed array with non-existing entries (the hole).
- static Handle<FixedArray> NewFixedArrayWithHoles(
+ Handle<FixedArray> NewFixedArrayWithHoles(
int size,
PretenureFlag pretenure = NOT_TENURED);
- static Handle<NumberDictionary> NewNumberDictionary(int at_least_space_for);
+ Handle<NumberDictionary> NewNumberDictionary(int at_least_space_for);
- static Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
+ Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
- static Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
- static Handle<DeoptimizationInputData> NewDeoptimizationInputData(
+ Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
+ Handle<DeoptimizationInputData> NewDeoptimizationInputData(
int deopt_entry_count,
PretenureFlag pretenure);
- static Handle<DeoptimizationOutputData> NewDeoptimizationOutputData(
+ Handle<DeoptimizationOutputData> NewDeoptimizationOutputData(
int deopt_entry_count,
PretenureFlag pretenure);
- static Handle<String> LookupSymbol(Vector<const char> str);
- static Handle<String> LookupAsciiSymbol(Vector<const char> str);
- static Handle<String> LookupTwoByteSymbol(Vector<const uc16> str);
- static Handle<String> LookupAsciiSymbol(const char* str) {
+ Handle<String> LookupSymbol(Vector<const char> str);
+ Handle<String> LookupAsciiSymbol(Vector<const char> str);
+ Handle<String> LookupTwoByteSymbol(Vector<const uc16> str);
+ Handle<String> LookupAsciiSymbol(const char* str) {
return LookupSymbol(CStrVector(str));
}
@@ -90,236 +91,236 @@ class Factory : public AllStatic {
// two byte.
//
// ASCII strings are pretenured when used as keys in the SourceCodeCache.
- static Handle<String> NewStringFromAscii(
+ Handle<String> NewStringFromAscii(
Vector<const char> str,
PretenureFlag pretenure = NOT_TENURED);
// UTF8 strings are pretenured when used for regexp literal patterns and
// flags in the parser.
- static Handle<String> NewStringFromUtf8(
+ Handle<String> NewStringFromUtf8(
Vector<const char> str,
PretenureFlag pretenure = NOT_TENURED);
- static Handle<String> NewStringFromTwoByte(
+ Handle<String> NewStringFromTwoByte(
Vector<const uc16> str,
PretenureFlag pretenure = NOT_TENURED);
// Allocates and partially initializes an ASCII or TwoByte String. The
// characters of the string are uninitialized. Currently used in regexp code
// only, where they are pretenured.
- static Handle<String> NewRawAsciiString(
+ Handle<String> NewRawAsciiString(
int length,
PretenureFlag pretenure = NOT_TENURED);
- static Handle<String> NewRawTwoByteString(
+ Handle<String> NewRawTwoByteString(
int length,
PretenureFlag pretenure = NOT_TENURED);
// Create a new cons string object which consists of a pair of strings.
- static Handle<String> NewConsString(Handle<String> first,
- Handle<String> second);
+ Handle<String> NewConsString(Handle<String> first,
+ Handle<String> second);
// Create a new string object which holds a substring of a string.
- static Handle<String> NewSubString(Handle<String> str,
- int begin,
- int end);
+ Handle<String> NewSubString(Handle<String> str,
+ int begin,
+ int end);
// Creates a new external String object. There are two String encodings
// in the system: ASCII and two byte. Unlike other String types, it does
// not make sense to have a UTF-8 factory function for external strings,
// because we cannot change the underlying buffer.
- static Handle<String> NewExternalStringFromAscii(
+ Handle<String> NewExternalStringFromAscii(
ExternalAsciiString::Resource* resource);
- static Handle<String> NewExternalStringFromTwoByte(
+ Handle<String> NewExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource);
// Create a global (but otherwise uninitialized) context.
- static Handle<Context> NewGlobalContext();
+ Handle<Context> NewGlobalContext();
// Create a function context.
- static Handle<Context> NewFunctionContext(int length,
- Handle<JSFunction> closure);
+ Handle<Context> NewFunctionContext(int length,
+ Handle<JSFunction> closure);
// Create a 'with' context.
- static Handle<Context> NewWithContext(Handle<Context> previous,
- Handle<JSObject> extension,
- bool is_catch_context);
+ Handle<Context> NewWithContext(Handle<Context> previous,
+ Handle<JSObject> extension,
+ bool is_catch_context);
// Return the Symbol matching the passed in string.
- static Handle<String> SymbolFromString(Handle<String> value);
+ Handle<String> SymbolFromString(Handle<String> value);
// Allocate a new struct. The struct is pretenured (allocated directly in
// the old generation).
- static Handle<Struct> NewStruct(InstanceType type);
+ Handle<Struct> NewStruct(InstanceType type);
- static Handle<AccessorInfo> NewAccessorInfo();
+ Handle<AccessorInfo> NewAccessorInfo();
- static Handle<Script> NewScript(Handle<String> source);
+ Handle<Script> NewScript(Handle<String> source);
// Proxies are pretenured when allocated by the bootstrapper.
- static Handle<Proxy> NewProxy(Address addr,
- PretenureFlag pretenure = NOT_TENURED);
+ Handle<Proxy> NewProxy(Address addr,
+ PretenureFlag pretenure = NOT_TENURED);
// Allocate a new proxy. The proxy is pretenured (allocated directly in
// the old generation).
- static Handle<Proxy> NewProxy(const AccessorDescriptor* proxy);
+ Handle<Proxy> NewProxy(const AccessorDescriptor* proxy);
- static Handle<ByteArray> NewByteArray(int length,
- PretenureFlag pretenure = NOT_TENURED);
+ Handle<ByteArray> NewByteArray(int length,
+ PretenureFlag pretenure = NOT_TENURED);
- static Handle<PixelArray> NewPixelArray(
- int length,
- uint8_t* external_pointer,
- PretenureFlag pretenure = NOT_TENURED);
-
- static Handle<ExternalArray> NewExternalArray(
+ Handle<ExternalArray> NewExternalArray(
int length,
ExternalArrayType array_type,
void* external_pointer,
PretenureFlag pretenure = NOT_TENURED);
- static Handle<JSGlobalPropertyCell> NewJSGlobalPropertyCell(
+ Handle<JSGlobalPropertyCell> NewJSGlobalPropertyCell(
Handle<Object> value);
- static Handle<Map> NewMap(InstanceType type, int instance_size);
+ Handle<Map> NewMap(InstanceType type, int instance_size);
- static Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
+ Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
- static Handle<Map> CopyMapDropDescriptors(Handle<Map> map);
+ Handle<Map> CopyMapDropDescriptors(Handle<Map> map);
// Copy the map adding more inobject properties if possible without
// overflowing the instance size.
- static Handle<Map> CopyMap(Handle<Map> map, int extra_inobject_props);
+ Handle<Map> CopyMap(Handle<Map> map, int extra_inobject_props);
- static Handle<Map> CopyMapDropTransitions(Handle<Map> map);
+ Handle<Map> CopyMapDropTransitions(Handle<Map> map);
- static Handle<Map> GetFastElementsMap(Handle<Map> map);
+ Handle<Map> GetFastElementsMap(Handle<Map> map);
- static Handle<Map> GetSlowElementsMap(Handle<Map> map);
+ Handle<Map> GetSlowElementsMap(Handle<Map> map);
- static Handle<Map> GetPixelArrayElementsMap(Handle<Map> map);
+ Handle<Map> GetExternalArrayElementsMap(Handle<Map> map,
+ ExternalArrayType array_type,
+ bool safe_to_add_transition);
- static Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
+ Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
// Numbers (eg, literals) are pretenured by the parser.
- static Handle<Object> NewNumber(double value,
- PretenureFlag pretenure = NOT_TENURED);
+ Handle<Object> NewNumber(double value,
+ PretenureFlag pretenure = NOT_TENURED);
- static Handle<Object> NewNumberFromInt(int value);
- static Handle<Object> NewNumberFromUint(uint32_t value);
+ Handle<Object> NewNumberFromInt(int value);
+ Handle<Object> NewNumberFromUint(uint32_t value);
// These objects are used by the api to create env-independent data
// structures in the heap.
- static Handle<JSObject> NewNeanderObject();
+ Handle<JSObject> NewNeanderObject();
- static Handle<JSObject> NewArgumentsObject(Handle<Object> callee, int length);
+ Handle<JSObject> NewArgumentsObject(Handle<Object> callee, int length);
// JS objects are pretenured when allocated by the bootstrapper and
// runtime.
- static Handle<JSObject> NewJSObject(Handle<JSFunction> constructor,
- PretenureFlag pretenure = NOT_TENURED);
+ Handle<JSObject> NewJSObject(Handle<JSFunction> constructor,
+ PretenureFlag pretenure = NOT_TENURED);
// Global objects are pretenured.
- static Handle<GlobalObject> NewGlobalObject(Handle<JSFunction> constructor);
+ Handle<GlobalObject> NewGlobalObject(Handle<JSFunction> constructor);
// JS objects are pretenured when allocated by the bootstrapper and
// runtime.
- static Handle<JSObject> NewJSObjectFromMap(Handle<Map> map);
+ Handle<JSObject> NewJSObjectFromMap(Handle<Map> map);
// JS arrays are pretenured when allocated by the parser.
- static Handle<JSArray> NewJSArray(int init_length,
- PretenureFlag pretenure = NOT_TENURED);
+ Handle<JSArray> NewJSArray(int capacity,
+ PretenureFlag pretenure = NOT_TENURED);
- static Handle<JSArray> NewJSArrayWithElements(
+ Handle<JSArray> NewJSArrayWithElements(
Handle<FixedArray> elements,
PretenureFlag pretenure = NOT_TENURED);
- static Handle<JSFunction> NewFunction(Handle<String> name,
- Handle<Object> prototype);
+ Handle<JSFunction> NewFunction(Handle<String> name,
+ Handle<Object> prototype);
- static Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String> name);
+ Handle<JSFunction> NewFunctionWithoutPrototype(
+ Handle<String> name,
+ StrictModeFlag strict_mode);
- static Handle<JSFunction> NewFunction(Handle<Object> super, bool is_global);
+ Handle<JSFunction> NewFunction(Handle<Object> super, bool is_global);
- static Handle<JSFunction> BaseNewFunctionFromSharedFunctionInfo(
+ Handle<JSFunction> BaseNewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> function_info,
Handle<Map> function_map,
PretenureFlag pretenure);
- static Handle<JSFunction> NewFunctionFromSharedFunctionInfo(
+ Handle<JSFunction> NewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> function_info,
Handle<Context> context,
PretenureFlag pretenure = TENURED);
- static Handle<Code> NewCode(const CodeDesc& desc,
- Code::Flags flags,
- Handle<Object> self_reference);
+ Handle<Code> NewCode(const CodeDesc& desc,
+ Code::Flags flags,
+ Handle<Object> self_reference,
+ bool immovable = false);
- static Handle<Code> CopyCode(Handle<Code> code);
+ Handle<Code> CopyCode(Handle<Code> code);
- static Handle<Code> CopyCode(Handle<Code> code, Vector<byte> reloc_info);
+ Handle<Code> CopyCode(Handle<Code> code, Vector<byte> reloc_info);
- static Handle<Object> ToObject(Handle<Object> object);
- static Handle<Object> ToObject(Handle<Object> object,
- Handle<Context> global_context);
+ Handle<Object> ToObject(Handle<Object> object);
+ Handle<Object> ToObject(Handle<Object> object,
+ Handle<Context> global_context);
// Interface for creating error objects.
- static Handle<Object> NewError(const char* maker, const char* type,
- Handle<JSArray> args);
- static Handle<Object> NewError(const char* maker, const char* type,
- Vector< Handle<Object> > args);
- static Handle<Object> NewError(const char* type,
- Vector< Handle<Object> > args);
- static Handle<Object> NewError(Handle<String> message);
- static Handle<Object> NewError(const char* constructor,
- Handle<String> message);
+ Handle<Object> NewError(const char* maker, const char* type,
+ Handle<JSArray> args);
+ Handle<Object> NewError(const char* maker, const char* type,
+ Vector< Handle<Object> > args);
+ Handle<Object> NewError(const char* type,
+ Vector< Handle<Object> > args);
+ Handle<Object> NewError(Handle<String> message);
+ Handle<Object> NewError(const char* constructor,
+ Handle<String> message);
- static Handle<Object> NewTypeError(const char* type,
- Vector< Handle<Object> > args);
- static Handle<Object> NewTypeError(Handle<String> message);
+ Handle<Object> NewTypeError(const char* type,
+ Vector< Handle<Object> > args);
+ Handle<Object> NewTypeError(Handle<String> message);
- static Handle<Object> NewRangeError(const char* type,
- Vector< Handle<Object> > args);
- static Handle<Object> NewRangeError(Handle<String> message);
+ Handle<Object> NewRangeError(const char* type,
+ Vector< Handle<Object> > args);
+ Handle<Object> NewRangeError(Handle<String> message);
- static Handle<Object> NewSyntaxError(const char* type, Handle<JSArray> args);
- static Handle<Object> NewSyntaxError(Handle<String> message);
+ Handle<Object> NewSyntaxError(const char* type, Handle<JSArray> args);
+ Handle<Object> NewSyntaxError(Handle<String> message);
- static Handle<Object> NewReferenceError(const char* type,
- Vector< Handle<Object> > args);
- static Handle<Object> NewReferenceError(Handle<String> message);
+ Handle<Object> NewReferenceError(const char* type,
+ Vector< Handle<Object> > args);
+ Handle<Object> NewReferenceError(Handle<String> message);
- static Handle<Object> NewEvalError(const char* type,
- Vector< Handle<Object> > args);
+ Handle<Object> NewEvalError(const char* type,
+ Vector< Handle<Object> > args);
- static Handle<JSFunction> NewFunction(Handle<String> name,
- InstanceType type,
- int instance_size,
- Handle<Code> code,
- bool force_initial_map);
+ Handle<JSFunction> NewFunction(Handle<String> name,
+ InstanceType type,
+ int instance_size,
+ Handle<Code> code,
+ bool force_initial_map);
- static Handle<JSFunction> NewFunction(Handle<Map> function_map,
+ Handle<JSFunction> NewFunction(Handle<Map> function_map,
Handle<SharedFunctionInfo> shared, Handle<Object> prototype);
- static Handle<JSFunction> NewFunctionWithPrototype(Handle<String> name,
- InstanceType type,
- int instance_size,
- Handle<JSObject> prototype,
- Handle<Code> code,
- bool force_initial_map);
+ Handle<JSFunction> NewFunctionWithPrototype(Handle<String> name,
+ InstanceType type,
+ int instance_size,
+ Handle<JSObject> prototype,
+ Handle<Code> code,
+ bool force_initial_map);
- static Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String> name,
- Handle<Code> code);
+ Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String> name,
+ Handle<Code> code);
- static Handle<DescriptorArray> CopyAppendProxyDescriptor(
+ Handle<DescriptorArray> CopyAppendProxyDescriptor(
Handle<DescriptorArray> array,
Handle<String> key,
Handle<Object> value,
PropertyAttributes attributes);
- static Handle<String> NumberToString(Handle<Object> number);
+ Handle<String> NumberToString(Handle<Object> number);
enum ApiInstanceType {
JavaScriptObject,
@@ -327,47 +328,47 @@ class Factory : public AllStatic {
OuterGlobalObject
};
- static Handle<JSFunction> CreateApiFunction(
+ Handle<JSFunction> CreateApiFunction(
Handle<FunctionTemplateInfo> data,
ApiInstanceType type = JavaScriptObject);
- static Handle<JSFunction> InstallMembers(Handle<JSFunction> function);
+ Handle<JSFunction> InstallMembers(Handle<JSFunction> function);
// Installs interceptors on the instance. 'desc' is a function template,
// and instance is an object instance created by the function of this
// function template.
- static void ConfigureInstance(Handle<FunctionTemplateInfo> desc,
- Handle<JSObject> instance,
- bool* pending_exception);
+ void ConfigureInstance(Handle<FunctionTemplateInfo> desc,
+ Handle<JSObject> instance,
+ bool* pending_exception);
#define ROOT_ACCESSOR(type, name, camel_name) \
- static inline Handle<type> name() { \
+ inline Handle<type> name() { \
return Handle<type>(BitCast<type**>( \
- &Heap::roots_[Heap::k##camel_name##RootIndex])); \
+ &isolate()->heap()->roots_[Heap::k##camel_name##RootIndex])); \
}
ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR_ACCESSOR
-#define SYMBOL_ACCESSOR(name, str) \
- static inline Handle<String> name() { \
+#define SYMBOL_ACCESSOR(name, str) \
+ inline Handle<String> name() { \
return Handle<String>(BitCast<String**>( \
- &Heap::roots_[Heap::k##name##RootIndex])); \
+ &isolate()->heap()->roots_[Heap::k##name##RootIndex])); \
}
SYMBOL_LIST(SYMBOL_ACCESSOR)
#undef SYMBOL_ACCESSOR
- static Handle<String> hidden_symbol() {
- return Handle<String>(&Heap::hidden_symbol_);
+ Handle<String> hidden_symbol() {
+ return Handle<String>(&isolate()->heap()->hidden_symbol_);
}
- static Handle<SharedFunctionInfo> NewSharedFunctionInfo(
+ Handle<SharedFunctionInfo> NewSharedFunctionInfo(
Handle<String> name,
int number_of_literals,
Handle<Code> code,
Handle<SerializedScopeInfo> scope_info);
- static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
+ Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
- static Handle<JSMessageObject> NewJSMessageObject(
+ Handle<JSMessageObject> NewJSMessageObject(
Handle<String> type,
Handle<JSArray> arguments,
int start_position,
@@ -376,54 +377,57 @@ class Factory : public AllStatic {
Handle<Object> stack_trace,
Handle<Object> stack_frames);
- static Handle<NumberDictionary> DictionaryAtNumberPut(
+ Handle<NumberDictionary> DictionaryAtNumberPut(
Handle<NumberDictionary>,
uint32_t key,
Handle<Object> value);
#ifdef ENABLE_DEBUGGER_SUPPORT
- static Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
+ Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
#endif
// Return a map using the map cache in the global context.
// The key the an ordered set of property names.
- static Handle<Map> ObjectLiteralMapFromCache(Handle<Context> context,
- Handle<FixedArray> keys);
+ Handle<Map> ObjectLiteralMapFromCache(Handle<Context> context,
+ Handle<FixedArray> keys);
// Creates a new FixedArray that holds the data associated with the
// atom regexp and stores it in the regexp.
- static void SetRegExpAtomData(Handle<JSRegExp> regexp,
- JSRegExp::Type type,
- Handle<String> source,
- JSRegExp::Flags flags,
- Handle<Object> match_pattern);
+ void SetRegExpAtomData(Handle<JSRegExp> regexp,
+ JSRegExp::Type type,
+ Handle<String> source,
+ JSRegExp::Flags flags,
+ Handle<Object> match_pattern);
// Creates a new FixedArray that holds the data associated with the
// irregexp regexp and stores it in the regexp.
- static void SetRegExpIrregexpData(Handle<JSRegExp> regexp,
- JSRegExp::Type type,
- Handle<String> source,
- JSRegExp::Flags flags,
- int capture_count);
+ void SetRegExpIrregexpData(Handle<JSRegExp> regexp,
+ JSRegExp::Type type,
+ Handle<String> source,
+ JSRegExp::Flags flags,
+ int capture_count);
private:
- static Handle<JSFunction> NewFunctionHelper(Handle<String> name,
- Handle<Object> prototype);
+ Isolate* isolate() { return reinterpret_cast<Isolate*>(this); }
+
+ Handle<JSFunction> NewFunctionHelper(Handle<String> name,
+ Handle<Object> prototype);
- static Handle<JSFunction> NewFunctionWithoutPrototypeHelper(
- Handle<String> name);
+ Handle<JSFunction> NewFunctionWithoutPrototypeHelper(
+ Handle<String> name,
+ StrictModeFlag strict_mode);
- static Handle<DescriptorArray> CopyAppendCallbackDescriptors(
+ Handle<DescriptorArray> CopyAppendCallbackDescriptors(
Handle<DescriptorArray> array,
Handle<Object> descriptors);
// Create a new map cache.
- static Handle<MapCache> NewMapCache(int at_least_space_for);
+ Handle<MapCache> NewMapCache(int at_least_space_for);
// Update the map cache in the global context with (keys, map)
- static Handle<MapCache> AddToMapCache(Handle<Context> context,
- Handle<FixedArray> keys,
- Handle<Map> map);
+ Handle<MapCache> AddToMapCache(Handle<Context> context,
+ Handle<FixedArray> keys,
+ Handle<Map> map);
};
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 2566766e..0bc64095 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -97,7 +97,11 @@ private:
#define FLAG FLAG_FULL
// Flags for Crankshaft.
-DEFINE_bool(crankshaft, true, "use crankshaft")
+#ifdef V8_TARGET_ARCH_MIPS
+ DEFINE_bool(crankshaft, false, "use crankshaft")
+#else
+ DEFINE_bool(crankshaft, true, "use crankshaft")
+#endif
DEFINE_string(hydrogen_filter, "", "hydrogen use/trace filter")
DEFINE_bool(use_hydrogen, true, "use generated hydrogen for compilation")
DEFINE_bool(build_lithium, true, "use lithium chunk builder")
@@ -111,7 +115,7 @@ DEFINE_bool(use_inlining, true, "use function inlining")
DEFINE_bool(limit_inlining, true, "limit code size growth from inlining")
DEFINE_bool(eliminate_empty_blocks, true, "eliminate empty blocks")
DEFINE_bool(loop_invariant_code_motion, true, "loop invariant code motion")
-DEFINE_bool(time_hydrogen, false, "timing for hydrogen")
+DEFINE_bool(hydrogen_stats, false, "print statistics for hydrogen")
DEFINE_bool(trace_hydrogen, false, "trace generated hydrogen to file")
DEFINE_bool(trace_inlining, false, "trace inlining decisions")
DEFINE_bool(trace_alloc, false, "trace register allocator")
@@ -161,6 +165,8 @@ DEFINE_bool(enable_vfp3, true,
"enable use of VFP3 instructions if available (ARM only)")
DEFINE_bool(enable_armv7, true,
"enable use of ARMv7 instructions if available (ARM only)")
+DEFINE_bool(enable_fpu, true,
+ "enable use of MIPS FPU instructions if available (MIPS only)")
// bootstrapper.cc
DEFINE_string(expose_natives_as, NULL, "expose natives in global object")
@@ -447,6 +453,8 @@ DEFINE_bool(collect_heap_spill_statistics, false,
"report heap spill statistics along with heap_stats "
"(requires heap_stats)")
+DEFINE_bool(trace_isolates, false, "trace isolate state changes")
+
// VM state
DEFINE_bool(log_state_changes, false, "Log state changes.")
diff --git a/src/frame-element.cc b/src/frame-element.cc
index ee7be95f..f6299007 100644
--- a/src/frame-element.cc
+++ b/src/frame-element.cc
@@ -33,10 +33,5 @@
namespace v8 {
namespace internal {
-FrameElement::ZoneObjectList* FrameElement::ConstantList() {
- static ZoneObjectList list(10);
- return &list;
-}
-
} } // namespace v8::internal
diff --git a/src/frame-element.h b/src/frame-element.h
index ae5d6a1b..0c7d0103 100644
--- a/src/frame-element.h
+++ b/src/frame-element.h
@@ -106,20 +106,9 @@ class FrameElement BASE_EMBEDDED {
return result;
}
- // Static indirection table for handles to constants. If a frame
- // element represents a constant, the data contains an index into
- // this table of handles to the actual constants.
- typedef ZoneList<Handle<Object> > ZoneObjectList;
-
- static ZoneObjectList* ConstantList();
-
static bool ConstantPoolOverflowed() {
- return !DataField::is_valid(ConstantList()->length());
- }
-
- // Clear the constants indirection table.
- static void ClearConstantList() {
- ConstantList()->Clear();
+ return !DataField::is_valid(
+ Isolate::Current()->frame_element_constant_list()->length());
}
bool is_synced() const { return SyncedField::decode(value_); }
@@ -164,7 +153,8 @@ class FrameElement BASE_EMBEDDED {
Handle<Object> handle() const {
ASSERT(is_constant());
- return ConstantList()->at(DataField::decode(value_));
+ return Isolate::Current()->frame_element_constant_list()->
+ at(DataField::decode(value_));
}
int index() const {
@@ -232,12 +222,14 @@ class FrameElement BASE_EMBEDDED {
// Used to construct constant elements.
FrameElement(Handle<Object> value, SyncFlag is_synced, TypeInfo info) {
+ ZoneObjectList* constant_list =
+ Isolate::Current()->frame_element_constant_list();
value_ = TypeField::encode(CONSTANT)
| CopiedField::encode(false)
| SyncedField::encode(is_synced != NOT_SYNCED)
| TypeInfoField::encode(info.ToInt())
- | DataField::encode(ConstantList()->length());
- ConstantList()->Add(value);
+ | DataField::encode(constant_list->length());
+ constant_list->Add(value);
}
Type type() const { return TypeField::decode(value_); }
diff --git a/src/frames-inl.h b/src/frames-inl.h
index 78bb646c..e6eaec0e 100644
--- a/src/frames-inl.h
+++ b/src/frames-inl.h
@@ -29,6 +29,8 @@
#define V8_FRAMES_INL_H_
#include "frames.h"
+#include "isolate.h"
+#include "v8memory.h"
#if V8_TARGET_ARCH_IA32
#include "ia32/frames-ia32.h"
@@ -91,6 +93,11 @@ inline StackHandler* StackFrame::top_handler() const {
}
+inline Code* StackFrame::GetContainingCode(Isolate* isolate, Address pc) {
+ return isolate->pc_to_code_cache()->GetCacheEntry(pc)->code;
+}
+
+
inline Object* StandardFrame::GetExpression(int index) const {
return Memory::Object_at(GetExpressionAddress(index));
}
diff --git a/src/frames.cc b/src/frames.cc
index 24ea8dde..79aa2507 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -35,13 +35,10 @@
#include "safepoint-table.h"
#include "scopeinfo.h"
#include "string-stream.h"
-#include "top.h"
namespace v8 {
namespace internal {
-PcToCodeCache::PcToCodeCacheEntry
- PcToCodeCache::cache_[PcToCodeCache::kPcToCodeCacheSize];
int SafeStackFrameIterator::active_count_ = 0;
@@ -77,7 +74,8 @@ class StackHandlerIterator BASE_EMBEDDED {
#define INITIALIZE_SINGLETON(type, field) field##_(this),
StackFrameIterator::StackFrameIterator()
: STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
- frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()),
+ frame_(NULL), handler_(NULL),
+ thread_(Isolate::Current()->thread_local_top()),
fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
Reset();
}
@@ -87,10 +85,11 @@ StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
Reset();
}
-StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp)
+StackFrameIterator::StackFrameIterator(Isolate* isolate,
+ bool use_top, Address fp, Address sp)
: STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
frame_(NULL), handler_(NULL),
- thread_(use_top ? Top::GetCurrentThread() : NULL),
+ thread_(use_top ? isolate->thread_local_top() : NULL),
fp_(use_top ? NULL : fp), sp_(sp),
advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
&StackFrameIterator::AdvanceWithoutHandler) {
@@ -138,8 +137,10 @@ void StackFrameIterator::Reset() {
StackFrame::State state;
StackFrame::Type type;
if (thread_ != NULL) {
- type = ExitFrame::GetStateForFramePointer(Top::c_entry_fp(thread_), &state);
- handler_ = StackHandler::FromAddress(Top::handler(thread_));
+ type = ExitFrame::GetStateForFramePointer(
+ Isolate::c_entry_fp(thread_), &state);
+ handler_ = StackHandler::FromAddress(
+ Isolate::handler(thread_));
} else {
ASSERT(fp_ != NULL);
state.fp = fp_;
@@ -221,22 +222,25 @@ bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) {
SafeStackFrameIterator::SafeStackFrameIterator(
+ Isolate* isolate,
Address fp, Address sp, Address low_bound, Address high_bound) :
maintainer_(),
stack_validator_(low_bound, high_bound),
- is_valid_top_(IsValidTop(low_bound, high_bound)),
+ is_valid_top_(IsValidTop(isolate, low_bound, high_bound)),
is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
is_working_iterator_(is_valid_top_ || is_valid_fp_),
iteration_done_(!is_working_iterator_),
- iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
+ iterator_(isolate, is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
}
-bool SafeStackFrameIterator::IsValidTop(Address low_bound, Address high_bound) {
- Address fp = Top::c_entry_fp(Top::GetCurrentThread());
+bool SafeStackFrameIterator::IsValidTop(Isolate* isolate,
+ Address low_bound, Address high_bound) {
+ ThreadLocalTop* top = isolate->thread_local_top();
+ Address fp = Isolate::c_entry_fp(top);
ExitFrameValidator validator(low_bound, high_bound);
if (!validator.IsValidFP(fp)) return false;
- return Top::handler(Top::GetCurrentThread()) != NULL;
+ return Isolate::handler(top) != NULL;
}
@@ -312,8 +316,9 @@ void SafeStackFrameIterator::Reset() {
#ifdef ENABLE_LOGGING_AND_PROFILING
SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
+ Isolate* isolate,
Address fp, Address sp, Address low_bound, Address high_bound) :
- SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) {
+ SafeJavaScriptFrameIterator(isolate, fp, sp, low_bound, high_bound) {
if (!done() && !frame()->is_java_script()) Advance();
}
@@ -331,7 +336,9 @@ void SafeStackTraceFrameIterator::Advance() {
Code* StackFrame::GetSafepointData(Address pc,
SafepointEntry* safepoint_entry,
unsigned* stack_slots) {
- PcToCodeCache::PcToCodeCacheEntry* entry = PcToCodeCache::GetCacheEntry(pc);
+ Isolate* isolate = Isolate::Current();
+ PcToCodeCache::PcToCodeCacheEntry* entry =
+ isolate->pc_to_code_cache()->GetCacheEntry(pc);
SafepointEntry cached_safepoint_entry = entry->safepoint_entry;
if (!entry->safepoint_entry.is_valid()) {
entry->safepoint_entry = entry->code->GetSafepointEntry(pc);
@@ -386,7 +393,8 @@ StackFrame::Type StackFrame::ComputeType(State* state) {
// into the heap to determine the state. This is safe as long
// as nobody tries to GC...
if (SafeStackFrameIterator::is_active()) return JAVA_SCRIPT;
- Code::Kind kind = GetContainingCode(*(state->pc_address))->kind();
+ Code::Kind kind = GetContainingCode(Isolate::Current(),
+ *(state->pc_address))->kind();
ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT;
}
@@ -402,7 +410,7 @@ StackFrame::Type StackFrame::GetCallerState(State* state) const {
Code* EntryFrame::unchecked_code() const {
- return Heap::raw_unchecked_js_entry_code();
+ return HEAP->raw_unchecked_js_entry_code();
}
@@ -425,7 +433,7 @@ StackFrame::Type EntryFrame::GetCallerState(State* state) const {
Code* EntryConstructFrame::unchecked_code() const {
- return Heap::raw_unchecked_js_construct_entry_code();
+ return HEAP->raw_unchecked_js_construct_entry_code();
}
@@ -457,7 +465,7 @@ void ExitFrame::SetCallerFp(Address caller_fp) {
void ExitFrame::Iterate(ObjectVisitor* v) const {
// The arguments are traversed as part of the expression stack of
// the calling frame.
- IteratePc(v, pc_address(), code());
+ IteratePc(v, pc_address(), LookupCode(Isolate::Current()));
v->VisitPointer(&code_slot());
}
@@ -630,15 +638,10 @@ Code* JavaScriptFrame::unchecked_code() const {
}
-int JavaScriptFrame::GetProvidedParametersCount() const {
- return ComputeParametersCount();
-}
-
-
Address JavaScriptFrame::GetCallerStackPointer() const {
int arguments;
- if (Heap::gc_state() != Heap::NOT_IN_GC ||
- SafeStackFrameIterator::is_active()) {
+ if (SafeStackFrameIterator::is_active() ||
+ HEAP->gc_state() != Heap::NOT_IN_GC) {
// If the we are currently iterating the safe stack the
// arguments for frames are traversed as if they were
// expression stack elements of the calling frame. The reason for
@@ -667,7 +670,7 @@ void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
ASSERT(functions->length() == 0);
- Code* code_pointer = code();
+ Code* code_pointer = LookupCode(Isolate::Current());
int offset = static_cast<int>(pc() - code_pointer->address());
FrameSummary summary(receiver(),
JSFunction::cast(function()),
@@ -786,7 +789,7 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
// back to a slow search in this case to find the original optimized
// code object.
if (!code->contains(pc())) {
- code = PcToCodeCache::GcSafeFindCodeForPc(pc());
+ code = Isolate::Current()->pc_to_code_cache()->GcSafeFindCodeForPc(pc());
}
ASSERT(code != NULL);
ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
@@ -847,7 +850,8 @@ Address InternalFrame::GetCallerStackPointer() const {
Code* ArgumentsAdaptorFrame::unchecked_code() const {
- return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
+ return Isolate::Current()->builtins()->builtin(
+ Builtins::kArgumentsAdaptorTrampoline);
}
@@ -1041,14 +1045,14 @@ void EntryFrame::Iterate(ObjectVisitor* v) const {
ASSERT(!it.done());
StackHandler* handler = it.handler();
ASSERT(handler->is_entry());
- handler->Iterate(v, code());
+ handler->Iterate(v, LookupCode(Isolate::Current()));
#ifdef DEBUG
// Make sure that the entry frame does not contain more than one
// stack handler.
it.Advance();
ASSERT(it.done());
#endif
- IteratePc(v, pc_address(), code());
+ IteratePc(v, pc_address(), LookupCode(Isolate::Current()));
}
@@ -1065,7 +1069,7 @@ void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
v->VisitPointers(base, reinterpret_cast<Object**>(address));
base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
// Traverse the pointers in the handler itself.
- handler->Iterate(v, code());
+ handler->Iterate(v, LookupCode(Isolate::Current()));
}
v->VisitPointers(base, limit);
}
@@ -1073,7 +1077,7 @@ void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
IterateExpressions(v);
- IteratePc(v, pc_address(), code());
+ IteratePc(v, pc_address(), LookupCode(Isolate::Current()));
IterateArguments(v);
}
@@ -1092,7 +1096,7 @@ void InternalFrame::Iterate(ObjectVisitor* v) const {
// Internal frames only have object pointers on the expression stack
// as they never have any arguments.
IterateExpressions(v);
- IteratePc(v, pc_address(), code());
+ IteratePc(v, pc_address(), LookupCode(Isolate::Current()));
}
@@ -1122,14 +1126,15 @@ Code* PcToCodeCache::GcSafeCastToCode(HeapObject* object, Address pc) {
Code* PcToCodeCache::GcSafeFindCodeForPc(Address pc) {
+ Heap* heap = isolate_->heap();
// Check if the pc points into a large object chunk.
- LargeObjectChunk* chunk = Heap::lo_space()->FindChunkContainingPc(pc);
+ LargeObjectChunk* chunk = heap->lo_space()->FindChunkContainingPc(pc);
if (chunk != NULL) return GcSafeCastToCode(chunk->GetObject(), pc);
// Iterate through the 8K page until we reach the end or find an
// object starting after the pc.
Page* page = Page::FromAddress(pc);
- HeapObjectIterator iterator(page, Heap::GcSafeSizeOfOldObjectFunction());
+ HeapObjectIterator iterator(page, heap->GcSafeSizeOfOldObjectFunction());
HeapObject* previous = NULL;
while (true) {
HeapObject* next = iterator.next();
@@ -1142,14 +1147,14 @@ Code* PcToCodeCache::GcSafeFindCodeForPc(Address pc) {
PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) {
- Counters::pc_to_code.Increment();
+ isolate_->counters()->pc_to_code()->Increment();
ASSERT(IsPowerOf2(kPcToCodeCacheSize));
uint32_t hash = ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)));
uint32_t index = hash & (kPcToCodeCacheSize - 1);
PcToCodeCacheEntry* entry = cache(index);
if (entry->pc == pc) {
- Counters::pc_to_code_cached.Increment();
+ isolate_->counters()->pc_to_code_cached()->Increment();
ASSERT(entry->code == GcSafeFindCodeForPc(pc));
} else {
// Because this code may be interrupted by a profiling signal that
@@ -1176,11 +1181,8 @@ int NumRegs(RegList reglist) {
}
-int JSCallerSavedCode(int n) {
- static int reg_code[kNumJSCallerSaved];
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
+struct JSCallerSavedCodeData {
+ JSCallerSavedCodeData() {
int i = 0;
for (int r = 0; r < kNumRegs; r++)
if ((kJSCallerSaved & (1 << r)) != 0)
@@ -1188,8 +1190,16 @@ int JSCallerSavedCode(int n) {
ASSERT(i == kNumJSCallerSaved);
}
+ int reg_code[kNumJSCallerSaved];
+};
+
+
+static const JSCallerSavedCodeData kCallerSavedCodeData;
+
+
+int JSCallerSavedCode(int n) {
ASSERT(0 <= n && n < kNumJSCallerSaved);
- return reg_code[n];
+ return kCallerSavedCodeData.reg_code[n];
}
diff --git a/src/frames.h b/src/frames.h
index 53787090..bee95ccb 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -28,6 +28,7 @@
#ifndef V8_FRAMES_H_
#define V8_FRAMES_H_
+#include "handles.h"
#include "safepoint-table.h"
namespace v8 {
@@ -44,11 +45,10 @@ int JSCallerSavedCode(int n);
// Forward declarations.
class StackFrameIterator;
-class Top;
class ThreadLocalTop;
+class Isolate;
-
-class PcToCodeCache : AllStatic {
+class PcToCodeCache {
public:
struct PcToCodeCacheEntry {
Address pc;
@@ -56,22 +56,28 @@ class PcToCodeCache : AllStatic {
SafepointEntry safepoint_entry;
};
- static PcToCodeCacheEntry* cache(int index) {
- return &cache_[index];
+ explicit PcToCodeCache(Isolate* isolate) : isolate_(isolate) {
+ Flush();
}
- static Code* GcSafeFindCodeForPc(Address pc);
- static Code* GcSafeCastToCode(HeapObject* object, Address pc);
+ Code* GcSafeFindCodeForPc(Address pc);
+ Code* GcSafeCastToCode(HeapObject* object, Address pc);
- static void FlushPcToCodeCache() {
+ void Flush() {
memset(&cache_[0], 0, sizeof(cache_));
}
- static PcToCodeCacheEntry* GetCacheEntry(Address pc);
+ PcToCodeCacheEntry* GetCacheEntry(Address pc);
private:
+ PcToCodeCacheEntry* cache(int index) { return &cache_[index]; }
+
+ Isolate* isolate_;
+
static const int kPcToCodeCacheSize = 1024;
- static PcToCodeCacheEntry cache_[kPcToCodeCacheSize];
+ PcToCodeCacheEntry cache_[kPcToCodeCacheSize];
+
+ DISALLOW_COPY_AND_ASSIGN(PcToCodeCache);
};
@@ -199,12 +205,12 @@ class StackFrame BASE_EMBEDDED {
virtual Code* unchecked_code() const = 0;
// Get the code associated with this frame.
- Code* code() const { return GetContainingCode(pc()); }
+ Code* LookupCode(Isolate* isolate) const {
+ return GetContainingCode(isolate, pc());
+ }
// Get the code object that contains the given pc.
- static Code* GetContainingCode(Address pc) {
- return PcToCodeCache::GetCacheEntry(pc)->code;
- }
+ static inline Code* GetContainingCode(Isolate* isolate, Address pc);
// Get the code object containing the given pc and fill in the
// safepoint entry and the number of stack slots. The pc must be at
@@ -452,12 +458,6 @@ class JavaScriptFrame: public StandardFrame {
Object* GetParameter(int index) const;
int ComputeParametersCount() const;
- // Temporary way of getting access to the number of parameters
- // passed on the stack by the caller. Once argument adaptor frames
- // has been introduced on ARM, this number will always match the
- // computed parameters count.
- int GetProvidedParametersCount() const;
-
// Check if this frame is a constructor frame invoked through 'new'.
bool IsConstructor() const;
@@ -618,7 +618,7 @@ class StackFrameIterator BASE_EMBEDDED {
// An iterator that can start from a given FP address.
// If use_top, then work as usual, if fp isn't NULL, use it,
// otherwise, do nothing.
- StackFrameIterator(bool use_top, Address fp, Address sp);
+ StackFrameIterator(Isolate* isolate, bool use_top, Address fp, Address sp);
StackFrame* frame() const {
ASSERT(!done());
@@ -681,6 +681,13 @@ class JavaScriptFrameIteratorTemp BASE_EMBEDDED {
if (!done()) Advance();
}
+ JavaScriptFrameIteratorTemp(Isolate* isolate,
+ Address fp, Address sp,
+ Address low_bound, Address high_bound) :
+ iterator_(isolate, fp, sp, low_bound, high_bound) {
+ if (!done()) Advance();
+ }
+
inline JavaScriptFrame* frame() const;
bool done() const { return iterator_.done(); }
@@ -718,7 +725,8 @@ class StackTraceFrameIterator: public JavaScriptFrameIterator {
class SafeStackFrameIterator BASE_EMBEDDED {
public:
- SafeStackFrameIterator(Address fp, Address sp,
+ SafeStackFrameIterator(Isolate* isolate,
+ Address fp, Address sp,
Address low_bound, Address high_bound);
StackFrame* frame() const {
@@ -768,7 +776,8 @@ class SafeStackFrameIterator BASE_EMBEDDED {
bool CanIterateHandles(StackFrame* frame, StackHandler* handler);
bool IsValidFrame(StackFrame* frame) const;
bool IsValidCaller(StackFrame* frame);
- static bool IsValidTop(Address low_bound, Address high_bound);
+ static bool IsValidTop(Isolate* isolate,
+ Address low_bound, Address high_bound);
// This is a nasty hack to make sure the active count is incremented
// before the constructor for the embedded iterator is invoked. This
@@ -782,6 +791,7 @@ class SafeStackFrameIterator BASE_EMBEDDED {
};
ActiveCountMaintainer maintainer_;
+ // TODO(isolates): this is dangerous.
static int active_count_;
StackAddressValidator stack_validator_;
const bool is_valid_top_;
@@ -799,7 +809,8 @@ typedef JavaScriptFrameIteratorTemp<SafeStackFrameIterator>
class SafeStackTraceFrameIterator: public SafeJavaScriptFrameIterator {
public:
- explicit SafeStackTraceFrameIterator(Address fp, Address sp,
+ explicit SafeStackTraceFrameIterator(Isolate* isolate,
+ Address fp, Address sp,
Address low_bound, Address high_bound);
void Advance();
};
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index b3dc95bd..d509cd5b 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -275,10 +275,11 @@ void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
#define __ ACCESS_MASM(masm())
bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
+ Isolate* isolate = info->isolate();
Handle<Script> script = info->script();
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
int len = String::cast(script->source())->length();
- Counters::total_full_codegen_source_size.Increment(len);
+ isolate->counters()->total_full_codegen_source_size()->Increment(len);
}
if (FLAG_trace_codegen) {
PrintF("Full Compiler - ");
@@ -293,7 +294,7 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
FullCodeGenerator cgen(&masm);
cgen.Generate(info);
if (cgen.HasStackOverflow()) {
- ASSERT(!Top::has_pending_exception());
+ ASSERT(!isolate->has_pending_exception());
return false;
}
unsigned table_offset = cgen.EmitStackCheckTable();
@@ -343,7 +344,8 @@ void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) {
if (!info_->HasDeoptimizationSupport()) return;
int length = bailout_entries_.length();
Handle<DeoptimizationOutputData> data =
- Factory::NewDeoptimizationOutputData(length, TENURED);
+ isolate()->factory()->
+ NewDeoptimizationOutputData(length, TENURED);
for (int i = 0; i < length; i++) {
data->SetAstId(i, Smi::FromInt(bailout_entries_[i].id));
data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state));
@@ -545,7 +547,8 @@ void FullCodeGenerator::VisitDeclarations(
// Compute array of global variable and function declarations.
// Do nothing in case of no declared global functions or variables.
if (globals > 0) {
- Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
+ Handle<FixedArray> array =
+ isolate()->factory()->NewFixedArray(2 * globals, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var();
@@ -596,7 +599,7 @@ void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
if (FLAG_debug_info) {
#ifdef ENABLE_DEBUGGER_SUPPORT
- if (!Debugger::IsDebuggerActive()) {
+ if (!isolate()->debugger()->IsDebuggerActive()) {
CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
} else {
// Check if the statement will be breakable without adding a debug break
@@ -624,7 +627,7 @@ void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
if (FLAG_debug_info) {
#ifdef ENABLE_DEBUGGER_SUPPORT
- if (!Debugger::IsDebuggerActive()) {
+ if (!isolate()->debugger()->IsDebuggerActive()) {
CodeGenerator::RecordPositions(masm_, pos);
} else {
// Check if the expression will be breakable without adding a debug break
@@ -694,7 +697,7 @@ FullCodeGenerator::InlineFunctionGenerator
void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments();
Handle<String> name = node->name();
- Runtime::Function* function = node->function();
+ const Runtime::Function* function = node->function();
ASSERT(function != NULL);
ASSERT(function->intrinsic_type == Runtime::INLINE);
InlineFunctionGenerator generator =
diff --git a/src/full-codegen.h b/src/full-codegen.h
index 5fb11b43..d6ed1b9f 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -501,9 +501,9 @@ class FullCodeGenerator: public AstVisitor {
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
- bool is_strict() { return function()->strict_mode(); }
+ bool is_strict_mode() { return function()->strict_mode(); }
StrictModeFlag strict_mode_flag() {
- return is_strict() ? kStrictMode : kNonStrictMode;
+ return is_strict_mode() ? kStrictMode : kNonStrictMode;
}
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return info_->scope(); }
@@ -553,6 +553,8 @@ class FullCodeGenerator: public AstVisitor {
codegen_->set_new_context(old_);
}
+ Isolate* isolate() const { return codegen_->isolate(); }
+
// Convert constant control flow (true or false) to the result expected for
// this expression context.
virtual void Plug(bool flag) const = 0;
diff --git a/src/func-name-inferrer.cc b/src/func-name-inferrer.cc
index f12d026b..c094251f 100644
--- a/src/func-name-inferrer.cc
+++ b/src/func-name-inferrer.cc
@@ -38,21 +38,22 @@ void FuncNameInferrer::PushEnclosingName(Handle<String> name) {
// Enclosing name is a name of a constructor function. To check
// that it is really a constructor, we check that it is not empty
// and starts with a capital letter.
- if (name->length() > 0 && Runtime::IsUpperCaseChar(name->Get(0))) {
+ if (name->length() > 0 && Runtime::IsUpperCaseChar(
+ Isolate::Current()->runtime_state(), name->Get(0))) {
names_stack_.Add(name);
}
}
void FuncNameInferrer::PushLiteralName(Handle<String> name) {
- if (IsOpen() && !Heap::prototype_symbol()->Equals(*name)) {
+ if (IsOpen() && !HEAP->prototype_symbol()->Equals(*name)) {
names_stack_.Add(name);
}
}
void FuncNameInferrer::PushVariableName(Handle<String> name) {
- if (IsOpen() && !Heap::result_symbol()->Equals(*name)) {
+ if (IsOpen() && !HEAP->result_symbol()->Equals(*name)) {
names_stack_.Add(name);
}
}
@@ -60,7 +61,7 @@ void FuncNameInferrer::PushVariableName(Handle<String> name) {
Handle<String> FuncNameInferrer::MakeNameFromStack() {
if (names_stack_.is_empty()) {
- return Factory::empty_string();
+ return FACTORY->empty_string();
} else {
return MakeNameFromStackHelper(1, names_stack_.at(0));
}
@@ -72,8 +73,8 @@ Handle<String> FuncNameInferrer::MakeNameFromStackHelper(int pos,
if (pos >= names_stack_.length()) {
return prev;
} else {
- Handle<String> curr = Factory::NewConsString(dot_, names_stack_.at(pos));
- return MakeNameFromStackHelper(pos + 1, Factory::NewConsString(prev, curr));
+ Handle<String> curr = FACTORY->NewConsString(dot_, names_stack_.at(pos));
+ return MakeNameFromStackHelper(pos + 1, FACTORY->NewConsString(prev, curr));
}
}
diff --git a/src/func-name-inferrer.h b/src/func-name-inferrer.h
index a35034ec..5aa2b35b 100644
--- a/src/func-name-inferrer.h
+++ b/src/func-name-inferrer.h
@@ -47,7 +47,7 @@ class FuncNameInferrer : public ZoneObject {
: entries_stack_(10),
names_stack_(5),
funcs_to_infer_(4),
- dot_(Factory::NewStringFromAscii(CStrVector("."))) {
+ dot_(FACTORY->NewStringFromAscii(CStrVector("."))) {
}
// Returns whether we have entered name collection state.
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index 5136dedd..c8dbf5d6 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -26,6 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef ENABLE_GDB_JIT_INTERFACE
+#include "v8.h"
#include "gdb-jit.h"
#include "bootstrapper.h"
diff --git a/src/global-handles.cc b/src/global-handles.cc
index 18cdc5a3..4d138597 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -35,12 +35,19 @@
namespace v8 {
namespace internal {
+
+ObjectGroup::~ObjectGroup() {
+ if (info_ != NULL) info_->Dispose();
+}
+
+
class GlobalHandles::Node : public Malloced {
public:
void Initialize(Object* object) {
// Set the initial value of the handle.
object_ = object;
+ class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
state_ = NORMAL;
parameter_or_next_free_.parameter = NULL;
callback_ = NULL;
@@ -57,7 +64,7 @@ class GlobalHandles::Node : public Malloced {
}
~Node() {
- if (state_ != DESTROYED) Destroy();
+ if (state_ != DESTROYED) Destroy(Isolate::Current()->global_handles());
#ifdef DEBUG
// Zap the values for eager trapping.
object_ = NULL;
@@ -66,11 +73,11 @@ class GlobalHandles::Node : public Malloced {
#endif
}
- void Destroy() {
+ void Destroy(GlobalHandles* global_handles) {
if (state_ == WEAK || IsNearDeath()) {
- GlobalHandles::number_of_weak_handles_--;
+ global_handles->number_of_weak_handles_--;
if (object_->IsJSGlobalObject()) {
- GlobalHandles::number_of_global_object_weak_handles_--;
+ global_handles->number_of_global_object_weak_handles_--;
}
}
state_ = DESTROYED;
@@ -101,13 +108,15 @@ class GlobalHandles::Node : public Malloced {
Handle<Object> handle() { return Handle<Object>(&object_); }
// Make this handle weak.
- void MakeWeak(void* parameter, WeakReferenceCallback callback) {
- LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
+ void MakeWeak(GlobalHandles* global_handles, void* parameter,
+ WeakReferenceCallback callback) {
+ LOG(global_handles->isolate(),
+ HandleEvent("GlobalHandle::MakeWeak", handle().location()));
ASSERT(state_ != DESTROYED);
if (state_ != WEAK && !IsNearDeath()) {
- GlobalHandles::number_of_weak_handles_++;
+ global_handles->number_of_weak_handles_++;
if (object_->IsJSGlobalObject()) {
- GlobalHandles::number_of_global_object_weak_handles_++;
+ global_handles->number_of_global_object_weak_handles_++;
}
}
state_ = WEAK;
@@ -115,13 +124,14 @@ class GlobalHandles::Node : public Malloced {
callback_ = callback;
}
- void ClearWeakness() {
- LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
+ void ClearWeakness(GlobalHandles* global_handles) {
+ LOG(global_handles->isolate(),
+ HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
ASSERT(state_ != DESTROYED);
if (state_ == WEAK || IsNearDeath()) {
- GlobalHandles::number_of_weak_handles_--;
+ global_handles->number_of_weak_handles_--;
if (object_->IsJSGlobalObject()) {
- GlobalHandles::number_of_global_object_weak_handles_--;
+ global_handles->number_of_global_object_weak_handles_--;
}
}
state_ = NORMAL;
@@ -137,6 +147,14 @@ class GlobalHandles::Node : public Malloced {
return state_ == WEAK;
}
+ bool CanBeRetainer() {
+ return state_ != DESTROYED && state_ != NEAR_DEATH;
+ }
+
+ void SetWrapperClassId(uint16_t class_id) {
+ class_id_ = class_id;
+ }
+
// Returns the id for this weak handle.
void set_parameter(void* parameter) {
ASSERT(state_ != DESTROYED);
@@ -150,12 +168,13 @@ class GlobalHandles::Node : public Malloced {
// Returns the callback for this weak handle.
WeakReferenceCallback callback() { return callback_; }
- bool PostGarbageCollectionProcessing() {
+ bool PostGarbageCollectionProcessing(Isolate* isolate,
+ GlobalHandles* global_handles) {
if (state_ != Node::PENDING) return false;
- LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
+ LOG(isolate, HandleEvent("GlobalHandle::Processing", handle().location()));
WeakReferenceCallback func = callback();
if (func == NULL) {
- Destroy();
+ Destroy(global_handles);
return false;
}
void* par = parameter();
@@ -167,9 +186,9 @@ class GlobalHandles::Node : public Malloced {
// Forbid reuse of destroyed nodes as they might be already deallocated.
// It's fine though to reuse nodes that were destroyed in weak callback
// as those cannot be deallocated until we are back from the callback.
- set_first_free(NULL);
- if (first_deallocated()) {
- first_deallocated()->set_next(head());
+ global_handles->set_first_free(NULL);
+ if (global_handles->first_deallocated()) {
+ global_handles->first_deallocated()->set_next(global_handles->head());
}
// Check that we are not passing a finalized external string to
// the callback.
@@ -178,7 +197,7 @@ class GlobalHandles::Node : public Malloced {
ASSERT(!object_->IsExternalTwoByteString() ||
ExternalTwoByteString::cast(object_)->resource() != NULL);
// Leaving V8.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
func(object, par);
}
// Absense of explicit cleanup or revival of weak handle
@@ -190,6 +209,8 @@ class GlobalHandles::Node : public Malloced {
// Place the handle address first to avoid offset computation.
Object* object_; // Storage for object pointer.
+ uint16_t class_id_;
+
// Transition diagram:
// NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
enum State {
@@ -199,7 +220,7 @@ class GlobalHandles::Node : public Malloced {
NEAR_DEATH, // Callback has informed the handle is near death.
DESTROYED
};
- State state_;
+ State state_ : 4; // Need one more bit for MSVC as it treats enums as signed.
private:
// Handle specific callback.
@@ -219,7 +240,7 @@ class GlobalHandles::Node : public Malloced {
};
-class GlobalHandles::Pool BASE_EMBEDDED {
+class GlobalHandles::Pool {
public:
Pool() {
current_ = new Chunk();
@@ -277,11 +298,27 @@ class GlobalHandles::Pool BASE_EMBEDDED {
};
-static GlobalHandles::Pool pool_;
+GlobalHandles::GlobalHandles(Isolate* isolate)
+ : isolate_(isolate),
+ number_of_weak_handles_(0),
+ number_of_global_object_weak_handles_(0),
+ head_(NULL),
+ first_free_(NULL),
+ first_deallocated_(NULL),
+ pool_(new Pool()),
+ post_gc_processing_count_(0),
+ object_groups_(4) {
+}
+
+
+GlobalHandles::~GlobalHandles() {
+ delete pool_;
+ pool_ = 0;
+}
Handle<Object> GlobalHandles::Create(Object* value) {
- Counters::global_handles.Increment();
+ isolate_->counters()->global_handles()->Increment();
Node* result;
if (first_free()) {
// Take the first node in the free list.
@@ -295,7 +332,7 @@ Handle<Object> GlobalHandles::Create(Object* value) {
set_head(result);
} else {
// Allocate a new node.
- result = pool_.Allocate();
+ result = pool_->Allocate();
result->set_next(head());
set_head(result);
}
@@ -305,10 +342,10 @@ Handle<Object> GlobalHandles::Create(Object* value) {
void GlobalHandles::Destroy(Object** location) {
- Counters::global_handles.Decrement();
+ isolate_->counters()->global_handles()->Decrement();
if (location == NULL) return;
Node* node = Node::FromLocation(location);
- node->Destroy();
+ node->Destroy(this);
// Link the destroyed.
node->set_next_free(first_free());
set_first_free(node);
@@ -318,12 +355,12 @@ void GlobalHandles::Destroy(Object** location) {
void GlobalHandles::MakeWeak(Object** location, void* parameter,
WeakReferenceCallback callback) {
ASSERT(callback != NULL);
- Node::FromLocation(location)->MakeWeak(parameter, callback);
+ Node::FromLocation(location)->MakeWeak(this, parameter, callback);
}
void GlobalHandles::ClearWeakness(Object** location) {
- Node::FromLocation(location)->ClearWeakness();
+ Node::FromLocation(location)->ClearWeakness(this);
}
@@ -337,6 +374,11 @@ bool GlobalHandles::IsWeak(Object** location) {
}
+void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) {
+ Node::FromLocation(location)->SetWrapperClassId(class_id);
+}
+
+
void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
// Traversal of GC roots in the global handle list that are marked as
// WEAK or PENDING.
@@ -365,27 +407,26 @@ void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
if (current->state_ == Node::WEAK) {
if (f(&current->object_)) {
current->state_ = Node::PENDING;
- LOG(HandleEvent("GlobalHandle::Pending", current->handle().location()));
+ LOG(isolate_,
+ HandleEvent("GlobalHandle::Pending", current->handle().location()));
}
}
}
}
-int post_gc_processing_count = 0;
-
bool GlobalHandles::PostGarbageCollectionProcessing() {
// Process weak global handle callbacks. This must be done after the
// GC is completely done, because the callbacks may invoke arbitrary
// API functions.
// At the same time deallocate all DESTROYED nodes.
- ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
- const int initial_post_gc_processing_count = ++post_gc_processing_count;
+ ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
+ const int initial_post_gc_processing_count = ++post_gc_processing_count_;
bool next_gc_likely_to_collect_more = false;
Node** p = &head_;
while (*p != NULL) {
- if ((*p)->PostGarbageCollectionProcessing()) {
- if (initial_post_gc_processing_count != post_gc_processing_count) {
+ if ((*p)->PostGarbageCollectionProcessing(isolate_, this)) {
+ if (initial_post_gc_processing_count != post_gc_processing_count_) {
// Weak callback triggered another GC and another round of
// PostGarbageCollection processing. The current node might
// have been deleted in that round, so we need to bail out (or
@@ -435,22 +476,25 @@ void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
}
+void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
+ for (Node* current = head_; current != NULL; current = current->next()) {
+ if (current->class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId &&
+ current->CanBeRetainer()) {
+ v->VisitEmbedderReference(&current->object_, current->class_id_);
+ }
+ }
+}
+
+
void GlobalHandles::TearDown() {
// Reset all the lists.
set_head(NULL);
set_first_free(NULL);
set_first_deallocated(NULL);
- pool_.Release();
+ pool_->Release();
}
-int GlobalHandles::number_of_weak_handles_ = 0;
-int GlobalHandles::number_of_global_object_weak_handles_ = 0;
-
-GlobalHandles::Node* GlobalHandles::head_ = NULL;
-GlobalHandles::Node* GlobalHandles::first_free_ = NULL;
-GlobalHandles::Node* GlobalHandles::first_deallocated_ = NULL;
-
void GlobalHandles::RecordStats(HeapStats* stats) {
*stats->global_handle_count = 0;
*stats->weak_global_handle_count = 0;
@@ -509,26 +553,44 @@ void GlobalHandles::Print() {
#endif
-List<ObjectGroup*>* GlobalHandles::ObjectGroups() {
- // Lazily initialize the list to avoid startup time static constructors.
- static List<ObjectGroup*> groups(4);
- return &groups;
-}
-void GlobalHandles::AddGroup(Object*** handles, size_t length) {
- ObjectGroup* new_entry = new ObjectGroup(length);
- for (size_t i = 0; i < length; ++i)
+
+void GlobalHandles::AddObjectGroup(Object*** handles,
+ size_t length,
+ v8::RetainedObjectInfo* info) {
+ ObjectGroup* new_entry = new ObjectGroup(length, info);
+ for (size_t i = 0; i < length; ++i) {
new_entry->objects_.Add(handles[i]);
- ObjectGroups()->Add(new_entry);
+ }
+ object_groups_.Add(new_entry);
+}
+
+
+void GlobalHandles::AddImplicitReferences(HeapObject* parent,
+ Object*** children,
+ size_t length) {
+ ImplicitRefGroup* new_entry = new ImplicitRefGroup(parent, length);
+ for (size_t i = 0; i < length; ++i) {
+ new_entry->children_.Add(children[i]);
+ }
+ implicit_ref_groups_.Add(new_entry);
}
void GlobalHandles::RemoveObjectGroups() {
- List<ObjectGroup*>* object_groups = ObjectGroups();
- for (int i = 0; i< object_groups->length(); i++) {
- delete object_groups->at(i);
+ for (int i = 0; i < object_groups_.length(); i++) {
+ delete object_groups_.at(i);
}
- object_groups->Clear();
+ object_groups_.Clear();
}
+
+void GlobalHandles::RemoveImplicitRefGroups() {
+ for (int i = 0; i < implicit_ref_groups_.length(); i++) {
+ delete implicit_ref_groups_.at(i);
+ }
+ implicit_ref_groups_.Clear();
+}
+
+
} } // namespace v8::internal
diff --git a/src/global-handles.h b/src/global-handles.h
index 37b2b445..a6afb2dc 100644
--- a/src/global-handles.h
+++ b/src/global-handles.h
@@ -39,31 +39,54 @@ namespace internal {
// At GC the destroyed global handles are removed from the free list
// and deallocated.
-// Callback function on handling weak global handles.
-// typedef bool (*WeakSlotCallback)(Object** pointer);
-
// An object group is treated like a single JS object: if one of object in
// the group is alive, all objects in the same group are considered alive.
// An object group is used to simulate object relationship in a DOM tree.
class ObjectGroup : public Malloced {
public:
ObjectGroup() : objects_(4) {}
- explicit ObjectGroup(size_t capacity)
- : objects_(static_cast<int>(capacity)) { }
+ ObjectGroup(size_t capacity, v8::RetainedObjectInfo* info)
+ : objects_(static_cast<int>(capacity)),
+ info_(info) { }
+ ~ObjectGroup();
List<Object**> objects_;
+ v8::RetainedObjectInfo* info_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ObjectGroup);
+};
+
+
+// An implicit references group consists of two parts: a parent object and
+// a list of children objects. If the parent is alive, all the children
+// are alive too.
+class ImplicitRefGroup : public Malloced {
+ public:
+ ImplicitRefGroup() : children_(4) {}
+ ImplicitRefGroup(HeapObject* parent, size_t capacity)
+ : parent_(parent),
+ children_(static_cast<int>(capacity)) { }
+
+ HeapObject* parent_;
+ List<Object**> children_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ImplicitRefGroup);
};
typedef void (*WeakReferenceGuest)(Object* object, void* parameter);
-class GlobalHandles : public AllStatic {
+class GlobalHandles {
public:
+ ~GlobalHandles();
+
// Creates a new global handle that is alive until Destroy is called.
- static Handle<Object> Create(Object* value);
+ Handle<Object> Create(Object* value);
// Destroy a global handle.
- static void Destroy(Object** location);
+ void Destroy(Object** location);
// Make the global handle weak and set the callback parameter for the
// handle. When the garbage collector recognizes that only weak global
@@ -71,23 +94,25 @@ class GlobalHandles : public AllStatic {
// function is invoked (for each handle) with the handle and corresponding
// parameter as arguments. Note: cleared means set to Smi::FromInt(0). The
// reason is that Smi::FromInt(0) does not change during garage collection.
- static void MakeWeak(Object** location,
- void* parameter,
- WeakReferenceCallback callback);
+ void MakeWeak(Object** location,
+ void* parameter,
+ WeakReferenceCallback callback);
+
+ static void SetWrapperClassId(Object** location, uint16_t class_id);
// Returns the current number of weak handles.
- static int NumberOfWeakHandles() { return number_of_weak_handles_; }
+ int NumberOfWeakHandles() { return number_of_weak_handles_; }
- static void RecordStats(HeapStats* stats);
+ void RecordStats(HeapStats* stats);
// Returns the current number of weak handles to global objects.
// These handles are also included in NumberOfWeakHandles().
- static int NumberOfGlobalObjectWeakHandles() {
+ int NumberOfGlobalObjectWeakHandles() {
return number_of_global_object_weak_handles_;
}
// Clear the weakness of a global handle.
- static void ClearWeakness(Object** location);
+ void ClearWeakness(Object** location);
// Tells whether global handle is near death.
static bool IsNearDeath(Object** location);
@@ -97,65 +122,89 @@ class GlobalHandles : public AllStatic {
// Process pending weak handles.
// Returns true if next major GC is likely to collect more garbage.
- static bool PostGarbageCollectionProcessing();
+ bool PostGarbageCollectionProcessing();
// Iterates over all strong handles.
- static void IterateStrongRoots(ObjectVisitor* v);
+ void IterateStrongRoots(ObjectVisitor* v);
// Iterates over all handles.
- static void IterateAllRoots(ObjectVisitor* v);
+ void IterateAllRoots(ObjectVisitor* v);
+
+ // Iterates over all handles that have embedder-assigned class ID.
+ void IterateAllRootsWithClassIds(ObjectVisitor* v);
// Iterates over all weak roots in heap.
- static void IterateWeakRoots(ObjectVisitor* v);
+ void IterateWeakRoots(ObjectVisitor* v);
// Iterates over weak roots that are bound to a given callback.
- static void IterateWeakRoots(WeakReferenceGuest f,
- WeakReferenceCallback callback);
+ void IterateWeakRoots(WeakReferenceGuest f,
+ WeakReferenceCallback callback);
// Find all weak handles satisfying the callback predicate, mark
// them as pending.
- static void IdentifyWeakHandles(WeakSlotCallback f);
+ void IdentifyWeakHandles(WeakSlotCallback f);
// Add an object group.
- // Should only used in GC callback function before a collection.
+ // Should be only used in GC callback function before a collection.
+ // All groups are destroyed after a mark-compact collection.
+ void AddObjectGroup(Object*** handles,
+ size_t length,
+ v8::RetainedObjectInfo* info);
+
+ // Add an implicit references' group.
+ // Should be only used in GC callback function before a collection.
// All groups are destroyed after a mark-compact collection.
- static void AddGroup(Object*** handles, size_t length);
+ void AddImplicitReferences(HeapObject* parent,
+ Object*** children,
+ size_t length);
// Returns the object groups.
- static List<ObjectGroup*>* ObjectGroups();
+ List<ObjectGroup*>* object_groups() { return &object_groups_; }
+
+ // Returns the implicit references' groups.
+ List<ImplicitRefGroup*>* implicit_ref_groups() {
+ return &implicit_ref_groups_;
+ }
// Remove bags, this should only happen after GC.
- static void RemoveObjectGroups();
+ void RemoveObjectGroups();
+ void RemoveImplicitRefGroups();
// Tear down the global handle structure.
- static void TearDown();
+ void TearDown();
+
+ Isolate* isolate() { return isolate_; }
#ifdef DEBUG
- static void PrintStats();
- static void Print();
+ void PrintStats();
+ void Print();
#endif
class Pool;
private:
+ explicit GlobalHandles(Isolate* isolate);
+
// Internal node structure, one for each global handle.
class Node;
+ Isolate* isolate_;
+
// Field always containing the number of weak and near-death handles.
- static int number_of_weak_handles_;
+ int number_of_weak_handles_;
// Field always containing the number of weak and near-death handles
// to global objects. These objects are also included in
// number_of_weak_handles_.
- static int number_of_global_object_weak_handles_;
+ int number_of_global_object_weak_handles_;
// Global handles are kept in a single linked list pointed to by head_.
- static Node* head_;
- static Node* head() { return head_; }
- static void set_head(Node* value) { head_ = value; }
+ Node* head_;
+ Node* head() { return head_; }
+ void set_head(Node* value) { head_ = value; }
// Free list for DESTROYED global handles not yet deallocated.
- static Node* first_free_;
- static Node* first_free() { return first_free_; }
- static void set_first_free(Node* value) { first_free_ = value; }
+ Node* first_free_;
+ Node* first_free() { return first_free_; }
+ void set_first_free(Node* value) { first_free_ = value; }
// List of deallocated nodes.
// Deallocated nodes form a prefix of all the nodes and
@@ -168,11 +217,20 @@ class GlobalHandles : public AllStatic {
// node node ... node node
// .next -> .next -> .next ->
// <- .next_free <- .next_free <- .next_free
- static Node* first_deallocated_;
- static Node* first_deallocated() { return first_deallocated_; }
- static void set_first_deallocated(Node* value) {
+ Node* first_deallocated_;
+ Node* first_deallocated() { return first_deallocated_; }
+ void set_first_deallocated(Node* value) {
first_deallocated_ = value;
}
+
+ Pool* pool_;
+ int post_gc_processing_count_;
+ List<ObjectGroup*> object_groups_;
+ List<ImplicitRefGroup*> implicit_ref_groups_;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(GlobalHandles);
};
diff --git a/src/globals.h b/src/globals.h
index 9b24bf63..5ab9806e 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -54,7 +54,7 @@ namespace internal {
#if CAN_USE_UNALIGNED_ACCESSES
#define V8_HOST_CAN_READ_UNALIGNED 1
#endif
-#elif defined(_MIPS_ARCH_MIPS32R2)
+#elif defined(__MIPSEL__)
#define V8_HOST_ARCH_MIPS 1
#define V8_HOST_ARCH_32_BIT 1
#else
@@ -72,7 +72,7 @@ namespace internal {
#define V8_TARGET_ARCH_IA32 1
#elif defined(__ARMEL__)
#define V8_TARGET_ARCH_ARM 1
-#elif defined(_MIPS_ARCH_MIPS32R2)
+#elif defined(__MIPSEL__)
#define V8_TARGET_ARCH_MIPS 1
#else
#error Target architecture was not detected as supported by v8
diff --git a/src/handles-inl.h b/src/handles-inl.h
index c0f2fda9..a5c81cec 100644
--- a/src/handles-inl.h
+++ b/src/handles-inl.h
@@ -29,17 +29,33 @@
#ifndef V8_HANDLES_INL_H_
#define V8_HANDLES_INL_H_
+#include "api.h"
#include "apiutils.h"
#include "handles.h"
-#include "api.h"
+#include "isolate.h"
namespace v8 {
namespace internal {
+inline Isolate* GetIsolateForHandle(Object* obj) {
+ return Isolate::Current();
+}
+
+inline Isolate* GetIsolateForHandle(HeapObject* obj) {
+ return obj->GetIsolate();
+}
+
template<typename T>
Handle<T>::Handle(T* obj) {
ASSERT(!obj->IsFailure());
- location_ = HandleScope::CreateHandle(obj);
+ location_ = HandleScope::CreateHandle(obj, GetIsolateForHandle(obj));
+}
+
+
+template<typename T>
+Handle<T>::Handle(T* obj, Isolate* isolate) {
+ ASSERT(!obj->IsFailure());
+ location_ = HandleScope::CreateHandle(obj, isolate);
}
@@ -51,10 +67,91 @@ inline T* Handle<T>::operator*() const {
}
+HandleScope::HandleScope() {
+ Isolate* isolate = Isolate::Current();
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate->handle_scope_data();
+ isolate_ = isolate;
+ prev_next_ = current->next;
+ prev_limit_ = current->limit;
+ current->level++;
+}
+
+
+HandleScope::HandleScope(Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate->handle_scope_data();
+ isolate_ = isolate;
+ prev_next_ = current->next;
+ prev_limit_ = current->limit;
+ current->level++;
+}
+
+
+HandleScope::~HandleScope() {
+ CloseScope();
+}
+
+void HandleScope::CloseScope() {
+ ASSERT(isolate_ == Isolate::Current());
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate_->handle_scope_data();
+ current->next = prev_next_;
+ current->level--;
+ if (current->limit != prev_limit_) {
+ current->limit = prev_limit_;
+ DeleteExtensions(isolate_);
+ }
+#ifdef DEBUG
+ ZapRange(prev_next_, prev_limit_);
+#endif
+}
+
+
+template <typename T>
+Handle<T> HandleScope::CloseAndEscape(Handle<T> handle_value) {
+ T* value = *handle_value;
+ // Throw away all handles in the current scope.
+ CloseScope();
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate_->handle_scope_data();
+ // Allocate one handle in the parent scope.
+ ASSERT(current->level > 0);
+ Handle<T> result(CreateHandle<T>(value, isolate_));
+ // Reinitialize the current scope (so that it's ready
+ // to be used or closed again).
+ prev_next_ = current->next;
+ prev_limit_ = current->limit;
+ current->level++;
+ return result;
+}
+
+
+template <typename T>
+T** HandleScope::CreateHandle(T* value, Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate->handle_scope_data();
+
+ internal::Object** cur = current->next;
+ if (cur == current->limit) cur = Extend();
+ // Update the current next field, set the value in the created
+ // handle, and return the result.
+ ASSERT(cur < current->limit);
+ current->next = cur + 1;
+
+ T** result = reinterpret_cast<T**>(cur);
+ *result = value;
+ return result;
+}
+
+
#ifdef DEBUG
inline NoHandleAllocation::NoHandleAllocation() {
v8::ImplementationUtilities::HandleScopeData* current =
- v8::ImplementationUtilities::CurrentHandleScope();
+ Isolate::Current()->handle_scope_data();
+
// Shrink the current handle scope to make it impossible to do
// handle allocations without an explicit handle scope.
current->limit = current->next;
@@ -67,10 +164,10 @@ inline NoHandleAllocation::NoHandleAllocation() {
inline NoHandleAllocation::~NoHandleAllocation() {
// Restore state in current handle scope to re-enable handle
// allocations.
- v8::ImplementationUtilities::HandleScopeData* current =
- v8::ImplementationUtilities::CurrentHandleScope();
- ASSERT_EQ(0, current->level);
- current->level = level_;
+ v8::ImplementationUtilities::HandleScopeData* data =
+ Isolate::Current()->handle_scope_data();
+ ASSERT_EQ(0, data->level);
+ data->level = level_;
}
#endif
diff --git a/src/handles.cc b/src/handles.cc
index efef095a..97a06d98 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -45,57 +45,62 @@ namespace v8 {
namespace internal {
-v8::ImplementationUtilities::HandleScopeData HandleScope::current_ =
- { NULL, NULL, 0 };
-
-
int HandleScope::NumberOfHandles() {
- int n = HandleScopeImplementer::instance()->blocks()->length();
+ Isolate* isolate = Isolate::Current();
+ HandleScopeImplementer* impl = isolate->handle_scope_implementer();
+ int n = impl->blocks()->length();
if (n == 0) return 0;
return ((n - 1) * kHandleBlockSize) + static_cast<int>(
- (current_.next - HandleScopeImplementer::instance()->blocks()->last()));
+ (isolate->handle_scope_data()->next - impl->blocks()->last()));
}
Object** HandleScope::Extend() {
- Object** result = current_.next;
+ Isolate* isolate = Isolate::Current();
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate->handle_scope_data();
+
+ Object** result = current->next;
- ASSERT(result == current_.limit);
+ ASSERT(result == current->limit);
// Make sure there's at least one scope on the stack and that the
// top of the scope stack isn't a barrier.
- if (current_.level == 0) {
+ if (current->level == 0) {
Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
"Cannot create a handle without a HandleScope");
return NULL;
}
- HandleScopeImplementer* impl = HandleScopeImplementer::instance();
+ HandleScopeImplementer* impl = isolate->handle_scope_implementer();
// If there's more room in the last block, we use that. This is used
// for fast creation of scopes after scope barriers.
if (!impl->blocks()->is_empty()) {
Object** limit = &impl->blocks()->last()[kHandleBlockSize];
- if (current_.limit != limit) {
- current_.limit = limit;
- ASSERT(limit - current_.next < kHandleBlockSize);
+ if (current->limit != limit) {
+ current->limit = limit;
+ ASSERT(limit - current->next < kHandleBlockSize);
}
}
// If we still haven't found a slot for the handle, we extend the
// current handle scope by allocating a new handle block.
- if (result == current_.limit) {
+ if (result == current->limit) {
// If there's a spare block, use it for growing the current scope.
result = impl->GetSpareOrNewBlock();
// Add the extension to the global list of blocks, but count the
// extension as part of the current scope.
impl->blocks()->Add(result);
- current_.limit = &result[kHandleBlockSize];
+ current->limit = &result[kHandleBlockSize];
}
return result;
}
-void HandleScope::DeleteExtensions() {
- HandleScopeImplementer::instance()->DeleteExtensions(current_.limit);
+void HandleScope::DeleteExtensions(Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ v8::ImplementationUtilities::HandleScopeData* current =
+ isolate->handle_scope_data();
+ isolate->handle_scope_implementer()->DeleteExtensions(current->limit);
}
@@ -108,37 +113,44 @@ void HandleScope::ZapRange(Object** start, Object** end) {
Address HandleScope::current_level_address() {
- return reinterpret_cast<Address>(&current_.level);
+ return reinterpret_cast<Address>(
+ &Isolate::Current()->handle_scope_data()->level);
}
Address HandleScope::current_next_address() {
- return reinterpret_cast<Address>(&current_.next);
+ return reinterpret_cast<Address>(
+ &Isolate::Current()->handle_scope_data()->next);
}
Address HandleScope::current_limit_address() {
- return reinterpret_cast<Address>(&current_.limit);
+ return reinterpret_cast<Address>(
+ &Isolate::Current()->handle_scope_data()->limit);
}
Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
Handle<JSArray> array) {
- CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray);
+ CALL_HEAP_FUNCTION(content->GetIsolate(),
+ content->AddKeysFromJSArray(*array), FixedArray);
}
Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first,
Handle<FixedArray> second) {
- CALL_HEAP_FUNCTION(first->UnionOfKeys(*second), FixedArray);
+ CALL_HEAP_FUNCTION(first->GetIsolate(),
+ first->UnionOfKeys(*second), FixedArray);
}
Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
Handle<JSFunction> constructor,
Handle<JSGlobalProxy> global) {
- CALL_HEAP_FUNCTION(Heap::ReinitializeJSGlobalProxy(*constructor, *global),
- JSGlobalProxy);
+ CALL_HEAP_FUNCTION(
+ constructor->GetIsolate(),
+ constructor->GetHeap()->ReinitializeJSGlobalProxy(*constructor, *global),
+ JSGlobalProxy);
}
@@ -153,7 +165,8 @@ void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
func->shared()->set_expected_nof_properties(nof);
if (func->has_initial_map()) {
Handle<Map> new_initial_map =
- Factory::CopyMapDropTransitions(Handle<Map>(func->initial_map()));
+ func->GetIsolate()->factory()->CopyMapDropTransitions(
+ Handle<Map>(func->initial_map()));
new_initial_map->set_unused_property_fields(nof);
func->set_initial_map(*new_initial_map);
}
@@ -161,7 +174,8 @@ void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) {
- CALL_HEAP_FUNCTION_VOID(func->SetPrototype(*value));
+ CALL_HEAP_FUNCTION_VOID(func->GetIsolate(),
+ func->SetPrototype(*value));
}
@@ -193,20 +207,23 @@ void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
void NormalizeProperties(Handle<JSObject> object,
PropertyNormalizationMode mode,
int expected_additional_properties) {
- CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties(
- mode,
- expected_additional_properties));
+ CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
+ object->NormalizeProperties(
+ mode,
+ expected_additional_properties));
}
void NormalizeElements(Handle<JSObject> object) {
- CALL_HEAP_FUNCTION_VOID(object->NormalizeElements());
+ CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
+ object->NormalizeElements());
}
void TransformToFastProperties(Handle<JSObject> object,
int unused_property_fields) {
CALL_HEAP_FUNCTION_VOID(
+ object->GetIsolate(),
object->TransformToFastProperties(unused_property_fields));
}
@@ -215,24 +232,26 @@ void NumberDictionarySet(Handle<NumberDictionary> dictionary,
uint32_t index,
Handle<Object> value,
PropertyDetails details) {
- CALL_HEAP_FUNCTION_VOID(dictionary->Set(index, *value, details));
+ CALL_HEAP_FUNCTION_VOID(dictionary->GetIsolate(),
+ dictionary->Set(index, *value, details));
}
void FlattenString(Handle<String> string) {
- CALL_HEAP_FUNCTION_VOID(string->TryFlatten());
+ CALL_HEAP_FUNCTION_VOID(string->GetIsolate(), string->TryFlatten());
}
Handle<String> FlattenGetString(Handle<String> string) {
- CALL_HEAP_FUNCTION(string->TryFlatten(), String);
+ CALL_HEAP_FUNCTION(string->GetIsolate(), string->TryFlatten(), String);
}
Handle<Object> SetPrototype(Handle<JSFunction> function,
Handle<Object> prototype) {
ASSERT(function->should_have_prototype());
- CALL_HEAP_FUNCTION(Accessors::FunctionSetPrototype(*function,
+ CALL_HEAP_FUNCTION(function->GetIsolate(),
+ Accessors::FunctionSetPrototype(*function,
*prototype,
NULL),
Object);
@@ -244,7 +263,8 @@ Handle<Object> SetProperty(Handle<JSObject> object,
Handle<Object> value,
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
- CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes, strict_mode),
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetProperty(*key, *value, attributes, strict_mode),
Object);
}
@@ -254,8 +274,11 @@ Handle<Object> SetProperty(Handle<Object> object,
Handle<Object> value,
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
+ Isolate* isolate = Isolate::Current();
CALL_HEAP_FUNCTION(
- Runtime::SetObjectProperty(object, key, value, attributes, strict_mode),
+ isolate,
+ Runtime::SetObjectProperty(
+ isolate, object, key, value, attributes, strict_mode),
Object);
}
@@ -264,9 +287,11 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object,
Handle<Object> key,
Handle<Object> value,
PropertyAttributes attributes) {
+ Isolate* isolate = object->GetIsolate();
CALL_HEAP_FUNCTION(
+ isolate,
Runtime::ForceSetObjectProperty(
- object, key, value, attributes),
+ isolate, object, key, value, attributes),
Object);
}
@@ -275,14 +300,18 @@ Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
Handle<String> key,
Handle<Object> value,
PropertyDetails details) {
- CALL_HEAP_FUNCTION(object->SetNormalizedProperty(*key, *value, details),
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetNormalizedProperty(*key, *value, details),
Object);
}
Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
Handle<Object> key) {
- CALL_HEAP_FUNCTION(Runtime::ForceDeleteObjectProperty(object, key), Object);
+ Isolate* isolate = object->GetIsolate();
+ CALL_HEAP_FUNCTION(isolate,
+ Runtime::ForceDeleteObjectProperty(isolate, object, key),
+ Object);
}
@@ -291,8 +320,10 @@ Handle<Object> SetLocalPropertyIgnoreAttributes(
Handle<String> key,
Handle<Object> value,
PropertyAttributes attributes) {
- CALL_HEAP_FUNCTION(object->
- SetLocalPropertyIgnoreAttributes(*key, *value, attributes), Object);
+ CALL_HEAP_FUNCTION(
+ object->GetIsolate(),
+ object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
+ Object);
}
@@ -300,10 +331,11 @@ void SetLocalPropertyNoThrow(Handle<JSObject> object,
Handle<String> key,
Handle<Object> value,
PropertyAttributes attributes) {
- ASSERT(!Top::has_pending_exception());
+ Isolate* isolate = object->GetIsolate();
+ ASSERT(!isolate->has_pending_exception());
CHECK(!SetLocalPropertyIgnoreAttributes(
object, key, value, attributes).is_null());
- CHECK(!Top::has_pending_exception());
+ CHECK(!isolate->has_pending_exception());
}
@@ -312,7 +344,8 @@ Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
Handle<Object> value,
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
- CALL_HEAP_FUNCTION(object->SetPropertyWithInterceptor(*key,
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetPropertyWithInterceptor(*key,
*value,
attributes,
strict_mode),
@@ -322,20 +355,24 @@ Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
Handle<Object> GetProperty(Handle<JSObject> obj,
const char* name) {
- Handle<String> str = Factory::LookupAsciiSymbol(name);
- CALL_HEAP_FUNCTION(obj->GetProperty(*str), Object);
+ Isolate* isolate = obj->GetIsolate();
+ Handle<String> str = isolate->factory()->LookupAsciiSymbol(name);
+ CALL_HEAP_FUNCTION(isolate, obj->GetProperty(*str), Object);
}
Handle<Object> GetProperty(Handle<Object> obj,
Handle<Object> key) {
- CALL_HEAP_FUNCTION(Runtime::GetObjectProperty(obj, key), Object);
+ Isolate* isolate = Isolate::Current();
+ CALL_HEAP_FUNCTION(isolate,
+ Runtime::GetObjectProperty(isolate, obj, key), Object);
}
Handle<Object> GetElement(Handle<Object> obj,
uint32_t index) {
- CALL_HEAP_FUNCTION(Runtime::GetElement(obj, index), Object);
+ Isolate* isolate = Isolate::Current();
+ CALL_HEAP_FUNCTION(isolate, Runtime::GetElement(obj, index), Object);
}
@@ -343,7 +380,9 @@ Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<String> name,
PropertyAttributes* attributes) {
- CALL_HEAP_FUNCTION(holder->GetPropertyWithInterceptor(*receiver,
+ Isolate* isolate = receiver->GetIsolate();
+ CALL_HEAP_FUNCTION(isolate,
+ holder->GetPropertyWithInterceptor(*receiver,
*name,
attributes),
Object);
@@ -358,15 +397,22 @@ Handle<Object> GetPrototype(Handle<Object> obj) {
Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) {
const bool skip_hidden_prototypes = false;
- CALL_HEAP_FUNCTION(obj->SetPrototype(*value, skip_hidden_prototypes), Object);
+ CALL_HEAP_FUNCTION(obj->GetIsolate(),
+ obj->SetPrototype(*value, skip_hidden_prototypes), Object);
+}
+
+
+Handle<Object> PreventExtensions(Handle<JSObject> object) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
}
Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
bool create_if_needed) {
+ Isolate* isolate = obj->GetIsolate();
Object* holder = obj->BypassGlobalProxy();
- if (holder->IsUndefined()) return Factory::undefined_value();
- obj = Handle<JSObject>(JSObject::cast(holder));
+ if (holder->IsUndefined()) return isolate->factory()->undefined_value();
+ obj = Handle<JSObject>(JSObject::cast(holder), isolate);
if (obj->HasFastProperties()) {
// If the object has fast properties, check whether the first slot
@@ -375,10 +421,11 @@ Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
// code zero) it will always occupy the first entry if present.
DescriptorArray* descriptors = obj->map()->instance_descriptors();
if ((descriptors->number_of_descriptors() > 0) &&
- (descriptors->GetKey(0) == Heap::hidden_symbol()) &&
+ (descriptors->GetKey(0) == isolate->heap()->hidden_symbol()) &&
descriptors->IsProperty(0)) {
ASSERT(descriptors->GetType(0) == FIELD);
- return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
+ return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0)),
+ isolate);
}
}
@@ -389,32 +436,39 @@ Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
// Hidden properties object not found. Allocate a new hidden properties
// object if requested. Otherwise return the undefined value.
if (create_if_needed) {
- Handle<Object> hidden_obj = Factory::NewJSObject(Top::object_function());
- CALL_HEAP_FUNCTION(obj->SetHiddenPropertiesObject(*hidden_obj), Object);
+ Handle<Object> hidden_obj =
+ isolate->factory()->NewJSObject(isolate->object_function());
+ CALL_HEAP_FUNCTION(isolate,
+ obj->SetHiddenPropertiesObject(*hidden_obj), Object);
} else {
- return Factory::undefined_value();
+ return isolate->factory()->undefined_value();
}
}
- return Handle<Object>(obj->GetHiddenPropertiesObject());
+ return Handle<Object>(obj->GetHiddenPropertiesObject(), isolate);
}
Handle<Object> DeleteElement(Handle<JSObject> obj,
uint32_t index) {
- CALL_HEAP_FUNCTION(obj->DeleteElement(index, JSObject::NORMAL_DELETION),
+ CALL_HEAP_FUNCTION(obj->GetIsolate(),
+ obj->DeleteElement(index, JSObject::NORMAL_DELETION),
Object);
}
Handle<Object> DeleteProperty(Handle<JSObject> obj,
Handle<String> prop) {
- CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
+ CALL_HEAP_FUNCTION(obj->GetIsolate(),
+ obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
Object);
}
Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
- CALL_HEAP_FUNCTION(Heap::LookupSingleCharacterStringFromCode(index), Object);
+ Isolate* isolate = Isolate::Current();
+ CALL_HEAP_FUNCTION(
+ isolate,
+ isolate->heap()->LookupSingleCharacterStringFromCode(index), Object);
}
@@ -422,7 +476,8 @@ Handle<String> SubString(Handle<String> str,
int start,
int end,
PretenureFlag pretenure) {
- CALL_HEAP_FUNCTION(str->SubString(start, end, pretenure), String);
+ CALL_HEAP_FUNCTION(str->GetIsolate(),
+ str->SubString(start, end, pretenure), String);
}
@@ -430,7 +485,7 @@ Handle<Object> SetElement(Handle<JSObject> object,
uint32_t index,
Handle<Object> value,
StrictModeFlag strict_mode) {
- if (object->HasPixelElements() || object->HasExternalArrayElements()) {
+ if (object->HasExternalArrayElements()) {
if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
bool has_exception;
Handle<Object> number = Execution::ToNumber(value, &has_exception);
@@ -438,7 +493,8 @@ Handle<Object> SetElement(Handle<JSObject> object,
value = number;
}
}
- CALL_HEAP_FUNCTION(object->SetElement(index, *value, strict_mode), Object);
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetElement(index, *value, strict_mode), Object);
}
@@ -446,20 +502,22 @@ Handle<Object> SetOwnElement(Handle<JSObject> object,
uint32_t index,
Handle<Object> value,
StrictModeFlag strict_mode) {
- ASSERT(!object->HasPixelElements());
ASSERT(!object->HasExternalArrayElements());
- CALL_HEAP_FUNCTION(object->SetElement(index, *value, strict_mode, false),
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetElement(index, *value, strict_mode, false),
Object);
}
Handle<JSObject> Copy(Handle<JSObject> obj) {
- CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject);
+ Isolate* isolate = obj->GetIsolate();
+ CALL_HEAP_FUNCTION(isolate,
+ isolate->heap()->CopyJSObject(*obj), JSObject);
}
Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) {
- CALL_HEAP_FUNCTION(obj->DefineAccessor(*info), Object);
+ CALL_HEAP_FUNCTION(obj->GetIsolate(), obj->DefineAccessor(*info), Object);
}
@@ -480,8 +538,9 @@ static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
Proxy* proxy = Script::cast(wrapper->value())->wrapper();
ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location()));
proxy->set_proxy(0);
- GlobalHandles::Destroy(cache.location());
- Counters::script_wrappers.Decrement();
+ Isolate* isolate = Isolate::Current();
+ isolate->global_handles()->Destroy(cache.location());
+ isolate->counters()->script_wrappers()->Decrement();
}
@@ -491,19 +550,20 @@ Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
return Handle<JSValue>(
reinterpret_cast<JSValue**>(script->wrapper()->proxy()));
}
-
+ Isolate* isolate = Isolate::Current();
// Construct a new script wrapper.
- Counters::script_wrappers.Increment();
- Handle<JSFunction> constructor = Top::script_function();
+ isolate->counters()->script_wrappers()->Increment();
+ Handle<JSFunction> constructor = isolate->script_function();
Handle<JSValue> result =
- Handle<JSValue>::cast(Factory::NewJSObject(constructor));
+ Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
result->set_value(*script);
// Create a new weak global handle and use it to cache the wrapper
// for future use. The cache will automatically be cleared by the
// garbage collector when it is not used anymore.
- Handle<Object> handle = GlobalHandles::Create(*result);
- GlobalHandles::MakeWeak(handle.location(), NULL, &ClearWrapperCache);
+ Handle<Object> handle = isolate->global_handles()->Create(*result);
+ isolate->global_handles()->MakeWeak(handle.location(), NULL,
+ &ClearWrapperCache);
script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location()));
return result;
}
@@ -514,20 +574,22 @@ Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
void InitScriptLineEnds(Handle<Script> script) {
if (!script->line_ends()->IsUndefined()) return;
+ Isolate* isolate = script->GetIsolate();
+
if (!script->source()->IsString()) {
ASSERT(script->source()->IsUndefined());
- Handle<FixedArray> empty = Factory::NewFixedArray(0);
+ Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
script->set_line_ends(*empty);
ASSERT(script->line_ends()->IsFixedArray());
return;
}
- Handle<String> src(String::cast(script->source()));
+ Handle<String> src(String::cast(script->source()), isolate);
Handle<FixedArray> array = CalculateLineEnds(src, true);
- if (*array != Heap::empty_fixed_array()) {
- array->set_map(Heap::fixed_cow_array_map());
+ if (*array != isolate->heap()->empty_fixed_array()) {
+ array->set_map(isolate->heap()->fixed_cow_array_map());
}
script->set_line_ends(*array);
@@ -536,11 +598,12 @@ void InitScriptLineEnds(Handle<Script> script) {
template <typename SourceChar>
-static void CalculateLineEnds(List<int>* line_ends,
+static void CalculateLineEnds(Isolate* isolate,
+ List<int>* line_ends,
Vector<const SourceChar> src,
bool with_last_line) {
const int src_len = src.length();
- StringSearch<char, SourceChar> search(CStrVector("\n"));
+ StringSearch<char, SourceChar> search(isolate, CStrVector("\n"));
// Find and record line ends.
int position = 0;
@@ -565,17 +628,24 @@ Handle<FixedArray> CalculateLineEnds(Handle<String> src,
// length of (unpacked) code.
int line_count_estimate = src->length() >> 4;
List<int> line_ends(line_count_estimate);
+ Isolate* isolate = src->GetIsolate();
{
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid.
// Dispatch on type of strings.
if (src->IsAsciiRepresentation()) {
- CalculateLineEnds(&line_ends, src->ToAsciiVector(), with_last_line);
+ CalculateLineEnds(isolate,
+ &line_ends,
+ src->ToAsciiVector(),
+ with_last_line);
} else {
- CalculateLineEnds(&line_ends, src->ToUC16Vector(), with_last_line);
+ CalculateLineEnds(isolate,
+ &line_ends,
+ src->ToUC16Vector(),
+ with_last_line);
}
}
int line_count = line_ends.length();
- Handle<FixedArray> array = Factory::NewFixedArray(line_count);
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
for (int i = 0; i < line_count; i++) {
array->set(i, Smi::FromInt(line_ends[i]));
}
@@ -641,17 +711,18 @@ void CustomArguments::IterateInstance(ObjectVisitor* v) {
// Compute the property keys from the interceptor.
v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
Handle<JSObject> object) {
+ Isolate* isolate = receiver->GetIsolate();
Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
- CustomArguments args(interceptor->data(), *receiver, *object);
+ CustomArguments args(isolate, interceptor->data(), *receiver, *object);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Array> result;
if (!interceptor->enumerator()->IsUndefined()) {
v8::NamedPropertyEnumerator enum_fun =
v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator());
- LOG(ApiObjectAccess("interceptor-named-enum", *object));
+ LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = enum_fun(info);
}
}
@@ -662,17 +733,18 @@ v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
// Compute the element keys from the interceptor.
v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
Handle<JSObject> object) {
+ Isolate* isolate = receiver->GetIsolate();
Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
- CustomArguments args(interceptor->data(), *receiver, *object);
+ CustomArguments args(isolate, interceptor->data(), *receiver, *object);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Array> result;
if (!interceptor->enumerator()->IsUndefined()) {
v8::IndexedPropertyEnumerator enum_fun =
v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator());
- LOG(ApiObjectAccess("interceptor-indexed-enum", *object));
+ LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = enum_fun(info);
}
}
@@ -693,31 +765,33 @@ static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
KeyCollectionType type) {
USE(ContainsOnlyValidKeys);
- Handle<FixedArray> content = Factory::empty_fixed_array();
- Handle<JSObject> arguments_boilerplate =
- Handle<JSObject>(
- Top::context()->global_context()->arguments_boilerplate());
- Handle<JSFunction> arguments_function =
- Handle<JSFunction>(
- JSFunction::cast(arguments_boilerplate->map()->constructor()));
+ Isolate* isolate = object->GetIsolate();
+ Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
+ Handle<JSObject> arguments_boilerplate = Handle<JSObject>(
+ isolate->context()->global_context()->arguments_boilerplate(),
+ isolate);
+ Handle<JSFunction> arguments_function = Handle<JSFunction>(
+ JSFunction::cast(arguments_boilerplate->map()->constructor()),
+ isolate);
// Only collect keys if access is permitted.
for (Handle<Object> p = object;
- *p != Heap::null_value();
- p = Handle<Object>(p->GetPrototype())) {
- Handle<JSObject> current(JSObject::cast(*p));
+ *p != isolate->heap()->null_value();
+ p = Handle<Object>(p->GetPrototype(), isolate)) {
+ Handle<JSObject> current(JSObject::cast(*p), isolate);
// Check access rights if required.
if (current->IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(*current, Heap::undefined_value(),
- v8::ACCESS_KEYS)) {
- Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
+ !isolate->MayNamedAccess(*current,
+ isolate->heap()->undefined_value(),
+ v8::ACCESS_KEYS)) {
+ isolate->ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
break;
}
// Compute the element keys.
Handle<FixedArray> element_keys =
- Factory::NewFixedArray(current->NumberOfEnumElements());
+ isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
current->GetEnumElementKeys(*element_keys);
content = UnionOfKeys(content, element_keys);
ASSERT(ContainsOnlyValidKeys(content));
@@ -771,28 +845,31 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
- Counters::for_in.Increment();
+ Isolate* isolate = object->GetIsolate();
+ isolate->counters()->for_in()->Increment();
Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
INCLUDE_PROTOS);
- return Factory::NewJSArrayWithElements(elements);
+ return isolate->factory()->NewJSArrayWithElements(elements);
}
Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
bool cache_result) {
int index = 0;
+ Isolate* isolate = object->GetIsolate();
if (object->HasFastProperties()) {
if (object->map()->instance_descriptors()->HasEnumCache()) {
- Counters::enum_cache_hits.Increment();
+ isolate->counters()->enum_cache_hits()->Increment();
DescriptorArray* desc = object->map()->instance_descriptors();
- return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()));
+ return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()),
+ isolate);
}
- Counters::enum_cache_misses.Increment();
+ isolate->counters()->enum_cache_misses()->Increment();
int num_enum = object->NumberOfEnumProperties();
- Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
- Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
+ Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum);
+ Handle<FixedArray> sort_array = isolate->factory()->NewFixedArray(num_enum);
Handle<DescriptorArray> descs =
- Handle<DescriptorArray>(object->map()->instance_descriptors());
+ Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
for (int i = 0; i < descs->number_of_descriptors(); i++) {
if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
(*storage)->set(index, descs->GetKey(i));
@@ -804,7 +881,8 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
(*storage)->SortPairs(*sort_array, sort_array->length());
if (cache_result) {
Handle<FixedArray> bridge_storage =
- Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
+ isolate->factory()->NewFixedArray(
+ DescriptorArray::kEnumCacheBridgeLength);
DescriptorArray* desc = object->map()->instance_descriptors();
desc->SetEnumCache(*bridge_storage, *storage);
}
@@ -812,8 +890,8 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
return storage;
} else {
int num_enum = object->NumberOfEnumProperties();
- Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
- Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
+ Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum);
+ Handle<FixedArray> sort_array = isolate->factory()->NewFixedArray(num_enum);
object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
return storage;
}
@@ -830,10 +908,12 @@ static bool CompileLazyHelper(CompilationInfo* info,
ClearExceptionFlag flag) {
// Compile the source information to a code object.
ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
- ASSERT(!Top::has_pending_exception());
+ ASSERT(!info->isolate()->has_pending_exception());
bool result = Compiler::CompileLazy(info);
- ASSERT(result != Top::has_pending_exception());
- if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception();
+ ASSERT(result != Isolate::Current()->has_pending_exception());
+ if (!result && flag == CLEAR_EXCEPTION) {
+ info->isolate()->clear_pending_exception();
+ }
return result;
}
@@ -882,34 +962,4 @@ bool CompileOptimized(Handle<JSFunction> function,
return CompileLazyHelper(&info, flag);
}
-
-OptimizedObjectForAddingMultipleProperties::
-OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
- int expected_additional_properties,
- bool condition) {
- object_ = object;
- if (condition && object_->HasFastProperties() && !object->IsJSGlobalProxy()) {
- // Normalize the properties of object to avoid n^2 behavior
- // when extending the object multiple properties. Indicate the number of
- // properties to be added.
- unused_property_fields_ = object->map()->unused_property_fields();
- NormalizeProperties(object_,
- KEEP_INOBJECT_PROPERTIES,
- expected_additional_properties);
- has_been_transformed_ = true;
-
- } else {
- has_been_transformed_ = false;
- }
-}
-
-
-OptimizedObjectForAddingMultipleProperties::
-~OptimizedObjectForAddingMultipleProperties() {
- // Reoptimize the object to allow fast property access.
- if (has_been_transformed_) {
- TransformToFastProperties(object_, unused_property_fields_);
- }
-}
-
} } // namespace v8::internal
diff --git a/src/handles.h b/src/handles.h
index bb519688..a357a009 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -44,6 +44,7 @@ class Handle {
public:
INLINE(explicit Handle(T** location)) { location_ = location; }
INLINE(explicit Handle(T* obj));
+ INLINE(Handle(T* obj, Isolate* isolate));
INLINE(Handle()) : location_(NULL) {}
@@ -82,7 +83,7 @@ class Handle {
}
static Handle<T> null() { return Handle<T>(); }
- bool is_null() { return location_ == NULL; }
+ bool is_null() const { return location_ == NULL; }
// Closes the given scope, but lets this handle escape. See
// implementation in api.h.
@@ -107,34 +108,20 @@ class Handle {
// for which the handle scope has been deleted is undefined.
class HandleScope {
public:
- HandleScope() : prev_next_(current_.next), prev_limit_(current_.limit) {
- current_.level++;
- }
+ inline HandleScope();
+ explicit inline HandleScope(Isolate* isolate);
- ~HandleScope() {
- CloseScope();
- }
+ inline ~HandleScope();
// Counts the number of allocated handles.
static int NumberOfHandles();
// Creates a new handle with the given value.
template <typename T>
- static inline T** CreateHandle(T* value) {
- internal::Object** cur = current_.next;
- if (cur == current_.limit) cur = Extend();
- // Update the current next field, set the value in the created
- // handle, and return the result.
- ASSERT(cur < current_.limit);
- current_.next = cur + 1;
-
- T** result = reinterpret_cast<T**>(cur);
- *result = value;
- return result;
- }
+ static inline T** CreateHandle(T* value, Isolate* isolate);
// Deallocates any extensions used by the current scope.
- static void DeleteExtensions();
+ static void DeleteExtensions(Isolate* isolate);
static Address current_next_address();
static Address current_limit_address();
@@ -145,20 +132,9 @@ class HandleScope {
// a Handle backed by the parent scope holding the
// value of the argument handle.
template <typename T>
- Handle<T> CloseAndEscape(Handle<T> handle_value) {
- T* value = *handle_value;
- // Throw away all handles in the current scope.
- CloseScope();
- // Allocate one handle in the parent scope.
- ASSERT(current_.level > 0);
- Handle<T> result(CreateHandle<T>(value));
- // Reinitialize the current scope (so that it's ready
- // to be used or closed again).
- prev_next_ = current_.next;
- prev_limit_ = current_.limit;
- current_.level++;
- return result;
- }
+ Handle<T> CloseAndEscape(Handle<T> handle_value);
+
+ Isolate* isolate() { return isolate_; }
private:
// Prevent heap allocation or illegal handle scopes.
@@ -167,21 +143,9 @@ class HandleScope {
void* operator new(size_t size);
void operator delete(void* size_t);
- inline void CloseScope() {
- current_.next = prev_next_;
- current_.level--;
- if (current_.limit != prev_limit_) {
- current_.limit = prev_limit_;
- DeleteExtensions();
- }
-#ifdef DEBUG
- ZapRange(prev_next_, prev_limit_);
-#endif
- }
+ inline void CloseScope();
- static v8::ImplementationUtilities::HandleScopeData current_;
- // Holds values on entry. The prev_next_ value is never NULL
- // on_entry, but is set to NULL when this scope is closed.
+ Isolate* isolate_;
Object** prev_next_;
Object** prev_limit_;
@@ -264,10 +228,10 @@ Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
PropertyAttributes attributes,
StrictModeFlag strict_mode);
-Handle<Object> SetElement(Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
- StrictModeFlag strict_mode);
+MUST_USE_RESULT Handle<Object> SetElement(Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
+ StrictModeFlag strict_mode);
Handle<Object> SetOwnElement(Handle<JSObject> object,
uint32_t index,
@@ -370,6 +334,7 @@ Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
Handle<Object> SetPrototype(Handle<JSFunction> function,
Handle<Object> prototype);
+Handle<Object> PreventExtensions(Handle<JSObject> object);
// Does lazy compilation of the given function. Returns true on success and
// false if the compilation resulted in a stack overflow.
@@ -402,25 +367,6 @@ class NoHandleAllocation BASE_EMBEDDED {
#endif
};
-
-// ----------------------------------------------------------------------------
-
-
-// Stack allocated wrapper call for optimizing adding multiple
-// properties to an object.
-class OptimizedObjectForAddingMultipleProperties BASE_EMBEDDED {
- public:
- OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
- int expected_property_count,
- bool condition = true);
- ~OptimizedObjectForAddingMultipleProperties();
- private:
- bool has_been_transformed_; // Tells whether the object has been transformed.
- int unused_property_fields_; // Captures the unused number of field.
- Handle<JSObject> object_; // The object being optimized.
-};
-
-
} } // namespace v8::internal
#endif // V8_HANDLES_H_
diff --git a/src/hashmap.h b/src/hashmap.h
index 27989889..bb3e3ceb 100644
--- a/src/hashmap.h
+++ b/src/hashmap.h
@@ -55,9 +55,9 @@ class HashMap {
// initial_capacity is the size of the initial hash map;
// it must be a power of 2 (and thus must not be 0).
- HashMap(MatchFun match,
- Allocator* allocator = &DefaultAllocator,
- uint32_t initial_capacity = 8);
+ explicit HashMap(MatchFun match,
+ Allocator* allocator = &DefaultAllocator,
+ uint32_t initial_capacity = 8);
~HashMap();
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 7b91e871..99737ed9 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -30,11 +30,20 @@
#include "heap.h"
#include "objects.h"
+#include "isolate.h"
#include "v8-counters.h"
namespace v8 {
namespace internal {
+void PromotionQueue::insert(HeapObject* target, int size) {
+ *(--rear_) = reinterpret_cast<intptr_t>(target);
+ *(--rear_) = size;
+ // Assert no overflow into live objects.
+ ASSERT(reinterpret_cast<Address>(rear_) >= HEAP->new_space()->top());
+}
+
+
int Heap::MaxObjectSizeInPagedSpace() {
return Page::kMaxHeapObjectSize;
}
@@ -146,8 +155,8 @@ MaybeObject* Heap::AllocateRaw(int size_in_bytes,
Heap::allocation_timeout_-- <= 0) {
return Failure::RetryAfterGC(space);
}
- Counters::objs_since_last_full.Increment();
- Counters::objs_since_last_young.Increment();
+ isolate_->counters()->objs_since_last_full()->Increment();
+ isolate_->counters()->objs_since_last_young()->Increment();
#endif
MaybeObject* result;
if (NEW_SPACE == space) {
@@ -214,8 +223,8 @@ void Heap::FinalizeExternalString(String* string) {
MaybeObject* Heap::AllocateRawMap() {
#ifdef DEBUG
- Counters::objs_since_last_full.Increment();
- Counters::objs_since_last_young.Increment();
+ isolate_->counters()->objs_since_last_full()->Increment();
+ isolate_->counters()->objs_since_last_young()->Increment();
#endif
MaybeObject* result = map_space_->AllocateRaw(Map::kSize);
if (result->IsFailure()) old_gen_exhausted_ = true;
@@ -232,8 +241,8 @@ MaybeObject* Heap::AllocateRawMap() {
MaybeObject* Heap::AllocateRawCell() {
#ifdef DEBUG
- Counters::objs_since_last_full.Increment();
- Counters::objs_since_last_young.Increment();
+ isolate_->counters()->objs_since_last_full()->Increment();
+ isolate_->counters()->objs_since_last_young()->Increment();
#endif
MaybeObject* result = cell_space_->AllocateRaw(JSGlobalPropertyCell::kSize);
if (result->IsFailure()) old_gen_exhausted_ = true;
@@ -341,7 +350,7 @@ void Heap::CopyBlockToOldSpaceAndUpdateRegionMarks(Address dst,
remaining--) {
Memory::Object_at(dst) = Memory::Object_at(src);
- if (Heap::InNewSpace(Memory::Object_at(dst))) {
+ if (InNewSpace(Memory::Object_at(dst))) {
marks |= page->GetRegionMaskForAddress(dst);
}
@@ -387,8 +396,13 @@ void Heap::MoveBlockToOldSpaceAndUpdateRegionMarks(Address dst,
}
+void Heap::ScavengePointer(HeapObject** p) {
+ ScavengeObject(p, *p);
+}
+
+
void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
- ASSERT(InFromSpace(object));
+ ASSERT(HEAP->InFromSpace(object));
// We use the first word (where the map pointer usually is) of a heap
// object to record the forwarding pointer. A forwarding pointer can
@@ -461,10 +475,15 @@ void Heap::SetLastScriptId(Object* last_script_id) {
roots_[kLastScriptIdRootIndex] = last_script_id;
}
+Isolate* Heap::isolate() {
+ return reinterpret_cast<Isolate*>(reinterpret_cast<intptr_t>(this) -
+ reinterpret_cast<size_t>(reinterpret_cast<Isolate*>(4)->heap()) + 4);
+}
+
#ifdef DEBUG
#define GC_GREEDY_CHECK() \
- if (FLAG_gc_greedy) v8::internal::Heap::GarbageCollectionGreedyCheck()
+ if (FLAG_gc_greedy) HEAP->GarbageCollectionGreedyCheck()
#else
#define GC_GREEDY_CHECK() { }
#endif
@@ -477,7 +496,7 @@ void Heap::SetLastScriptId(Object* last_script_id) {
// Warning: Do not use the identifiers __object__, __maybe_object__ or
// __scope__ in a call to this macro.
-#define CALL_AND_RETRY(FUNCTION_CALL, RETURN_VALUE, RETURN_EMPTY) \
+#define CALL_AND_RETRY(ISOLATE, FUNCTION_CALL, RETURN_VALUE, RETURN_EMPTY)\
do { \
GC_GREEDY_CHECK(); \
MaybeObject* __maybe_object__ = FUNCTION_CALL; \
@@ -487,16 +506,16 @@ void Heap::SetLastScriptId(Object* last_script_id) {
v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_0", true);\
} \
if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY; \
- Heap::CollectGarbage( \
- Failure::cast(__maybe_object__)->allocation_space()); \
+ ISOLATE->heap()->CollectGarbage(Failure::cast(__maybe_object__)-> \
+ allocation_space()); \
__maybe_object__ = FUNCTION_CALL; \
if (__maybe_object__->ToObject(&__object__)) RETURN_VALUE; \
if (__maybe_object__->IsOutOfMemory()) { \
v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_1", true);\
} \
if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY; \
- Counters::gc_last_resort_from_handles.Increment(); \
- Heap::CollectAllAvailableGarbage(); \
+ ISOLATE->counters()->gc_last_resort_from_handles()->Increment(); \
+ ISOLATE->heap()->CollectAllAvailableGarbage(); \
{ \
AlwaysAllocateScope __scope__; \
__maybe_object__ = FUNCTION_CALL; \
@@ -511,14 +530,17 @@ void Heap::SetLastScriptId(Object* last_script_id) {
} while (false)
-#define CALL_HEAP_FUNCTION(FUNCTION_CALL, TYPE) \
- CALL_AND_RETRY(FUNCTION_CALL, \
- return Handle<TYPE>(TYPE::cast(__object__)), \
+// TODO(isolates): cache isolate: either accept as a parameter or
+// set to some known symbol (__CUR_ISOLATE__?)
+#define CALL_HEAP_FUNCTION(ISOLATE, FUNCTION_CALL, TYPE) \
+ CALL_AND_RETRY(ISOLATE, \
+ FUNCTION_CALL, \
+ return Handle<TYPE>(TYPE::cast(__object__), ISOLATE), \
return Handle<TYPE>())
-#define CALL_HEAP_FUNCTION_VOID(FUNCTION_CALL) \
- CALL_AND_RETRY(FUNCTION_CALL, return, return)
+#define CALL_HEAP_FUNCTION_VOID(ISOLATE, FUNCTION_CALL) \
+ CALL_AND_RETRY(ISOLATE, FUNCTION_CALL, return, return)
#ifdef DEBUG
@@ -534,7 +556,7 @@ inline bool Heap::allow_allocation(bool new_state) {
void ExternalStringTable::AddString(String* string) {
ASSERT(string->IsExternalString());
- if (Heap::InNewSpace(string)) {
+ if (heap_->InNewSpace(string)) {
new_space_strings_.Add(string);
} else {
old_space_strings_.Add(string);
@@ -559,12 +581,12 @@ void ExternalStringTable::Iterate(ObjectVisitor* v) {
void ExternalStringTable::Verify() {
#ifdef DEBUG
for (int i = 0; i < new_space_strings_.length(); ++i) {
- ASSERT(Heap::InNewSpace(new_space_strings_[i]));
- ASSERT(new_space_strings_[i] != Heap::raw_unchecked_null_value());
+ ASSERT(heap_->InNewSpace(new_space_strings_[i]));
+ ASSERT(new_space_strings_[i] != HEAP->raw_unchecked_null_value());
}
for (int i = 0; i < old_space_strings_.length(); ++i) {
- ASSERT(!Heap::InNewSpace(old_space_strings_[i]));
- ASSERT(old_space_strings_[i] != Heap::raw_unchecked_null_value());
+ ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
+ ASSERT(old_space_strings_[i] != HEAP->raw_unchecked_null_value());
}
#endif
}
@@ -572,7 +594,7 @@ void ExternalStringTable::Verify() {
void ExternalStringTable::AddOldString(String* string) {
ASSERT(string->IsExternalString());
- ASSERT(!Heap::InNewSpace(string));
+ ASSERT(!heap_->InNewSpace(string));
old_space_strings_.Add(string);
}
@@ -582,6 +604,100 @@ void ExternalStringTable::ShrinkNewStrings(int position) {
Verify();
}
+
+void Heap::ClearInstanceofCache() {
+ set_instanceof_cache_function(the_hole_value());
+}
+
+
+Object* Heap::ToBoolean(bool condition) {
+ return condition ? true_value() : false_value();
+}
+
+
+void Heap::CompletelyClearInstanceofCache() {
+ set_instanceof_cache_map(the_hole_value());
+ set_instanceof_cache_function(the_hole_value());
+}
+
+
+MaybeObject* TranscendentalCache::Get(Type type, double input) {
+ SubCache* cache = caches_[type];
+ if (cache == NULL) {
+ caches_[type] = cache = new SubCache(type);
+ }
+ return cache->Get(input);
+}
+
+
+Address TranscendentalCache::cache_array_address() {
+ return reinterpret_cast<Address>(caches_);
+}
+
+
+double TranscendentalCache::SubCache::Calculate(double input) {
+ switch (type_) {
+ case ACOS:
+ return acos(input);
+ case ASIN:
+ return asin(input);
+ case ATAN:
+ return atan(input);
+ case COS:
+ return cos(input);
+ case EXP:
+ return exp(input);
+ case LOG:
+ return log(input);
+ case SIN:
+ return sin(input);
+ case TAN:
+ return tan(input);
+ default:
+ return 0.0; // Never happens.
+ }
+}
+
+
+MaybeObject* TranscendentalCache::SubCache::Get(double input) {
+ Converter c;
+ c.dbl = input;
+ int hash = Hash(c);
+ Element e = elements_[hash];
+ if (e.in[0] == c.integers[0] &&
+ e.in[1] == c.integers[1]) {
+ ASSERT(e.output != NULL);
+ isolate_->counters()->transcendental_cache_hit()->Increment();
+ return e.output;
+ }
+ double answer = Calculate(input);
+ isolate_->counters()->transcendental_cache_miss()->Increment();
+ Object* heap_number;
+ { MaybeObject* maybe_heap_number =
+ isolate_->heap()->AllocateHeapNumber(answer);
+ if (!maybe_heap_number->ToObject(&heap_number)) return maybe_heap_number;
+ }
+ elements_[hash].in[0] = c.integers[0];
+ elements_[hash].in[1] = c.integers[1];
+ elements_[hash].output = heap_number;
+ return heap_number;
+}
+
+
+Heap* _inline_get_heap_() {
+ return HEAP;
+}
+
+
+void MarkCompactCollector::SetMark(HeapObject* obj) {
+ tracer_->increment_marked_count();
+#ifdef DEBUG
+ UpdateLiveObjectCount(obj);
+#endif
+ obj->SetMark();
+}
+
+
} } // namespace v8::internal
#endif // V8_HEAP_INL_H_
diff --git a/src/heap-profiler.cc b/src/heap-profiler.cc
index 07b631fa..4815f826 100644
--- a/src/heap-profiler.cc
+++ b/src/heap-profiler.cc
@@ -72,14 +72,14 @@ JSObjectsCluster Clusterizer::Clusterize(HeapObject* obj, bool fine_grain) {
String* constructor = GetConstructorNameForHeapProfile(
JSObject::cast(js_obj));
// Differentiate Object and Array instances.
- if (fine_grain && (constructor == Heap::Object_symbol() ||
- constructor == Heap::Array_symbol())) {
+ if (fine_grain && (constructor == HEAP->Object_symbol() ||
+ constructor == HEAP->Array_symbol())) {
return JSObjectsCluster(constructor, obj);
} else {
return JSObjectsCluster(constructor);
}
} else if (obj->IsString()) {
- return JSObjectsCluster(Heap::String_symbol());
+ return JSObjectsCluster(HEAP->String_symbol());
} else if (obj->IsJSGlobalPropertyCell()) {
return JSObjectsCluster(JSObjectsCluster::GLOBAL_PROPERTY);
} else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) {
@@ -112,10 +112,10 @@ int Clusterizer::CalculateNetworkSize(JSObject* obj) {
int size = obj->Size();
// If 'properties' and 'elements' are non-empty (thus, non-shared),
// take their size into account.
- if (obj->properties() != Heap::empty_fixed_array()) {
+ if (obj->properties() != HEAP->empty_fixed_array()) {
size += obj->properties()->Size();
}
- if (obj->elements() != Heap::empty_fixed_array()) {
+ if (obj->elements() != HEAP->empty_fixed_array()) {
size += obj->elements()->Size();
}
// For functions, also account non-empty context and literals sizes.
@@ -174,7 +174,8 @@ class RetainersPrinter : public RetainerHeapProfile::Printer {
HeapStringAllocator allocator;
StringStream stream(&allocator);
cluster.Print(&stream);
- LOG(HeapSampleJSRetainersEvent(
+ LOG(ISOLATE,
+ HeapSampleJSRetainersEvent(
*(stream.ToCString()), *(retainers.ToCString())));
}
};
@@ -315,8 +316,6 @@ void RetainerTreeAggregator::Call(const JSObjectsCluster& cluster,
}
-HeapProfiler* HeapProfiler::singleton_ = NULL;
-
HeapProfiler::HeapProfiler()
: snapshots_(new HeapSnapshotsCollection()),
next_snapshot_uid_(1) {
@@ -327,12 +326,20 @@ HeapProfiler::~HeapProfiler() {
delete snapshots_;
}
+
+void HeapProfiler::ResetSnapshots() {
+ delete snapshots_;
+ snapshots_ = new HeapSnapshotsCollection();
+}
+
+
#endif // ENABLE_LOGGING_AND_PROFILING
void HeapProfiler::Setup() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (singleton_ == NULL) {
- singleton_ = new HeapProfiler();
+ Isolate* isolate = Isolate::Current();
+ if (isolate->heap_profiler() == NULL) {
+ isolate->set_heap_profiler(new HeapProfiler());
}
#endif
}
@@ -340,8 +347,9 @@ void HeapProfiler::Setup() {
void HeapProfiler::TearDown() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- delete singleton_;
- singleton_ = NULL;
+ Isolate* isolate = Isolate::Current();
+ delete isolate->heap_profiler();
+ isolate->set_heap_profiler(NULL);
#endif
}
@@ -351,16 +359,39 @@ void HeapProfiler::TearDown() {
HeapSnapshot* HeapProfiler::TakeSnapshot(const char* name,
int type,
v8::ActivityControl* control) {
- ASSERT(singleton_ != NULL);
- return singleton_->TakeSnapshotImpl(name, type, control);
+ ASSERT(Isolate::Current()->heap_profiler() != NULL);
+ return Isolate::Current()->heap_profiler()->TakeSnapshotImpl(name,
+ type,
+ control);
}
HeapSnapshot* HeapProfiler::TakeSnapshot(String* name,
int type,
v8::ActivityControl* control) {
- ASSERT(singleton_ != NULL);
- return singleton_->TakeSnapshotImpl(name, type, control);
+ ASSERT(Isolate::Current()->heap_profiler() != NULL);
+ return Isolate::Current()->heap_profiler()->TakeSnapshotImpl(name,
+ type,
+ control);
+}
+
+
+void HeapProfiler::DefineWrapperClass(
+ uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) {
+ ASSERT(class_id != v8::HeapProfiler::kPersistentHandleNoClassId);
+ if (wrapper_callbacks_.length() <= class_id) {
+ wrapper_callbacks_.AddBlock(
+ NULL, class_id - wrapper_callbacks_.length() + 1);
+ }
+ wrapper_callbacks_[class_id] = callback;
+}
+
+
+v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback(
+ uint16_t class_id, Object** wrapper) {
+ if (wrapper_callbacks_.length() <= class_id) return NULL;
+ return wrapper_callbacks_[class_id](
+ class_id, Utils::ToLocal(Handle<Object>(wrapper)));
}
@@ -373,13 +404,13 @@ HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name,
bool generation_completed = true;
switch (s_type) {
case HeapSnapshot::kFull: {
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
HeapSnapshotGenerator generator(result, control);
generation_completed = generator.GenerateSnapshot();
break;
}
case HeapSnapshot::kAggregated: {
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
AggregatedHeapSnapshot agg_snapshot;
AggregatedHeapSnapshotGenerator generator(&agg_snapshot);
generator.GenerateSnapshot();
@@ -401,31 +432,40 @@ HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name,
HeapSnapshot* HeapProfiler::TakeSnapshotImpl(String* name,
int type,
v8::ActivityControl* control) {
- return TakeSnapshotImpl(snapshots_->GetName(name), type, control);
+ return TakeSnapshotImpl(snapshots_->names()->GetName(name), type, control);
}
int HeapProfiler::GetSnapshotsCount() {
- ASSERT(singleton_ != NULL);
- return singleton_->snapshots_->snapshots()->length();
+ HeapProfiler* profiler = Isolate::Current()->heap_profiler();
+ ASSERT(profiler != NULL);
+ return profiler->snapshots_->snapshots()->length();
}
HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
- ASSERT(singleton_ != NULL);
- return singleton_->snapshots_->snapshots()->at(index);
+ HeapProfiler* profiler = Isolate::Current()->heap_profiler();
+ ASSERT(profiler != NULL);
+ return profiler->snapshots_->snapshots()->at(index);
}
HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) {
- ASSERT(singleton_ != NULL);
- return singleton_->snapshots_->GetSnapshot(uid);
+ HeapProfiler* profiler = Isolate::Current()->heap_profiler();
+ ASSERT(profiler != NULL);
+ return profiler->snapshots_->GetSnapshot(uid);
+}
+
+
+void HeapProfiler::DeleteAllSnapshots() {
+ HeapProfiler* profiler = Isolate::Current()->heap_profiler();
+ ASSERT(profiler != NULL);
+ profiler->ResetSnapshots();
}
void HeapProfiler::ObjectMoveEvent(Address from, Address to) {
- ASSERT(singleton_ != NULL);
- singleton_->snapshots_->ObjectMoveEvent(from, to);
+ snapshots_->ObjectMoveEvent(from, to);
}
@@ -443,7 +483,8 @@ void ConstructorHeapProfile::Call(const JSObjectsCluster& cluster,
HeapStringAllocator allocator;
StringStream stream(&allocator);
cluster.Print(&stream);
- LOG(HeapSampleJSConstructorEvent(*(stream.ToCString()),
+ LOG(ISOLATE,
+ HeapSampleJSConstructorEvent(*(stream.ToCString()),
number_and_size.number(),
number_and_size.bytes()));
}
@@ -662,7 +703,7 @@ RetainerHeapProfile::RetainerHeapProfile()
aggregator_(NULL) {
JSObjectsCluster roots(JSObjectsCluster::ROOTS);
ReferencesExtractor extractor(roots, this);
- Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG);
+ HEAP->IterateRoots(&extractor, VISIT_ONLY_STRONG);
}
@@ -732,15 +773,18 @@ static void PrintProducerStackTrace(Object* obj, void* trace) {
String* constructor = GetConstructorNameForHeapProfile(JSObject::cast(obj));
SmartPointer<char> s_name(
constructor->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
- LOG(HeapSampleJSProducerEvent(GetConstructorName(*s_name),
+ LOG(ISOLATE,
+ HeapSampleJSProducerEvent(GetConstructorName(*s_name),
reinterpret_cast<Address*>(trace)));
}
void HeapProfiler::WriteSample() {
- LOG(HeapSampleBeginEvent("Heap", "allocated"));
- LOG(HeapSampleStats(
- "Heap", "allocated", Heap::CommittedMemory(), Heap::SizeOfObjects()));
+ Isolate* isolate = Isolate::Current();
+ LOG(isolate, HeapSampleBeginEvent("Heap", "allocated"));
+ LOG(isolate,
+ HeapSampleStats(
+ "Heap", "allocated", HEAP->CommittedMemory(), HEAP->SizeOfObjects()));
AggregatedHeapSnapshot snapshot;
AggregatedHeapSnapshotGenerator generator(&snapshot);
@@ -751,7 +795,8 @@ void HeapProfiler::WriteSample() {
i <= AggregatedHeapSnapshotGenerator::kAllStringsType;
++i) {
if (info[i].bytes() > 0) {
- LOG(HeapSampleItemEvent(info[i].name(), info[i].number(),
+ LOG(isolate,
+ HeapSampleItemEvent(info[i].name(), info[i].number(),
info[i].bytes()));
}
}
@@ -759,10 +804,10 @@ void HeapProfiler::WriteSample() {
snapshot.js_cons_profile()->PrintStats();
snapshot.js_retainer_profile()->PrintStats();
- GlobalHandles::IterateWeakRoots(PrintProducerStackTrace,
- StackWeakReferenceCallback);
+ isolate->global_handles()->IterateWeakRoots(PrintProducerStackTrace,
+ StackWeakReferenceCallback);
- LOG(HeapSampleEndEvent("Heap", "allocated"));
+ LOG(isolate, HeapSampleEndEvent("Heap", "allocated"));
}
@@ -872,7 +917,8 @@ class AllocatingConstructorHeapProfileIterator {
const NumberAndSizeInfo& number_and_size) {
const char* name = cluster.GetSpecialCaseName();
if (name == NULL) {
- name = snapshot_->collection()->GetFunctionName(cluster.constructor());
+ name = snapshot_->collection()->names()->GetFunctionName(
+ cluster.constructor());
}
AddEntryFromAggregatedSnapshot(snapshot_,
root_child_index_,
@@ -1013,7 +1059,8 @@ class AggregatedRetainerTreeAllocator : public HeapEntriesAllocator {
JSObjectsCluster cluster = HeapObjectAsCluster(obj);
const char* name = cluster.GetSpecialCaseName();
if (name == NULL) {
- name = snapshot_->collection()->GetFunctionName(cluster.constructor());
+ name = snapshot_->collection()->names()->GetFunctionName(
+ cluster.constructor());
}
return AddEntryFromAggregatedSnapshot(
snapshot_, root_child_index_, HeapEntry::kObject, name,
@@ -1094,8 +1141,6 @@ void AggregatedHeapSnapshotGenerator::FillHeapSnapshot(HeapSnapshot* snapshot) {
}
-bool ProducerHeapProfile::can_log_ = false;
-
void ProducerHeapProfile::Setup() {
can_log_ = true;
}
@@ -1115,10 +1160,10 @@ void ProducerHeapProfile::DoRecordJSObjectAllocation(Object* obj) {
stack[i++] = it.frame()->pc();
}
stack[i] = NULL;
- Handle<Object> handle = GlobalHandles::Create(obj);
- GlobalHandles::MakeWeak(handle.location(),
- static_cast<void*>(stack.start()),
- StackWeakReferenceCallback);
+ Handle<Object> handle = isolate_->global_handles()->Create(obj);
+ isolate_->global_handles()->MakeWeak(handle.location(),
+ static_cast<void*>(stack.start()),
+ StackWeakReferenceCallback);
}
diff --git a/src/heap-profiler.h b/src/heap-profiler.h
index 20ba457c..89a2e8a5 100644
--- a/src/heap-profiler.h
+++ b/src/heap-profiler.h
@@ -28,6 +28,7 @@
#ifndef V8_HEAP_PROFILER_H_
#define V8_HEAP_PROFILER_H_
+#include "isolate.h"
#include "zone-inl.h"
namespace v8 {
@@ -38,14 +39,15 @@ namespace internal {
class HeapSnapshot;
class HeapSnapshotsCollection;
-#define HEAP_PROFILE(Call) \
- do { \
- if (v8::internal::HeapProfiler::is_profiling()) { \
- v8::internal::HeapProfiler::Call; \
- } \
+#define HEAP_PROFILE(heap, call) \
+ do { \
+ v8::internal::HeapProfiler* profiler = heap->isolate()->heap_profiler(); \
+ if (profiler != NULL && profiler->is_profiling()) { \
+ profiler->call; \
+ } \
} while (false)
#else
-#define HEAP_PROFILE(Call) ((void) 0)
+#define HEAP_PROFILE(heap, call) ((void) 0)
#endif // ENABLE_LOGGING_AND_PROFILING
// The HeapProfiler writes data to the log files, which can be postprocessed
@@ -65,11 +67,17 @@ class HeapProfiler {
static int GetSnapshotsCount();
static HeapSnapshot* GetSnapshot(int index);
static HeapSnapshot* FindSnapshot(unsigned uid);
+ static void DeleteAllSnapshots();
- static void ObjectMoveEvent(Address from, Address to);
+ void ObjectMoveEvent(Address from, Address to);
- static INLINE(bool is_profiling()) {
- return singleton_ != NULL && singleton_->snapshots_->is_tracking_objects();
+ void DefineWrapperClass(
+ uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback);
+
+ v8::RetainedObjectInfo* ExecuteWrapperClassCallback(uint16_t class_id,
+ Object** wrapper);
+ INLINE(bool is_profiling()) {
+ return snapshots_->is_tracking_objects();
}
// Obsolete interface.
@@ -85,11 +93,12 @@ class HeapProfiler {
HeapSnapshot* TakeSnapshotImpl(String* name,
int type,
v8::ActivityControl* control);
+ void ResetSnapshots();
HeapSnapshotsCollection* snapshots_;
unsigned next_snapshot_uid_;
+ List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_;
- static HeapProfiler* singleton_;
#endif // ENABLE_LOGGING_AND_PROFILING
};
@@ -148,10 +157,10 @@ class JSObjectsCluster BASE_EMBEDDED {
// We use symbols that are illegal JS identifiers to identify special cases.
// Their actual value is irrelevant for us.
switch (special) {
- case ROOTS: return Heap::result_symbol();
- case GLOBAL_PROPERTY: return Heap::code_symbol();
- case CODE: return Heap::arguments_shadow_symbol();
- case SELF: return Heap::catch_var_symbol();
+ case ROOTS: return HEAP->result_symbol();
+ case GLOBAL_PROPERTY: return HEAP->code_symbol();
+ case CODE: return HEAP->arguments_shadow_symbol();
+ case SELF: return HEAP->catch_var_symbol();
default:
UNREACHABLE();
return NULL;
@@ -341,7 +350,6 @@ class AggregatedHeapSnapshot {
class HeapEntriesMap;
class HeapEntriesAllocator;
-class HeapSnapshot;
class AggregatedHeapSnapshotGenerator {
public:
@@ -362,16 +370,23 @@ class AggregatedHeapSnapshotGenerator {
};
-class ProducerHeapProfile : public AllStatic {
+class ProducerHeapProfile {
public:
- static void Setup();
- static void RecordJSObjectAllocation(Object* obj) {
+ void Setup();
+ void RecordJSObjectAllocation(Object* obj) {
if (FLAG_log_producers) DoRecordJSObjectAllocation(obj);
}
private:
- static void DoRecordJSObjectAllocation(Object* obj);
- static bool can_log_;
+ ProducerHeapProfile() : can_log_(false) { }
+
+ void DoRecordJSObjectAllocation(Object* obj);
+ Isolate* isolate_;
+ bool can_log_;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(ProducerHeapProfile);
};
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/src/heap.cc b/src/heap.cc
index 34ab9aaf..5d1a66e2 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -49,119 +49,114 @@
#include "regexp-macro-assembler.h"
#include "arm/regexp-macro-assembler-arm.h"
#endif
-
+#if V8_TARGET_ARCH_MIPS && !V8_INTERPRETED_REGEXP
+#include "regexp-macro-assembler.h"
+#include "mips/regexp-macro-assembler-mips.h"
+#endif
namespace v8 {
namespace internal {
-String* Heap::hidden_symbol_;
-Object* Heap::roots_[Heap::kRootListLength];
-Object* Heap::global_contexts_list_;
-
-
-NewSpace Heap::new_space_;
-OldSpace* Heap::old_pointer_space_ = NULL;
-OldSpace* Heap::old_data_space_ = NULL;
-OldSpace* Heap::code_space_ = NULL;
-MapSpace* Heap::map_space_ = NULL;
-CellSpace* Heap::cell_space_ = NULL;
-LargeObjectSpace* Heap::lo_space_ = NULL;
-
static const intptr_t kMinimumPromotionLimit = 2 * MB;
static const intptr_t kMinimumAllocationLimit = 8 * MB;
-intptr_t Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit;
-intptr_t Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit;
-int Heap::old_gen_exhausted_ = false;
+static Mutex* gc_initializer_mutex = OS::CreateMutex();
-int Heap::amount_of_external_allocated_memory_ = 0;
-int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0;
+Heap::Heap()
+ : isolate_(NULL),
// semispace_size_ should be a power of 2 and old_generation_size_ should be
// a multiple of Page::kPageSize.
#if defined(ANDROID)
-static const int default_max_semispace_size_ = 2*MB;
-intptr_t Heap::max_old_generation_size_ = 192*MB;
-int Heap::initial_semispace_size_ = 128*KB;
-intptr_t Heap::code_range_size_ = 0;
-intptr_t Heap::max_executable_size_ = max_old_generation_size_;
+ reserved_semispace_size_(2*MB),
+ max_semispace_size_(2*MB),
+ initial_semispace_size_(128*KB),
+ max_old_generation_size_(192*MB),
+ max_executable_size_(max_old_generation_size_),
+ code_range_size_(0),
#elif defined(V8_TARGET_ARCH_X64)
-static const int default_max_semispace_size_ = 16*MB;
-intptr_t Heap::max_old_generation_size_ = 1*GB;
-int Heap::initial_semispace_size_ = 1*MB;
-intptr_t Heap::code_range_size_ = 512*MB;
-intptr_t Heap::max_executable_size_ = 256*MB;
+ reserved_semispace_size_(16*MB),
+ max_semispace_size_(16*MB),
+ initial_semispace_size_(1*MB),
+ max_old_generation_size_(1*GB),
+ max_executable_size_(256*MB),
+ code_range_size_(512*MB),
#else
-static const int default_max_semispace_size_ = 8*MB;
-intptr_t Heap::max_old_generation_size_ = 512*MB;
-int Heap::initial_semispace_size_ = 512*KB;
-intptr_t Heap::code_range_size_ = 0;
-intptr_t Heap::max_executable_size_ = 128*MB;
+ reserved_semispace_size_(8*MB),
+ max_semispace_size_(8*MB),
+ initial_semispace_size_(512*KB),
+ max_old_generation_size_(512*MB),
+ max_executable_size_(128*MB),
+ code_range_size_(0),
#endif
-
-// Allow build-time customization of the max semispace size. Building
-// V8 with snapshots and a non-default max semispace size is much
-// easier if you can define it as part of the build environment.
-#if defined(V8_MAX_SEMISPACE_SIZE)
-int Heap::max_semispace_size_ = V8_MAX_SEMISPACE_SIZE;
-#else
-int Heap::max_semispace_size_ = default_max_semispace_size_;
-#endif
-
-// The snapshot semispace size will be the default semispace size if
-// snapshotting is used and will be the requested semispace size as
-// set up by ConfigureHeap otherwise.
-int Heap::reserved_semispace_size_ = Heap::max_semispace_size_;
-
-List<Heap::GCPrologueCallbackPair> Heap::gc_prologue_callbacks_;
-List<Heap::GCEpilogueCallbackPair> Heap::gc_epilogue_callbacks_;
-
-GCCallback Heap::global_gc_prologue_callback_ = NULL;
-GCCallback Heap::global_gc_epilogue_callback_ = NULL;
-HeapObjectCallback Heap::gc_safe_size_of_old_object_ = NULL;
-
// Variables set based on semispace_size_ and old_generation_size_ in
-// ConfigureHeap.
-
+// ConfigureHeap (survived_since_last_expansion_, external_allocation_limit_)
// Will be 4 * reserved_semispace_size_ to ensure that young
// generation can be aligned to its size.
-int Heap::survived_since_last_expansion_ = 0;
-intptr_t Heap::external_allocation_limit_ = 0;
-
-Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
-
-int Heap::mc_count_ = 0;
-int Heap::ms_count_ = 0;
-unsigned int Heap::gc_count_ = 0;
-
-GCTracer* Heap::tracer_ = NULL;
-
-int Heap::unflattened_strings_length_ = 0;
-
-int Heap::always_allocate_scope_depth_ = 0;
-int Heap::linear_allocation_scope_depth_ = 0;
-int Heap::contexts_disposed_ = 0;
-
-int Heap::young_survivors_after_last_gc_ = 0;
-int Heap::high_survival_rate_period_length_ = 0;
-double Heap::survival_rate_ = 0;
-Heap::SurvivalRateTrend Heap::previous_survival_rate_trend_ = Heap::STABLE;
-Heap::SurvivalRateTrend Heap::survival_rate_trend_ = Heap::STABLE;
-
+ survived_since_last_expansion_(0),
+ always_allocate_scope_depth_(0),
+ linear_allocation_scope_depth_(0),
+ contexts_disposed_(0),
+ new_space_(this),
+ old_pointer_space_(NULL),
+ old_data_space_(NULL),
+ code_space_(NULL),
+ map_space_(NULL),
+ cell_space_(NULL),
+ lo_space_(NULL),
+ gc_state_(NOT_IN_GC),
+ mc_count_(0),
+ ms_count_(0),
+ gc_count_(0),
+ unflattened_strings_length_(0),
#ifdef DEBUG
-bool Heap::allocation_allowed_ = true;
-
-int Heap::allocation_timeout_ = 0;
-bool Heap::disallow_allocation_failure_ = false;
+ allocation_allowed_(true),
+ allocation_timeout_(0),
+ disallow_allocation_failure_(false),
+ debug_utils_(NULL),
#endif // DEBUG
+ old_gen_promotion_limit_(kMinimumPromotionLimit),
+ old_gen_allocation_limit_(kMinimumAllocationLimit),
+ external_allocation_limit_(0),
+ amount_of_external_allocated_memory_(0),
+ amount_of_external_allocated_memory_at_last_global_gc_(0),
+ old_gen_exhausted_(false),
+ hidden_symbol_(NULL),
+ global_gc_prologue_callback_(NULL),
+ global_gc_epilogue_callback_(NULL),
+ gc_safe_size_of_old_object_(NULL),
+ tracer_(NULL),
+ young_survivors_after_last_gc_(0),
+ high_survival_rate_period_length_(0),
+ survival_rate_(0),
+ previous_survival_rate_trend_(Heap::STABLE),
+ survival_rate_trend_(Heap::STABLE),
+ max_gc_pause_(0),
+ max_alive_after_gc_(0),
+ min_in_mutator_(kMaxInt),
+ alive_after_last_gc_(0),
+ last_gc_end_timestamp_(0.0),
+ page_watermark_invalidated_mark_(1 << Page::WATERMARK_INVALIDATED),
+ number_idle_notifications_(0),
+ last_idle_notification_gc_count_(0),
+ last_idle_notification_gc_count_init_(false),
+ configured_(false),
+ is_safe_to_read_maps_(true) {
+ // Allow build-time customization of the max semispace size. Building
+ // V8 with snapshots and a non-default max semispace size is much
+ // easier if you can define it as part of the build environment.
+#if defined(V8_MAX_SEMISPACE_SIZE)
+ max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE;
+#endif
+
+ memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
+ global_contexts_list_ = NULL;
+ mark_compact_collector_.heap_ = this;
+ external_string_table_.heap_ = this;
+}
-intptr_t GCTracer::alive_after_last_gc_ = 0;
-double GCTracer::last_gc_end_timestamp_ = 0.0;
-int GCTracer::max_gc_pause_ = 0;
-intptr_t GCTracer::max_alive_after_gc_ = 0;
-int GCTracer::min_in_mutator_ = kMaxInt;
intptr_t Heap::Capacity() {
if (!HasBeenSetup()) return 0;
@@ -190,7 +185,7 @@ intptr_t Heap::CommittedMemory() {
intptr_t Heap::CommittedMemoryExecutable() {
if (!HasBeenSetup()) return 0;
- return MemoryAllocator::SizeExecutable();
+ return isolate()->memory_allocator()->SizeExecutable();
}
@@ -217,8 +212,8 @@ bool Heap::HasBeenSetup() {
int Heap::GcSafeSizeOfOldObject(HeapObject* object) {
- ASSERT(!Heap::InNewSpace(object)); // Code only works for old objects.
- ASSERT(!MarkCompactCollector::are_map_pointers_encoded());
+ ASSERT(!HEAP->InNewSpace(object)); // Code only works for old objects.
+ ASSERT(!HEAP->mark_compact_collector()->are_map_pointers_encoded());
MapWord map_word = object->map_word();
map_word.ClearMark();
map_word.ClearOverflow();
@@ -227,8 +222,8 @@ int Heap::GcSafeSizeOfOldObject(HeapObject* object) {
int Heap::GcSafeSizeOfOldObjectWithEncodedMap(HeapObject* object) {
- ASSERT(!Heap::InNewSpace(object)); // Code only works for old objects.
- ASSERT(MarkCompactCollector::are_map_pointers_encoded());
+ ASSERT(!HEAP->InNewSpace(object)); // Code only works for old objects.
+ ASSERT(HEAP->mark_compact_collector()->are_map_pointers_encoded());
uint32_t marker = Memory::uint32_at(object->address());
if (marker == MarkCompactCollector::kSingleFreeEncoding) {
return kIntSize;
@@ -236,7 +231,7 @@ int Heap::GcSafeSizeOfOldObjectWithEncodedMap(HeapObject* object) {
return Memory::int_at(object->address() + kIntSize);
} else {
MapWord map_word = object->map_word();
- Address map_address = map_word.DecodeMapAddress(Heap::map_space());
+ Address map_address = map_word.DecodeMapAddress(HEAP->map_space());
Map* map = reinterpret_cast<Map*>(HeapObject::FromAddress(map_address));
return object->SizeFromMap(map);
}
@@ -246,19 +241,20 @@ int Heap::GcSafeSizeOfOldObjectWithEncodedMap(HeapObject* object) {
GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) {
// Is global GC requested?
if (space != NEW_SPACE || FLAG_gc_global) {
- Counters::gc_compactor_caused_by_request.Increment();
+ isolate_->counters()->gc_compactor_caused_by_request()->Increment();
return MARK_COMPACTOR;
}
// Is enough data promoted to justify a global GC?
if (OldGenerationPromotionLimitReached()) {
- Counters::gc_compactor_caused_by_promoted_data.Increment();
+ isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment();
return MARK_COMPACTOR;
}
// Have allocation in OLD and LO failed?
if (old_gen_exhausted_) {
- Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
+ isolate_->counters()->
+ gc_compactor_caused_by_oldspace_exhaustion()->Increment();
return MARK_COMPACTOR;
}
@@ -271,8 +267,9 @@ GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) {
// and does not count available bytes already in the old space or code
// space. Undercounting is safe---we may get an unrequested full GC when
// a scavenge would have succeeded.
- if (MemoryAllocator::MaxAvailable() <= new_space_.Size()) {
- Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
+ if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) {
+ isolate_->counters()->
+ gc_compactor_caused_by_oldspace_exhaustion()->Increment();
return MARK_COMPACTOR;
}
@@ -317,8 +314,8 @@ void Heap::PrintShortHeapStatistics() {
if (!FLAG_trace_gc_verbose) return;
PrintF("Memory allocator, used: %8" V8_PTR_PREFIX "d"
", available: %8" V8_PTR_PREFIX "d\n",
- MemoryAllocator::Size(),
- MemoryAllocator::Available());
+ isolate_->memory_allocator()->Size(),
+ isolate_->memory_allocator()->Available());
PrintF("New space, used: %8" V8_PTR_PREFIX "d"
", available: %8" V8_PTR_PREFIX "d\n",
Heap::new_space_.Size(),
@@ -383,7 +380,7 @@ void Heap::ReportStatisticsAfterGC() {
void Heap::GarbageCollectionPrologue() {
- TranscendentalCache::Clear();
+ isolate_->transcendental_cache()->Clear();
ClearJSFunctionResultCaches();
gc_count_++;
unflattened_strings_length_ = 0;
@@ -424,21 +421,24 @@ void Heap::GarbageCollectionEpilogue() {
Verify();
}
- if (FLAG_print_global_handles) GlobalHandles::Print();
+ if (FLAG_print_global_handles) isolate_->global_handles()->Print();
if (FLAG_print_handles) PrintHandles();
if (FLAG_gc_verbose) Print();
if (FLAG_code_stats) ReportCodeStatistics("After GC");
#endif
- Counters::alive_after_last_gc.Set(static_cast<int>(SizeOfObjects()));
+ isolate_->counters()->alive_after_last_gc()->Set(
+ static_cast<int>(SizeOfObjects()));
- Counters::symbol_table_capacity.Set(symbol_table()->Capacity());
- Counters::number_of_symbols.Set(symbol_table()->NumberOfElements());
+ isolate_->counters()->symbol_table_capacity()->Set(
+ symbol_table()->Capacity());
+ isolate_->counters()->number_of_symbols()->Set(
+ symbol_table()->NumberOfElements());
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
ReportStatisticsAfterGC();
#endif
#ifdef ENABLE_DEBUGGER_SUPPORT
- Debug::AfterGarbageCollection();
+ isolate_->debug()->AfterGarbageCollection();
#endif
}
@@ -447,9 +447,9 @@ void Heap::CollectAllGarbage(bool force_compaction) {
// Since we are ignoring the return value, the exact choice of space does
// not matter, so long as we do not specify NEW_SPACE, which would not
// cause a full GC.
- MarkCompactCollector::SetForceCompaction(force_compaction);
+ mark_compact_collector_.SetForceCompaction(force_compaction);
CollectGarbage(OLD_POINTER_SPACE);
- MarkCompactCollector::SetForceCompaction(false);
+ mark_compact_collector_.SetForceCompaction(false);
}
@@ -457,7 +457,7 @@ void Heap::CollectAllAvailableGarbage() {
// Since we are ignoring the return value, the exact choice of space does
// not matter, so long as we do not specify NEW_SPACE, which would not
// cause a full GC.
- MarkCompactCollector::SetForceCompaction(true);
+ mark_compact_collector()->SetForceCompaction(true);
// Major GC would invoke weak handle callbacks on weakly reachable
// handles, but won't collect weakly reachable objects until next
@@ -473,13 +473,13 @@ void Heap::CollectAllAvailableGarbage() {
break;
}
}
- MarkCompactCollector::SetForceCompaction(false);
+ mark_compact_collector()->SetForceCompaction(false);
}
bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
// The VM is in the GC state until exiting this function.
- VMState state(GC);
+ VMState state(isolate_, GC);
#ifdef DEBUG
// Reset the allocation timeout to the GC interval, but make sure to
@@ -492,7 +492,7 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
bool next_gc_likely_to_collect_more = false;
- { GCTracer tracer;
+ { GCTracer tracer(this);
GarbageCollectionPrologue();
// The GC count was incremented in the prologue. Tell the tracer about
// it.
@@ -502,8 +502,8 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
tracer.set_collector(collector);
HistogramTimer* rate = (collector == SCAVENGER)
- ? &Counters::gc_scavenger
- : &Counters::gc_compactor;
+ ? isolate_->counters()->gc_scavenger()
+ : isolate_->counters()->gc_compactor();
rate->Start();
next_gc_likely_to_collect_more =
PerformGarbageCollection(collector, &tracer);
@@ -522,7 +522,7 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
void Heap::PerformScavenge() {
- GCTracer tracer;
+ GCTracer tracer(this);
PerformGarbageCollection(SCAVENGER, &tracer);
}
@@ -531,7 +531,6 @@ void Heap::PerformScavenge() {
// Helper class for verifying the symbol table.
class SymbolTableVerifier : public ObjectVisitor {
public:
- SymbolTableVerifier() { }
void VisitPointers(Object** start, Object** end) {
// Visit all HeapObject pointers in [start, end).
for (Object** p = start; p < end; p++) {
@@ -548,7 +547,7 @@ class SymbolTableVerifier : public ObjectVisitor {
static void VerifySymbolTable() {
#ifdef DEBUG
SymbolTableVerifier verifier;
- Heap::symbol_table()->IterateElements(&verifier);
+ HEAP->symbol_table()->IterateElements(&verifier);
#endif // DEBUG
}
@@ -633,7 +632,7 @@ void Heap::EnsureFromSpaceIsCommitted() {
void Heap::ClearJSFunctionResultCaches() {
- if (Bootstrapper::IsActive()) return;
+ if (isolate_->bootstrapper()->IsActive()) return;
Object* context = global_contexts_list_;
while (!context->IsUndefined()) {
@@ -651,8 +650,9 @@ void Heap::ClearJSFunctionResultCaches() {
}
+
void Heap::ClearNormalizedMapCaches() {
- if (Bootstrapper::IsActive()) return;
+ if (isolate_->bootstrapper()->IsActive()) return;
Object* context = global_contexts_list_;
while (!context->IsUndefined()) {
@@ -709,7 +709,7 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
bool next_gc_likely_to_collect_more = false;
if (collector != SCAVENGER) {
- PROFILE(CodeMovingGCEvent());
+ PROFILE(isolate_, CodeMovingGCEvent());
}
VerifySymbolTable();
@@ -768,13 +768,13 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
UpdateSurvivalRateTrend(start_new_space_size);
}
- Counters::objs_since_last_young.Set(0);
+ isolate_->counters()->objs_since_last_young()->Set(0);
if (collector == MARK_COMPACTOR) {
DisableAssertNoAllocation allow_allocation;
GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
next_gc_likely_to_collect_more =
- GlobalHandles::PostGarbageCollectionProcessing();
+ isolate_->global_handles()->PostGarbageCollectionProcessing();
}
// Update relocatables.
@@ -808,11 +808,11 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
void Heap::MarkCompact(GCTracer* tracer) {
gc_state_ = MARK_COMPACT;
- LOG(ResourceEvent("markcompact", "begin"));
+ LOG(isolate_, ResourceEvent("markcompact", "begin"));
- MarkCompactCollector::Prepare(tracer);
+ mark_compact_collector_.Prepare(tracer);
- bool is_compacting = MarkCompactCollector::IsCompacting();
+ bool is_compacting = mark_compact_collector_.IsCompacting();
if (is_compacting) {
mc_count_++;
@@ -823,15 +823,17 @@ void Heap::MarkCompact(GCTracer* tracer) {
MarkCompactPrologue(is_compacting);
- MarkCompactCollector::CollectGarbage();
+ is_safe_to_read_maps_ = false;
+ mark_compact_collector_.CollectGarbage();
+ is_safe_to_read_maps_ = true;
- LOG(ResourceEvent("markcompact", "end"));
+ LOG(isolate_, ResourceEvent("markcompact", "end"));
gc_state_ = NOT_IN_GC;
Shrink();
- Counters::objs_since_last_full.Set(0);
+ isolate_->counters()->objs_since_last_full()->Set(0);
contexts_disposed_ = 0;
}
@@ -840,11 +842,11 @@ void Heap::MarkCompact(GCTracer* tracer) {
void Heap::MarkCompactPrologue(bool is_compacting) {
// At any old GC clear the keyed lookup cache to enable collection of unused
// maps.
- KeyedLookupCache::Clear();
- ContextSlotCache::Clear();
- DescriptorLookupCache::Clear();
+ isolate_->keyed_lookup_cache()->Clear();
+ isolate_->context_slot_cache()->Clear();
+ isolate_->descriptor_lookup_cache()->Clear();
- CompilationCache::MarkCompactPrologue();
+ isolate_->compilation_cache()->MarkCompactPrologue();
CompletelyClearInstanceofCache();
@@ -868,6 +870,7 @@ Object* Heap::FindCodeObject(Address a) {
// Helper class for copying HeapObjects
class ScavengeVisitor: public ObjectVisitor {
public:
+ explicit ScavengeVisitor(Heap* heap) : heap_(heap) {}
void VisitPointer(Object** p) { ScavengePointer(p); }
@@ -879,48 +882,15 @@ class ScavengeVisitor: public ObjectVisitor {
private:
void ScavengePointer(Object** p) {
Object* object = *p;
- if (!Heap::InNewSpace(object)) return;
+ if (!heap_->InNewSpace(object)) return;
Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
reinterpret_cast<HeapObject*>(object));
}
-};
-
-
-// A queue of objects promoted during scavenge. Each object is accompanied
-// by it's size to avoid dereferencing a map pointer for scanning.
-class PromotionQueue {
- public:
- void Initialize(Address start_address) {
- front_ = rear_ = reinterpret_cast<intptr_t*>(start_address);
- }
-
- bool is_empty() { return front_ <= rear_; }
- void insert(HeapObject* target, int size) {
- *(--rear_) = reinterpret_cast<intptr_t>(target);
- *(--rear_) = size;
- // Assert no overflow into live objects.
- ASSERT(reinterpret_cast<Address>(rear_) >= Heap::new_space()->top());
- }
-
- void remove(HeapObject** target, int* size) {
- *target = reinterpret_cast<HeapObject*>(*(--front_));
- *size = static_cast<int>(*(--front_));
- // Assert no underflow.
- ASSERT(front_ >= rear_);
- }
-
- private:
- // The front of the queue is higher in memory than the rear.
- intptr_t* front_;
- intptr_t* rear_;
+ Heap* heap_;
};
-// Shared state read by the scavenge collector and set by ScavengeObject.
-static PromotionQueue promotion_queue;
-
-
#ifdef DEBUG
// Visitor class to verify pointers in code or data space do not point into
// new space.
@@ -929,7 +899,7 @@ class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
void VisitPointers(Object** start, Object**end) {
for (Object** current = start; current < end; current++) {
if ((*current)->IsHeapObject()) {
- ASSERT(!Heap::InNewSpace(HeapObject::cast(*current)));
+ ASSERT(!HEAP->InNewSpace(HeapObject::cast(*current)));
}
}
}
@@ -940,12 +910,12 @@ static void VerifyNonPointerSpacePointers() {
// Verify that there are no pointers to new space in spaces where we
// do not expect them.
VerifyNonPointerSpacePointersVisitor v;
- HeapObjectIterator code_it(Heap::code_space());
+ HeapObjectIterator code_it(HEAP->code_space());
for (HeapObject* object = code_it.next();
object != NULL; object = code_it.next())
object->Iterate(&v);
- HeapObjectIterator data_it(Heap::old_data_space());
+ HeapObjectIterator data_it(HEAP->old_data_space());
for (HeapObject* object = data_it.next();
object != NULL; object = data_it.next())
object->Iterate(&v);
@@ -971,7 +941,7 @@ void Heap::Scavenge() {
gc_state_ = SCAVENGE;
- Page::FlipMeaningOfInvalidatedWatermarkFlag();
+ Page::FlipMeaningOfInvalidatedWatermarkFlag(this);
#ifdef DEBUG
VerifyPageWatermarkValidity(old_pointer_space_, ALL_VALID);
VerifyPageWatermarkValidity(map_space_, ALL_VALID);
@@ -986,10 +956,10 @@ void Heap::Scavenge() {
map_space_->FlushTopPageWatermark();
// Implements Cheney's copying algorithm
- LOG(ResourceEvent("scavenge", "begin"));
+ LOG(isolate_, ResourceEvent("scavenge", "begin"));
// Clear descriptor cache.
- DescriptorLookupCache::Clear();
+ isolate_->descriptor_lookup_cache()->Clear();
// Used for updating survived_since_last_expansion_ at function end.
intptr_t survived_watermark = PromotedSpaceSize();
@@ -1019,16 +989,17 @@ void Heap::Scavenge() {
// frees up its size in bytes from the top of the new space, and
// objects are at least one pointer in size.
Address new_space_front = new_space_.ToSpaceLow();
- promotion_queue.Initialize(new_space_.ToSpaceHigh());
+ promotion_queue_.Initialize(new_space_.ToSpaceHigh());
- ScavengeVisitor scavenge_visitor;
+ is_safe_to_read_maps_ = false;
+ ScavengeVisitor scavenge_visitor(this);
// Copy roots.
IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
// Copy objects reachable from the old generation. By definition,
// there are no intergenerational pointers in code or data spaces.
IterateDirtyRegions(old_pointer_space_,
- &IteratePointersInDirtyRegion,
+ &Heap::IteratePointersInDirtyRegion,
&ScavengePointer,
WATERMARK_CAN_BE_INVALID);
@@ -1060,10 +1031,12 @@ void Heap::Scavenge() {
&UpdateNewSpaceReferenceInExternalStringTableEntry);
LiveObjectList::UpdateReferencesForScavengeGC();
- RuntimeProfiler::UpdateSamplesAfterScavenge();
+ isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
ASSERT(new_space_front == new_space_.top());
+ is_safe_to_read_maps_ = true;
+
// Set age mark.
new_space_.set_age_mark(new_space_.top());
@@ -1071,18 +1044,19 @@ void Heap::Scavenge() {
IncrementYoungSurvivorsCounter(static_cast<int>(
(PromotedSpaceSize() - survived_watermark) + new_space_.Size()));
- LOG(ResourceEvent("scavenge", "end"));
+ LOG(isolate_, ResourceEvent("scavenge", "end"));
gc_state_ = NOT_IN_GC;
}
-String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Object** p) {
+String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
+ Object** p) {
MapWord first_word = HeapObject::cast(*p)->map_word();
if (!first_word.IsForwardingAddress()) {
// Unreachable external string can be finalized.
- FinalizeExternalString(String::cast(*p));
+ heap->FinalizeExternalString(String::cast(*p));
return NULL;
}
@@ -1093,48 +1067,49 @@ String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Object** p) {
void Heap::UpdateNewSpaceReferencesInExternalStringTable(
ExternalStringTableUpdaterCallback updater_func) {
- ExternalStringTable::Verify();
+ external_string_table_.Verify();
- if (ExternalStringTable::new_space_strings_.is_empty()) return;
+ if (external_string_table_.new_space_strings_.is_empty()) return;
- Object** start = &ExternalStringTable::new_space_strings_[0];
- Object** end = start + ExternalStringTable::new_space_strings_.length();
+ Object** start = &external_string_table_.new_space_strings_[0];
+ Object** end = start + external_string_table_.new_space_strings_.length();
Object** last = start;
for (Object** p = start; p < end; ++p) {
- ASSERT(Heap::InFromSpace(*p));
- String* target = updater_func(p);
+ ASSERT(InFromSpace(*p));
+ String* target = updater_func(this, p);
if (target == NULL) continue;
ASSERT(target->IsExternalString());
- if (Heap::InNewSpace(target)) {
+ if (InNewSpace(target)) {
// String is still in new space. Update the table entry.
*last = target;
++last;
} else {
// String got promoted. Move it to the old string list.
- ExternalStringTable::AddOldString(target);
+ external_string_table_.AddOldString(target);
}
}
ASSERT(last <= end);
- ExternalStringTable::ShrinkNewStrings(static_cast<int>(last - start));
+ external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
}
-static Object* ProcessFunctionWeakReferences(Object* function,
+static Object* ProcessFunctionWeakReferences(Heap* heap,
+ Object* function,
WeakObjectRetainer* retainer) {
- Object* head = Heap::undefined_value();
+ Object* head = heap->undefined_value();
JSFunction* tail = NULL;
Object* candidate = function;
- while (!candidate->IsUndefined()) {
+ while (candidate != heap->undefined_value()) {
// Check whether to keep the candidate in the list.
JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate);
Object* retain = retainer->RetainAs(candidate);
if (retain != NULL) {
- if (head->IsUndefined()) {
+ if (head == heap->undefined_value()) {
// First element in the list.
head = candidate_function;
} else {
@@ -1151,7 +1126,7 @@ static Object* ProcessFunctionWeakReferences(Object* function,
// Terminate the list if there is one or more elements.
if (tail != NULL) {
- tail->set_next_function_link(Heap::undefined_value());
+ tail->set_next_function_link(heap->undefined_value());
}
return head;
@@ -1162,18 +1137,19 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
Object* head = undefined_value();
Context* tail = NULL;
Object* candidate = global_contexts_list_;
- while (!candidate->IsUndefined()) {
+ while (candidate != undefined_value()) {
// Check whether to keep the candidate in the list.
Context* candidate_context = reinterpret_cast<Context*>(candidate);
Object* retain = retainer->RetainAs(candidate);
if (retain != NULL) {
- if (head->IsUndefined()) {
+ if (head == undefined_value()) {
// First element in the list.
head = candidate_context;
} else {
// Subsequent elements in the list.
ASSERT(tail != NULL);
- tail->set_unchecked(Context::NEXT_CONTEXT_LINK,
+ tail->set_unchecked(this,
+ Context::NEXT_CONTEXT_LINK,
candidate_context,
UPDATE_WRITE_BARRIER);
}
@@ -1183,9 +1159,11 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
// Process the weak list of optimized functions for the context.
Object* function_list_head =
ProcessFunctionWeakReferences(
+ this,
candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
retainer);
- candidate_context->set_unchecked(Context::OPTIMIZED_FUNCTIONS_LIST,
+ candidate_context->set_unchecked(this,
+ Context::OPTIMIZED_FUNCTIONS_LIST,
function_list_head,
UPDATE_WRITE_BARRIER);
}
@@ -1195,21 +1173,22 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
// Terminate the list if there is one or more elements.
if (tail != NULL) {
- tail->set_unchecked(Context::NEXT_CONTEXT_LINK,
+ tail->set_unchecked(this,
+ Context::NEXT_CONTEXT_LINK,
Heap::undefined_value(),
UPDATE_WRITE_BARRIER);
}
// Update the head of the list of contexts.
- Heap::global_contexts_list_ = head;
+ global_contexts_list_ = head;
}
class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> {
public:
- static inline void VisitPointer(Object** p) {
+ static inline void VisitPointer(Heap* heap, Object** p) {
Object* object = *p;
- if (!Heap::InNewSpace(object)) return;
+ if (!heap->InNewSpace(object)) return;
Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
reinterpret_cast<HeapObject*>(object));
}
@@ -1230,10 +1209,10 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
}
// Promote and process all the to-be-promoted objects.
- while (!promotion_queue.is_empty()) {
+ while (!promotion_queue_.is_empty()) {
HeapObject* target;
int size;
- promotion_queue.remove(&target, &size);
+ promotion_queue_.remove(&target, &size);
// Promoted object might be already partially visited
// during dirty regions iteration. Thus we search specificly
@@ -1303,7 +1282,7 @@ class ScavengingVisitor : public StaticVisitorBase {
enum SizeRestriction { SMALL, UNKNOWN_SIZE };
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
- static void RecordCopiedObject(HeapObject* obj) {
+ static void RecordCopiedObject(Heap* heap, HeapObject* obj) {
bool should_record = false;
#ifdef DEBUG
should_record = FLAG_heap_stats;
@@ -1312,10 +1291,10 @@ class ScavengingVisitor : public StaticVisitorBase {
should_record = should_record || FLAG_log_gc;
#endif
if (should_record) {
- if (Heap::new_space()->Contains(obj)) {
- Heap::new_space()->RecordAllocation(obj);
+ if (heap->new_space()->Contains(obj)) {
+ heap->new_space()->RecordAllocation(obj);
} else {
- Heap::new_space()->RecordPromotion(obj);
+ heap->new_space()->RecordPromotion(obj);
}
}
}
@@ -1324,24 +1303,28 @@ class ScavengingVisitor : public StaticVisitorBase {
// Helper function used by CopyObject to copy a source object to an
// allocated target object and update the forwarding pointer in the source
// object. Returns the target object.
- INLINE(static HeapObject* MigrateObject(HeapObject* source,
+ INLINE(static HeapObject* MigrateObject(Heap* heap,
+ HeapObject* source,
HeapObject* target,
int size)) {
// Copy the content of source to target.
- Heap::CopyBlock(target->address(), source->address(), size);
+ heap->CopyBlock(target->address(), source->address(), size);
// Set the forwarding address.
source->set_map_word(MapWord::FromForwardingAddress(target));
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
// Update NewSpace stats if necessary.
- RecordCopiedObject(target);
+ RecordCopiedObject(heap, target);
#endif
- HEAP_PROFILE(ObjectMoveEvent(source->address(), target->address()));
+ HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address()));
#if defined(ENABLE_LOGGING_AND_PROFILING)
- if (Logger::is_logging() || CpuProfiler::is_profiling()) {
+ Isolate* isolate = heap->isolate();
+ if (isolate->logger()->is_logging() ||
+ isolate->cpu_profiler()->is_profiling()) {
if (target->IsSharedFunctionInfo()) {
- PROFILE(SFIMoveEvent(source->address(), target->address()));
+ PROFILE(isolate, SharedFunctionInfoMoveEvent(
+ source->address(), target->address()));
}
}
#endif
@@ -1358,36 +1341,37 @@ class ScavengingVisitor : public StaticVisitorBase {
(object_size <= Page::kMaxHeapObjectSize));
ASSERT(object->Size() == object_size);
- if (Heap::ShouldBePromoted(object->address(), object_size)) {
+ Heap* heap = map->heap();
+ if (heap->ShouldBePromoted(object->address(), object_size)) {
MaybeObject* maybe_result;
if ((size_restriction != SMALL) &&
(object_size > Page::kMaxHeapObjectSize)) {
- maybe_result = Heap::lo_space()->AllocateRawFixedArray(object_size);
+ maybe_result = heap->lo_space()->AllocateRawFixedArray(object_size);
} else {
if (object_contents == DATA_OBJECT) {
- maybe_result = Heap::old_data_space()->AllocateRaw(object_size);
+ maybe_result = heap->old_data_space()->AllocateRaw(object_size);
} else {
- maybe_result = Heap::old_pointer_space()->AllocateRaw(object_size);
+ maybe_result = heap->old_pointer_space()->AllocateRaw(object_size);
}
}
Object* result = NULL; // Initialization to please compiler.
if (maybe_result->ToObject(&result)) {
HeapObject* target = HeapObject::cast(result);
- *slot = MigrateObject(object, target, object_size);
+ *slot = MigrateObject(heap, object , target, object_size);
if (object_contents == POINTER_OBJECT) {
- promotion_queue.insert(target, object_size);
+ heap->promotion_queue()->insert(target, object_size);
}
- Heap::tracer()->increment_promoted_objects_size(object_size);
+ heap->tracer()->increment_promoted_objects_size(object_size);
return;
}
}
Object* result =
- Heap::new_space()->AllocateRaw(object_size)->ToObjectUnchecked();
- *slot = MigrateObject(object, HeapObject::cast(result), object_size);
+ heap->new_space()->AllocateRaw(object_size)->ToObjectUnchecked();
+ *slot = MigrateObject(heap, object, HeapObject::cast(result), object_size);
return;
}
@@ -1438,13 +1422,14 @@ class ScavengingVisitor : public StaticVisitorBase {
HeapObject* object) {
ASSERT(IsShortcutCandidate(map->instance_type()));
- if (ConsString::cast(object)->unchecked_second() == Heap::empty_string()) {
+ if (ConsString::cast(object)->unchecked_second() ==
+ map->heap()->empty_string()) {
HeapObject* first =
HeapObject::cast(ConsString::cast(object)->unchecked_first());
*slot = first;
- if (!Heap::InNewSpace(first)) {
+ if (!map->heap()->InNewSpace(first)) {
object->set_map_word(MapWord::FromForwardingAddress(first));
return;
}
@@ -1495,7 +1480,7 @@ VisitorDispatchTable<ScavengingVisitor::Callback> ScavengingVisitor::table_;
void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
- ASSERT(InFromSpace(object));
+ ASSERT(HEAP->InFromSpace(object));
MapWord first_word = object->map_word();
ASSERT(!first_word.IsForwardingAddress());
Map* map = first_word.ToMap();
@@ -1503,11 +1488,6 @@ void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
}
-void Heap::ScavengePointer(HeapObject** p) {
- ScavengeObject(p, *p);
-}
-
-
MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
int instance_size) {
Object* result;
@@ -1519,9 +1499,8 @@ MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
- reinterpret_cast<Map*>(result)->
- set_visitor_id(
- StaticVisitorBase::GetVisitorId(instance_type, instance_size));
+ reinterpret_cast<Map*>(result)->set_visitor_id(
+ StaticVisitorBase::GetVisitorId(instance_type, instance_size));
reinterpret_cast<Map*>(result)->set_inobject_properties(0);
reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
@@ -1630,6 +1609,7 @@ bool Heap::CreateInitialMaps() {
if (!maybe_obj->ToObject(&obj)) return false;
}
set_null_value(obj);
+ Oddball::cast(obj)->set_kind(Oddball::kNull);
// Allocate the empty descriptor array.
{ MaybeObject* maybe_obj = AllocateEmptyFixedArray();
@@ -1707,10 +1687,10 @@ bool Heap::CreateInitialMaps() {
set_empty_byte_array(ByteArray::cast(obj));
{ MaybeObject* maybe_obj =
- AllocateMap(PIXEL_ARRAY_TYPE, PixelArray::kAlignedSize);
+ AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize);
if (!maybe_obj->ToObject(&obj)) return false;
}
- set_pixel_array_map(Map::cast(obj));
+ set_external_pixel_array_map(Map::cast(obj));
{ MaybeObject* maybe_obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
ExternalArray::kAlignedSize);
@@ -1821,7 +1801,7 @@ bool Heap::CreateInitialMaps() {
}
set_message_object_map(Map::cast(obj));
- ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
+ ASSERT(!InNewSpace(empty_fixed_array()));
return true;
}
@@ -1874,12 +1854,13 @@ MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
MaybeObject* Heap::CreateOddball(const char* to_string,
- Object* to_number) {
+ Object* to_number,
+ byte kind) {
Object* result;
{ MaybeObject* maybe_result = Allocate(oddball_map(), OLD_DATA_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- return Oddball::cast(result)->Initialize(to_string, to_number);
+ return Oddball::cast(result)->Initialize(to_string, to_number, kind);
}
@@ -1891,7 +1872,7 @@ bool Heap::CreateApiObjects() {
}
set_neander_map(Map::cast(obj));
- { MaybeObject* maybe_obj = Heap::AllocateJSObjectFromMap(neander_map());
+ { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
if (!maybe_obj->ToObject(&obj)) return false;
}
Object* elements;
@@ -1906,20 +1887,6 @@ bool Heap::CreateApiObjects() {
}
-void Heap::CreateCEntryStub() {
- CEntryStub stub(1);
- set_c_entry_code(*stub.GetCode());
-}
-
-
-#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
-void Heap::CreateRegExpCEntryStub() {
- RegExpCEntryStub stub;
- set_re_c_entry_code(*stub.GetCode());
-}
-#endif
-
-
void Heap::CreateJSEntryStub() {
JSEntryStub stub;
set_js_entry_code(*stub.GetCode());
@@ -1932,14 +1899,6 @@ void Heap::CreateJSConstructEntryStub() {
}
-#if V8_TARGET_ARCH_ARM
-void Heap::CreateDirectCEntryStub() {
- DirectCEntryStub stub;
- set_direct_c_entry_code(*stub.GetCode());
-}
-#endif
-
-
void Heap::CreateFixedStubs() {
// Here we create roots for fixed stubs. They are needed at GC
// for cooking and uncooking (check out frames.cc).
@@ -1947,22 +1906,15 @@ void Heap::CreateFixedStubs() {
// stub cache for these stubs.
HandleScope scope;
// gcc-4.4 has problem generating correct code of following snippet:
- // { CEntryStub stub;
- // c_entry_code_ = *stub.GetCode();
+ // { JSEntryStub stub;
+ // js_entry_code_ = *stub.GetCode();
// }
- // { DebuggerStatementStub stub;
- // debugger_statement_code_ = *stub.GetCode();
+ // { JSConstructEntryStub stub;
+ // js_construct_entry_code_ = *stub.GetCode();
// }
// To workaround the problem, make separate functions without inlining.
- Heap::CreateCEntryStub();
Heap::CreateJSEntryStub();
Heap::CreateJSConstructEntryStub();
-#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
- Heap::CreateRegExpCEntryStub();
-#endif
-#if V8_TARGET_ARCH_ARM
- Heap::CreateDirectCEntryStub();
-#endif
}
@@ -1985,6 +1937,7 @@ bool Heap::CreateInitialObjects() {
if (!maybe_obj->ToObject(&obj)) return false;
}
set_undefined_value(obj);
+ Oddball::cast(obj)->set_kind(Oddball::kUndefined);
ASSERT(!InNewSpace(undefined_value()));
// Allocate initial symbol table.
@@ -2004,39 +1957,50 @@ bool Heap::CreateInitialObjects() {
// Allocate the null_value
{ MaybeObject* maybe_obj =
- Oddball::cast(null_value())->Initialize("null", Smi::FromInt(0));
+ Oddball::cast(null_value())->Initialize("null",
+ Smi::FromInt(0),
+ Oddball::kNull);
if (!maybe_obj->ToObject(&obj)) return false;
}
- { MaybeObject* maybe_obj = CreateOddball("true", Smi::FromInt(1));
+ { MaybeObject* maybe_obj = CreateOddball("true",
+ Smi::FromInt(1),
+ Oddball::kTrue);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_true_value(obj);
- { MaybeObject* maybe_obj = CreateOddball("false", Smi::FromInt(0));
+ { MaybeObject* maybe_obj = CreateOddball("false",
+ Smi::FromInt(0),
+ Oddball::kFalse);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_false_value(obj);
- { MaybeObject* maybe_obj = CreateOddball("hole", Smi::FromInt(-1));
+ { MaybeObject* maybe_obj = CreateOddball("hole",
+ Smi::FromInt(-1),
+ Oddball::kTheHole);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_the_hole_value(obj);
{ MaybeObject* maybe_obj = CreateOddball("arguments_marker",
- Smi::FromInt(-4));
+ Smi::FromInt(-4),
+ Oddball::kArgumentMarker);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_arguments_marker(obj);
- { MaybeObject* maybe_obj =
- CreateOddball("no_interceptor_result_sentinel", Smi::FromInt(-2));
+ { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel",
+ Smi::FromInt(-2),
+ Oddball::kOther);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_no_interceptor_result_sentinel(obj);
- { MaybeObject* maybe_obj =
- CreateOddball("termination_exception", Smi::FromInt(-3));
+ { MaybeObject* maybe_obj = CreateOddball("termination_exception",
+ Smi::FromInt(-3),
+ Oddball::kOther);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_termination_exception(obj);
@@ -2098,7 +2062,8 @@ bool Heap::CreateInitialObjects() {
{ MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions);
if (!maybe_obj->ToObject(&obj)) return false;
}
- { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(obj);
+ { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this,
+ obj);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_intrinsic_function_names(StringDictionary::cast(obj));
@@ -2118,20 +2083,20 @@ bool Heap::CreateInitialObjects() {
}
set_natives_source_cache(FixedArray::cast(obj));
- // Handling of script id generation is in Factory::NewScript.
+ // Handling of script id generation is in FACTORY->NewScript.
set_last_script_id(undefined_value());
// Initialize keyed lookup cache.
- KeyedLookupCache::Clear();
+ isolate_->keyed_lookup_cache()->Clear();
// Initialize context slot cache.
- ContextSlotCache::Clear();
+ isolate_->context_slot_cache()->Clear();
// Initialize descriptor cache.
- DescriptorLookupCache::Clear();
+ isolate_->descriptor_lookup_cache()->Clear();
// Initialize compilation cache.
- CompilationCache::Clear();
+ isolate_->compilation_cache()->Clear();
return true;
}
@@ -2155,7 +2120,7 @@ void Heap::FlushNumberStringCache() {
// Flush the number to string cache.
int len = number_string_cache()->length();
for (int i = 0; i < len; i++) {
- number_string_cache()->set_undefined(i);
+ number_string_cache()->set_undefined(this, i);
}
}
@@ -2207,7 +2172,7 @@ void Heap::SetNumberStringCache(Object* number, String* string) {
MaybeObject* Heap::NumberToString(Object* number,
bool check_number_string_cache) {
- Counters::number_to_string_runtime.Increment();
+ isolate_->counters()->number_to_string_runtime()->Increment();
if (check_number_string_cache) {
Object* cached = GetNumberStringCache(number);
if (cached != undefined_value()) {
@@ -2257,6 +2222,8 @@ Heap::RootListIndex Heap::RootIndexForExternalArrayType(
return kExternalUnsignedIntArrayMapRootIndex;
case kExternalFloatArray:
return kExternalFloatArrayMapRootIndex;
+ case kExternalPixelArray:
+ return kExternalPixelArrayMapRootIndex;
default:
UNREACHABLE();
return kUndefinedValueRootIndex;
@@ -2308,10 +2275,11 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
SharedFunctionInfo* share = SharedFunctionInfo::cast(result);
share->set_name(name);
- Code* illegal = Builtins::builtin(Builtins::Illegal);
+ Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal);
share->set_code(illegal);
share->set_scope_info(SerializedScopeInfo::Empty());
- Code* construct_stub = Builtins::builtin(Builtins::JSConstructStubGeneric);
+ Code* construct_stub = isolate_->builtins()->builtin(
+ Builtins::kJSConstructStubGeneric);
share->set_construct_stub(construct_stub);
share->set_expected_nof_properties(0);
share->set_length(0);
@@ -2369,20 +2337,21 @@ static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString(
+ Heap* heap,
uint32_t c1,
uint32_t c2) {
String* symbol;
// Numeric strings have a different hash algorithm not known by
// LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
- Heap::symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
+ heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
return symbol;
// Now we know the length is 2, we might as well make use of that fact
// when building the new string.
} else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this
ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateRawAsciiString(2);
+ { MaybeObject* maybe_result = heap->AllocateRawAsciiString(2);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
char* dest = SeqAsciiString::cast(result)->GetChars();
@@ -2391,7 +2360,7 @@ MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString(
return result;
} else {
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateRawTwoByteString(2);
+ { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
uc16* dest = SeqTwoByteString::cast(result)->GetChars();
@@ -2421,7 +2390,7 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) {
if (length == 2) {
unsigned c1 = first->Get(0);
unsigned c2 = second->Get(0);
- return MakeOrFindTwoCharacterString(c1, c2);
+ return MakeOrFindTwoCharacterString(this, c1, c2);
}
bool first_is_ascii = first->IsAsciiRepresentation();
@@ -2431,7 +2400,7 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) {
// Make sure that an out of memory exception is thrown if the length
// of the new cons string is too large.
if (length > String::kMaxLength || length < 0) {
- Top::context()->mark_out_of_memory();
+ isolate()->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
@@ -2443,7 +2412,7 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) {
is_ascii_data_in_two_byte_string =
first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
if (is_ascii_data_in_two_byte_string) {
- Counters::string_add_runtime_ext_to_ascii.Increment();
+ isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
}
}
@@ -2484,6 +2453,7 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) {
char* dest = SeqAsciiString::cast(result)->GetChars();
String::WriteToFlat(first, dest, 0, first_length);
String::WriteToFlat(second, dest + first_length, 0, second_length);
+ isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
return result;
}
@@ -2525,15 +2495,14 @@ MaybeObject* Heap::AllocateSubString(String* buffer,
int length = end - start;
if (length == 1) {
- return Heap::LookupSingleCharacterStringFromCode(
- buffer->Get(start));
+ return LookupSingleCharacterStringFromCode(buffer->Get(start));
} else if (length == 2) {
// Optimization for 2-byte strings often used as keys in a decompression
// dictionary. Check whether we already have the string in the symbol
// table to prevent creation of many unneccesary strings.
unsigned c1 = buffer->Get(start);
unsigned c2 = buffer->Get(start + 1);
- return MakeOrFindTwoCharacterString(c1, c2);
+ return MakeOrFindTwoCharacterString(this, c1, c2);
}
// Make an attempt to flatten the buffer to reduce access time.
@@ -2565,7 +2534,7 @@ MaybeObject* Heap::AllocateExternalStringFromAscii(
ExternalAsciiString::Resource* resource) {
size_t length = resource->length();
if (length > static_cast<size_t>(String::kMaxLength)) {
- Top::context()->mark_out_of_memory();
+ isolate()->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
@@ -2588,7 +2557,7 @@ MaybeObject* Heap::AllocateExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource) {
size_t length = resource->length();
if (length > static_cast<size_t>(String::kMaxLength)) {
- Top::context()->mark_out_of_memory();
+ isolate()->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
@@ -2598,7 +2567,7 @@ MaybeObject* Heap::AllocateExternalStringFromTwoByte(
bool is_ascii = length <= kAsciiCheckLengthLimit &&
String::IsAscii(resource->data(), static_cast<int>(length));
Map* map = is_ascii ?
- Heap::external_string_with_ascii_data_map() : Heap::external_string_map();
+ external_string_with_ascii_data_map() : external_string_map();
Object* result;
{ MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result;
@@ -2615,8 +2584,8 @@ MaybeObject* Heap::AllocateExternalStringFromTwoByte(
MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
if (code <= String::kMaxAsciiCharCode) {
- Object* value = Heap::single_character_string_cache()->get(code);
- if (value != Heap::undefined_value()) return value;
+ Object* value = single_character_string_cache()->get(code);
+ if (value != undefined_value()) return value;
char buffer[1];
buffer[0] = static_cast<char>(code);
@@ -2624,12 +2593,12 @@ MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
MaybeObject* maybe_result = LookupSymbol(Vector<const char>(buffer, 1));
if (!maybe_result->ToObject(&result)) return maybe_result;
- Heap::single_character_string_cache()->set(code, result);
+ single_character_string_cache()->set(code, result);
return result;
}
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateRawTwoByteString(1);
+ { MaybeObject* maybe_result = AllocateRawTwoByteString(1);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
String* answer = String::cast(result);
@@ -2691,24 +2660,6 @@ void Heap::CreateFillerObjectAt(Address addr, int size) {
}
-MaybeObject* Heap::AllocatePixelArray(int length,
- uint8_t* external_pointer,
- PretenureFlag pretenure) {
- AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
- Object* result;
- { MaybeObject* maybe_result =
- AllocateRaw(PixelArray::kAlignedSize, space, OLD_DATA_SPACE);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
-
- reinterpret_cast<PixelArray*>(result)->set_map(pixel_array_map());
- reinterpret_cast<PixelArray*>(result)->set_length(length);
- reinterpret_cast<PixelArray*>(result)->set_external_pointer(external_pointer);
-
- return result;
-}
-
-
MaybeObject* Heap::AllocateExternalArray(int length,
ExternalArrayType array_type,
void* external_pointer,
@@ -2733,7 +2684,8 @@ MaybeObject* Heap::AllocateExternalArray(int length,
MaybeObject* Heap::CreateCode(const CodeDesc& desc,
Code::Flags flags,
- Handle<Object> self_reference) {
+ Handle<Object> self_reference,
+ bool immovable) {
// Allocate ByteArray before the Code object, so that we do not risk
// leaving uninitialized Code object (and breaking the heap).
Object* reloc_info;
@@ -2741,12 +2693,14 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc,
if (!maybe_reloc_info->ToObject(&reloc_info)) return maybe_reloc_info;
}
- // Compute size
+ // Compute size.
int body_size = RoundUp(desc.instr_size, kObjectAlignment);
int obj_size = Code::SizeFor(body_size);
ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment));
MaybeObject* maybe_result;
- if (obj_size > MaxObjectSizeInPagedSpace()) {
+ // Large code objects and code objects which should stay at a fixed address
+ // are allocated in large object space.
+ if (obj_size > MaxObjectSizeInPagedSpace() || immovable) {
maybe_result = lo_space_->AllocateRawCode(obj_size);
} else {
maybe_result = code_space_->AllocateRaw(obj_size);
@@ -2758,7 +2712,8 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc,
// Initialize the object
HeapObject::cast(result)->set_map(code_map());
Code* code = Code::cast(result);
- ASSERT(!CodeRange::exists() || CodeRange::contains(code->address()));
+ ASSERT(!isolate_->code_range()->exists() ||
+ isolate_->code_range()->contains(code->address()));
code->set_instruction_size(desc.instr_size);
code->set_relocation_info(ByteArray::cast(reloc_info));
code->set_flags(flags);
@@ -2804,7 +2759,8 @@ MaybeObject* Heap::CopyCode(Code* code) {
CopyBlock(new_addr, old_addr, obj_size);
// Relocate the copy.
Code* new_code = Code::cast(result);
- ASSERT(!CodeRange::exists() || CodeRange::contains(code->address()));
+ ASSERT(!isolate_->code_range()->exists() ||
+ isolate_->code_range()->contains(code->address()));
new_code->Relocate(new_addr - old_addr);
return new_code;
}
@@ -2853,7 +2809,8 @@ MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
// Relocate the copy.
- ASSERT(!CodeRange::exists() || CodeRange::contains(code->address()));
+ ASSERT(!isolate_->code_range()->exists() ||
+ isolate_->code_range()->contains(code->address()));
new_code->Relocate(new_addr - old_addr);
#ifdef DEBUG
@@ -2877,7 +2834,7 @@ MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
}
HeapObject::cast(result)->set_map(map);
#ifdef ENABLE_LOGGING_AND_PROFILING
- ProducerHeapProfile::RecordJSObjectAllocation(result);
+ isolate_->producer_heap_profile()->RecordJSObjectAllocation(result);
#endif
return result;
}
@@ -2939,22 +2896,34 @@ MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
// To get fast allocation and map sharing for arguments objects we
// allocate them based on an arguments boilerplate.
+ JSObject* boilerplate;
+ int arguments_object_size;
+ bool strict_mode_callee = callee->IsJSFunction() &&
+ JSFunction::cast(callee)->shared()->strict_mode();
+ if (strict_mode_callee) {
+ boilerplate =
+ isolate()->context()->global_context()->
+ strict_mode_arguments_boilerplate();
+ arguments_object_size = kArgumentsObjectSizeStrict;
+ } else {
+ boilerplate =
+ isolate()->context()->global_context()->arguments_boilerplate();
+ arguments_object_size = kArgumentsObjectSize;
+ }
+
// This calls Copy directly rather than using Heap::AllocateRaw so we
// duplicate the check here.
ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
- JSObject* boilerplate =
- Top::context()->global_context()->arguments_boilerplate();
-
// Check that the size of the boilerplate matches our
// expectations. The ArgumentsAccessStub::GenerateNewObject relies
// on the size being a known constant.
- ASSERT(kArgumentsObjectSize == boilerplate->map()->instance_size());
+ ASSERT(arguments_object_size == boilerplate->map()->instance_size());
// Do the allocation.
Object* result;
{ MaybeObject* maybe_result =
- AllocateRaw(kArgumentsObjectSize, NEW_SPACE, OLD_POINTER_SPACE);
+ AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
@@ -2963,14 +2932,17 @@ MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
// barrier here.
CopyBlock(HeapObject::cast(result)->address(),
boilerplate->address(),
- kArgumentsObjectSize);
+ JSObject::kHeaderSize);
- // Set the two properties.
- JSObject::cast(result)->InObjectPropertyAtPut(arguments_callee_index,
- callee);
- JSObject::cast(result)->InObjectPropertyAtPut(arguments_length_index,
+ // Set the length property.
+ JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex,
Smi::FromInt(length),
SKIP_WRITE_BARRIER);
+ // Set the callee property for non-strict mode arguments object only.
+ if (!strict_mode_callee) {
+ JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex,
+ callee);
+ }
// Check the state of the object
ASSERT(JSObject::cast(result)->HasFastProperties());
@@ -3002,8 +2974,7 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
int instance_size = fun->shared()->CalculateInstanceSize();
int in_object_properties = fun->shared()->CalculateInObjectProperties();
Object* map_obj;
- { MaybeObject* maybe_map_obj =
- Heap::AllocateMap(JS_OBJECT_TYPE, instance_size);
+ { MaybeObject* maybe_map_obj = AllocateMap(JS_OBJECT_TYPE, instance_size);
if (!maybe_map_obj->ToObject(&map_obj)) return maybe_map_obj;
}
@@ -3199,7 +3170,7 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
PropertyDetails d =
PropertyDetails(details.attributes(), CALLBACKS, details.index());
Object* value = descs->GetCallbacksObject(i);
- { MaybeObject* maybe_value = Heap::AllocateJSGlobalPropertyCell(value);
+ { MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
if (!maybe_value->ToObject(&value)) return maybe_value;
}
@@ -3225,7 +3196,7 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
// Setup the global object as a normalized object.
global->set_map(new_map);
- global->map()->set_instance_descriptors(Heap::empty_descriptor_array());
+ global->map()->set_instance_descriptors(empty_descriptor_array());
global->set_properties(dictionary);
// Make sure result is a global object with properties in dictionary.
@@ -3264,7 +3235,7 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) {
{ MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
if (!maybe_clone->ToObject(&clone)) return maybe_clone;
}
- ASSERT(Heap::InNewSpace(clone));
+ ASSERT(InNewSpace(clone));
// Since we know the clone is allocated in new space, we can copy
// the contents without worrying about updating the write barrier.
CopyBlock(HeapObject::cast(clone)->address(),
@@ -3294,7 +3265,7 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) {
}
// Return the new clone.
#ifdef ENABLE_LOGGING_AND_PROFILING
- ProducerHeapProfile::RecordJSObjectAllocation(clone);
+ isolate_->producer_heap_profile()->RecordJSObjectAllocation(clone);
#endif
return clone;
}
@@ -3350,7 +3321,7 @@ MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
// Count the number of characters in the UTF-8 string and check if
// it is an ASCII string.
Access<ScannerConstants::Utf8Decoder>
- decoder(ScannerConstants::utf8_decoder());
+ decoder(isolate_->scanner_constants()->utf8_decoder());
decoder->Reset(string.start(), string.length());
int chars = 0;
while (decoder->has_more()) {
@@ -3403,12 +3374,24 @@ Map* Heap::SymbolMapForString(String* string) {
// Find the corresponding symbol map for strings.
Map* map = string->map();
- if (map == ascii_string_map()) return ascii_symbol_map();
- if (map == string_map()) return symbol_map();
- if (map == cons_string_map()) return cons_symbol_map();
- if (map == cons_ascii_string_map()) return cons_ascii_symbol_map();
- if (map == external_string_map()) return external_symbol_map();
- if (map == external_ascii_string_map()) return external_ascii_symbol_map();
+ if (map == ascii_string_map()) {
+ return ascii_symbol_map();
+ }
+ if (map == string_map()) {
+ return symbol_map();
+ }
+ if (map == cons_string_map()) {
+ return cons_symbol_map();
+ }
+ if (map == cons_ascii_string_map()) {
+ return cons_ascii_symbol_map();
+ }
+ if (map == external_string_map()) {
+ return external_symbol_map();
+ }
+ if (map == external_ascii_string_map()) {
+ return external_ascii_symbol_map();
+ }
if (map == external_string_with_ascii_data_map()) {
return external_symbol_with_ascii_data_map();
}
@@ -3582,7 +3565,7 @@ MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
{ MaybeObject* maybe_obj = AllocateRawFixedArray(len);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- if (Heap::InNewSpace(obj)) {
+ if (InNewSpace(obj)) {
HeapObject* dst = HeapObject::cast(obj);
dst->set_map(map);
CopyBlock(dst->address() + kPointerSize,
@@ -3614,7 +3597,7 @@ MaybeObject* Heap::AllocateFixedArray(int length) {
array->set_map(fixed_array_map());
array->set_length(length);
// Initialize body.
- ASSERT(!Heap::InNewSpace(undefined_value()));
+ ASSERT(!InNewSpace(undefined_value()));
MemsetPointer(array->data_start(), undefined_value(), length);
return result;
}
@@ -3645,20 +3628,21 @@ MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
+ Heap* heap,
int length,
PretenureFlag pretenure,
Object* filler) {
ASSERT(length >= 0);
- ASSERT(Heap::empty_fixed_array()->IsFixedArray());
- if (length == 0) return Heap::empty_fixed_array();
+ ASSERT(heap->empty_fixed_array()->IsFixedArray());
+ if (length == 0) return heap->empty_fixed_array();
- ASSERT(!Heap::InNewSpace(filler));
+ ASSERT(!heap->InNewSpace(filler));
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateRawFixedArray(length, pretenure);
+ { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- HeapObject::cast(result)->set_map(Heap::fixed_array_map());
+ HeapObject::cast(result)->set_map(heap->fixed_array_map());
FixedArray* array = FixedArray::cast(result);
array->set_length(length);
MemsetPointer(array->data_start(), filler, length);
@@ -3667,13 +3651,19 @@ MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
- return AllocateFixedArrayWithFiller(length, pretenure, undefined_value());
+ return AllocateFixedArrayWithFiller(this,
+ length,
+ pretenure,
+ undefined_value());
}
MaybeObject* Heap::AllocateFixedArrayWithHoles(int length,
PretenureFlag pretenure) {
- return AllocateFixedArrayWithFiller(length, pretenure, the_hole_value());
+ return AllocateFixedArrayWithFiller(this,
+ length,
+ pretenure,
+ the_hole_value());
}
@@ -3693,7 +3683,7 @@ MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateFixedArray(length, pretenure);
+ { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
reinterpret_cast<HeapObject*>(result)->set_map(hash_table_map());
@@ -3705,7 +3695,7 @@ MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
MaybeObject* Heap::AllocateGlobalContext() {
Object* result;
{ MaybeObject* maybe_result =
- Heap::AllocateFixedArray(Context::GLOBAL_CONTEXT_SLOTS);
+ AllocateFixedArray(Context::GLOBAL_CONTEXT_SLOTS);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Context* context = reinterpret_cast<Context*>(result);
@@ -3719,7 +3709,7 @@ MaybeObject* Heap::AllocateGlobalContext() {
MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateFixedArray(length);
+ { MaybeObject* maybe_result = AllocateFixedArray(length);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Context* context = reinterpret_cast<Context*>(result);
@@ -3740,12 +3730,12 @@ MaybeObject* Heap::AllocateWithContext(Context* previous,
JSObject* extension,
bool is_catch_context) {
Object* result;
- { MaybeObject* maybe_result =
- Heap::AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
+ { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Context* context = reinterpret_cast<Context*>(result);
- context->set_map(is_catch_context ? catch_context_map() : context_map());
+ context->set_map(is_catch_context ? catch_context_map() :
+ context_map());
context->set_closure(previous->closure());
context->set_fcontext(previous->fcontext());
context->set_previous(previous);
@@ -3761,7 +3751,8 @@ MaybeObject* Heap::AllocateWithContext(Context* previous,
MaybeObject* Heap::AllocateStruct(InstanceType type) {
Map* map;
switch (type) {
-#define MAKE_CASE(NAME, Name, name) case NAME##_TYPE: map = name##_map(); break;
+#define MAKE_CASE(NAME, Name, name) \
+ case NAME##_TYPE: map = name##_map(); break;
STRUCT_LIST(MAKE_CASE)
#undef MAKE_CASE
default:
@@ -3772,7 +3763,7 @@ STRUCT_LIST(MAKE_CASE)
AllocationSpace space =
(size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE;
Object* result;
- { MaybeObject* maybe_result = Heap::Allocate(map, space);
+ { MaybeObject* maybe_result = Allocate(map, space);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Struct::cast(result)->InitializeBody(size);
@@ -3786,8 +3777,11 @@ bool Heap::IdleNotification() {
static const int kIdlesBeforeMarkCompact = 8;
static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
static const unsigned int kGCsBetweenCleanup = 4;
- static int number_idle_notifications = 0;
- static unsigned int last_gc_count = gc_count_;
+
+ if (!last_idle_notification_gc_count_init_) {
+ last_idle_notification_gc_count_ = gc_count_;
+ last_idle_notification_gc_count_init_ = true;
+ }
bool uncommit = true;
bool finished = false;
@@ -3796,56 +3790,56 @@ bool Heap::IdleNotification() {
// GCs have taken place. This allows another round of cleanup based
// on idle notifications if enough work has been carried out to
// provoke a number of garbage collections.
- if (gc_count_ - last_gc_count < kGCsBetweenCleanup) {
- number_idle_notifications =
- Min(number_idle_notifications + 1, kMaxIdleCount);
+ if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) {
+ number_idle_notifications_ =
+ Min(number_idle_notifications_ + 1, kMaxIdleCount);
} else {
- number_idle_notifications = 0;
- last_gc_count = gc_count_;
+ number_idle_notifications_ = 0;
+ last_idle_notification_gc_count_ = gc_count_;
}
- if (number_idle_notifications == kIdlesBeforeScavenge) {
+ if (number_idle_notifications_ == kIdlesBeforeScavenge) {
if (contexts_disposed_ > 0) {
- HistogramTimerScope scope(&Counters::gc_context);
+ HistogramTimerScope scope(isolate_->counters()->gc_context());
CollectAllGarbage(false);
} else {
CollectGarbage(NEW_SPACE);
}
new_space_.Shrink();
- last_gc_count = gc_count_;
- } else if (number_idle_notifications == kIdlesBeforeMarkSweep) {
+ last_idle_notification_gc_count_ = gc_count_;
+ } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) {
// Before doing the mark-sweep collections we clear the
// compilation cache to avoid hanging on to source code and
// generated code for cached functions.
- CompilationCache::Clear();
+ isolate_->compilation_cache()->Clear();
CollectAllGarbage(false);
new_space_.Shrink();
- last_gc_count = gc_count_;
+ last_idle_notification_gc_count_ = gc_count_;
- } else if (number_idle_notifications == kIdlesBeforeMarkCompact) {
+ } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) {
CollectAllGarbage(true);
new_space_.Shrink();
- last_gc_count = gc_count_;
+ last_idle_notification_gc_count_ = gc_count_;
+ number_idle_notifications_ = 0;
finished = true;
-
} else if (contexts_disposed_ > 0) {
if (FLAG_expose_gc) {
contexts_disposed_ = 0;
} else {
- HistogramTimerScope scope(&Counters::gc_context);
+ HistogramTimerScope scope(isolate_->counters()->gc_context());
CollectAllGarbage(false);
- last_gc_count = gc_count_;
+ last_idle_notification_gc_count_ = gc_count_;
}
// If this is the first idle notification, we reset the
// notification count to avoid letting idle notifications for
// context disposal garbage collections start a potentially too
// aggressive idle GC cycle.
- if (number_idle_notifications <= 1) {
- number_idle_notifications = 0;
+ if (number_idle_notifications_ <= 1) {
+ number_idle_notifications_ = 0;
uncommit = false;
}
- } else if (number_idle_notifications > kIdlesBeforeMarkCompact) {
+ } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) {
// If we have received more than kIdlesBeforeMarkCompact idle
// notifications we do not perform any cleanup because we don't
// expect to gain much by doing so.
@@ -3855,7 +3849,7 @@ bool Heap::IdleNotification() {
// Make sure that we have no pending context disposals and
// conditionally uncommit from space.
ASSERT(contexts_disposed_ == 0);
- if (uncommit) Heap::UncommitFromSpace();
+ if (uncommit) UncommitFromSpace();
return finished;
}
@@ -3864,7 +3858,7 @@ bool Heap::IdleNotification() {
void Heap::Print() {
if (!HasBeenSetup()) return;
- Top::PrintStack();
+ isolate()->PrintStack();
AllSpaces spaces;
for (Space* space = spaces.next(); space != NULL; space = spaces.next())
space->Print();
@@ -3897,11 +3891,11 @@ void Heap::ReportHeapStatistics(const char* title) {
PrintF("\n");
PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
- GlobalHandles::PrintStats();
+ isolate_->global_handles()->PrintStats();
PrintF("\n");
PrintF("Heap statistics : ");
- MemoryAllocator::ReportStatistics();
+ isolate_->memory_allocator()->ReportStatistics();
PrintF("To space : ");
new_space_.ReportStatistics();
PrintF("Old pointer space : ");
@@ -3984,7 +3978,7 @@ static void VerifyPointersUnderWatermark(
Address start = page->ObjectAreaStart();
Address end = page->AllocationWatermark();
- Heap::IterateDirtyRegions(Page::kAllRegionsDirtyMarks,
+ HEAP->IterateDirtyRegions(Page::kAllRegionsDirtyMarks,
start,
end,
visit_dirty_region,
@@ -4005,7 +3999,7 @@ static void VerifyPointersUnderWatermark(LargeObjectSpace* space) {
// When we are not in GC the Heap::InNewSpace() predicate
// checks that pointers which satisfy predicate point into
// the active semispace.
- Heap::InNewSpace(*slot);
+ HEAP->InNewSpace(*slot);
slot_address += kPointerSize;
}
}
@@ -4126,7 +4120,8 @@ void Heap::ZapFromSpace() {
#endif // DEBUG
-bool Heap::IteratePointersInDirtyRegion(Address start,
+bool Heap::IteratePointersInDirtyRegion(Heap* heap,
+ Address start,
Address end,
ObjectSlotCallback copy_object_func) {
Address slot_address = start;
@@ -4134,10 +4129,10 @@ bool Heap::IteratePointersInDirtyRegion(Address start,
while (slot_address < end) {
Object** slot = reinterpret_cast<Object**>(slot_address);
- if (Heap::InNewSpace(*slot)) {
+ if (heap->InNewSpace(*slot)) {
ASSERT((*slot)->IsHeapObject());
copy_object_func(reinterpret_cast<HeapObject**>(slot));
- if (Heap::InNewSpace(*slot)) {
+ if (heap->InNewSpace(*slot)) {
ASSERT((*slot)->IsHeapObject());
pointers_to_new_space_found = true;
}
@@ -4171,14 +4166,16 @@ static bool IteratePointersInDirtyMaps(Address start,
Address map_address = start;
bool pointers_to_new_space_found = false;
+ Heap* heap = HEAP;
while (map_address < end) {
- ASSERT(!Heap::InNewSpace(Memory::Object_at(map_address)));
+ ASSERT(!heap->InNewSpace(Memory::Object_at(map_address)));
ASSERT(Memory::Object_at(map_address)->IsMap());
Address pointer_fields_start = map_address + Map::kPointerFieldsBeginOffset;
Address pointer_fields_end = map_address + Map::kPointerFieldsEndOffset;
- if (Heap::IteratePointersInDirtyRegion(pointer_fields_start,
+ if (Heap::IteratePointersInDirtyRegion(heap,
+ pointer_fields_start,
pointer_fields_end,
copy_object_func)) {
pointers_to_new_space_found = true;
@@ -4192,6 +4189,7 @@ static bool IteratePointersInDirtyMaps(Address start,
bool Heap::IteratePointersInDirtyMapsRegion(
+ Heap* heap,
Address start,
Address end,
ObjectSlotCallback copy_object_func) {
@@ -4211,7 +4209,8 @@ bool Heap::IteratePointersInDirtyMapsRegion(
Min(prev_map + Map::kPointerFieldsEndOffset, end);
contains_pointers_to_new_space =
- IteratePointersInDirtyRegion(pointer_fields_start,
+ IteratePointersInDirtyRegion(heap,
+ pointer_fields_start,
pointer_fields_end,
copy_object_func)
|| contains_pointers_to_new_space;
@@ -4233,7 +4232,8 @@ bool Heap::IteratePointersInDirtyMapsRegion(
Min(end, map_aligned_end + Map::kPointerFieldsEndOffset);
contains_pointers_to_new_space =
- IteratePointersInDirtyRegion(pointer_fields_start,
+ IteratePointersInDirtyRegion(heap,
+ pointer_fields_start,
pointer_fields_end,
copy_object_func)
|| contains_pointers_to_new_space;
@@ -4253,10 +4253,10 @@ void Heap::IterateAndMarkPointersToFromSpace(Address start,
while (slot_address < end) {
Object** slot = reinterpret_cast<Object**>(slot_address);
- if (Heap::InFromSpace(*slot)) {
+ if (InFromSpace(*slot)) {
ASSERT((*slot)->IsHeapObject());
callback(reinterpret_cast<HeapObject**>(slot));
- if (Heap::InNewSpace(*slot)) {
+ if (InNewSpace(*slot)) {
ASSERT((*slot)->IsHeapObject());
marks |= page->GetRegionMaskForAddress(slot_address);
}
@@ -4295,7 +4295,7 @@ uint32_t Heap::IterateDirtyRegions(
Address region_end = Min(second_region, area_end);
if (marks & mask) {
- if (visit_dirty_region(region_start, region_end, copy_object_func)) {
+ if (visit_dirty_region(this, region_start, region_end, copy_object_func)) {
newmarks |= mask;
}
}
@@ -4307,7 +4307,10 @@ uint32_t Heap::IterateDirtyRegions(
while (region_end <= area_end) {
if (marks & mask) {
- if (visit_dirty_region(region_start, region_end, copy_object_func)) {
+ if (visit_dirty_region(this,
+ region_start,
+ region_end,
+ copy_object_func)) {
newmarks |= mask;
}
}
@@ -4323,7 +4326,7 @@ uint32_t Heap::IterateDirtyRegions(
// with region end. Check whether region covering last part of area is
// dirty.
if (marks & mask) {
- if (visit_dirty_region(region_start, area_end, copy_object_func)) {
+ if (visit_dirty_region(this, region_start, area_end, copy_object_func)) {
newmarks |= mask;
}
}
@@ -4389,7 +4392,7 @@ void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
v->Synchronize("symbol_table");
if (mode != VISIT_ALL_IN_SCAVENGE) {
// Scavenge collections have special processing for this.
- ExternalStringTable::Iterate(v);
+ external_string_table_.Iterate(v);
}
v->Synchronize("external_string_table");
}
@@ -4402,42 +4405,42 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
v->Synchronize("symbol");
- Bootstrapper::Iterate(v);
+ isolate_->bootstrapper()->Iterate(v);
v->Synchronize("bootstrapper");
- Top::Iterate(v);
+ isolate_->Iterate(v);
v->Synchronize("top");
Relocatable::Iterate(v);
v->Synchronize("relocatable");
#ifdef ENABLE_DEBUGGER_SUPPORT
- Debug::Iterate(v);
+ isolate_->debug()->Iterate(v);
#endif
v->Synchronize("debug");
- CompilationCache::Iterate(v);
+ isolate_->compilation_cache()->Iterate(v);
v->Synchronize("compilationcache");
// Iterate over local handles in handle scopes.
- HandleScopeImplementer::Iterate(v);
+ isolate_->handle_scope_implementer()->Iterate(v);
v->Synchronize("handlescope");
// Iterate over the builtin code objects and code stubs in the
// heap. Note that it is not necessary to iterate over code objects
// on scavenge collections.
if (mode != VISIT_ALL_IN_SCAVENGE) {
- Builtins::IterateBuiltins(v);
+ isolate_->builtins()->IterateBuiltins(v);
}
v->Synchronize("builtins");
// Iterate over global handles.
if (mode == VISIT_ONLY_STRONG) {
- GlobalHandles::IterateStrongRoots(v);
+ isolate_->global_handles()->IterateStrongRoots(v);
} else {
- GlobalHandles::IterateAllRoots(v);
+ isolate_->global_handles()->IterateAllRoots(v);
}
v->Synchronize("globalhandles");
// Iterate over pointers being held by inactive threads.
- ThreadManager::Iterate(v);
+ isolate_->thread_manager()->Iterate(v);
v->Synchronize("threadmanager");
// Iterate over the pointers the Serialization/Deserialization code is
@@ -4456,10 +4459,6 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
}
-// Flag is set when the heap has been configured. The heap can be repeatedly
-// configured through the API until it is setup.
-static bool heap_configured = false;
-
// TODO(1236194): Since the heap size is configurable on the command line
// and through the API, we should gracefully handle the case that the heap
// size is not big enough to fit all the initial objects.
@@ -4506,7 +4505,7 @@ bool Heap::ConfigureHeap(int max_semispace_size,
// The old generation is paged.
max_old_generation_size_ = RoundUp(max_old_generation_size_, Page::kPageSize);
- heap_configured = true;
+ configured_ = true;
return true;
}
@@ -4534,11 +4533,13 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
*stats->cell_space_size = cell_space_->Size();
*stats->cell_space_capacity = cell_space_->Capacity();
*stats->lo_space_size = lo_space_->Size();
- GlobalHandles::RecordStats(stats);
- *stats->memory_allocator_size = MemoryAllocator::Size();
+ isolate_->global_handles()->RecordStats(stats);
+ *stats->memory_allocator_size = isolate()->memory_allocator()->Size();
*stats->memory_allocator_capacity =
- MemoryAllocator::Size() + MemoryAllocator::Available();
+ isolate()->memory_allocator()->Size() +
+ isolate()->memory_allocator()->Available();
*stats->os_error = OS::GetLastError();
+ isolate()->memory_allocator()->Available();
if (take_snapshot) {
HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
for (HeapObject* obj = iterator.next();
@@ -4570,8 +4571,177 @@ int Heap::PromotedExternalMemorySize() {
- amount_of_external_allocated_memory_at_last_global_gc_;
}
+#ifdef DEBUG
+
+// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
+static const int kMarkTag = 2;
+
+
+class HeapDebugUtils {
+ public:
+ explicit HeapDebugUtils(Heap* heap)
+ : search_for_any_global_(false),
+ search_target_(NULL),
+ found_target_(false),
+ object_stack_(20),
+ heap_(heap) {
+ }
+
+ class MarkObjectVisitor : public ObjectVisitor {
+ public:
+ explicit MarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
+
+ void VisitPointers(Object** start, Object** end) {
+ // Copy all HeapObject pointers in [start, end)
+ for (Object** p = start; p < end; p++) {
+ if ((*p)->IsHeapObject())
+ utils_->MarkObjectRecursively(p);
+ }
+ }
+
+ HeapDebugUtils* utils_;
+ };
+
+ void MarkObjectRecursively(Object** p) {
+ if (!(*p)->IsHeapObject()) return;
+
+ HeapObject* obj = HeapObject::cast(*p);
+
+ Object* map = obj->map();
+
+ if (!map->IsHeapObject()) return; // visited before
+
+ if (found_target_) return; // stop if target found
+ object_stack_.Add(obj);
+ if ((search_for_any_global_ && obj->IsJSGlobalObject()) ||
+ (!search_for_any_global_ && (obj == search_target_))) {
+ found_target_ = true;
+ return;
+ }
+
+ // not visited yet
+ Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
+
+ Address map_addr = map_p->address();
+
+ obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag));
+
+ MarkObjectRecursively(&map);
+
+ MarkObjectVisitor mark_visitor(this);
+
+ obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p),
+ &mark_visitor);
+
+ if (!found_target_) // don't pop if found the target
+ object_stack_.RemoveLast();
+ }
+
+
+ class UnmarkObjectVisitor : public ObjectVisitor {
+ public:
+ explicit UnmarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
+
+ void VisitPointers(Object** start, Object** end) {
+ // Copy all HeapObject pointers in [start, end)
+ for (Object** p = start; p < end; p++) {
+ if ((*p)->IsHeapObject())
+ utils_->UnmarkObjectRecursively(p);
+ }
+ }
+
+ HeapDebugUtils* utils_;
+ };
+
+
+ void UnmarkObjectRecursively(Object** p) {
+ if (!(*p)->IsHeapObject()) return;
+
+ HeapObject* obj = HeapObject::cast(*p);
+
+ Object* map = obj->map();
+
+ if (map->IsHeapObject()) return; // unmarked already
+
+ Address map_addr = reinterpret_cast<Address>(map);
+
+ map_addr -= kMarkTag;
+
+ ASSERT_TAG_ALIGNED(map_addr);
+
+ HeapObject* map_p = HeapObject::FromAddress(map_addr);
+
+ obj->set_map(reinterpret_cast<Map*>(map_p));
+
+ UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p));
+
+ UnmarkObjectVisitor unmark_visitor(this);
+
+ obj->IterateBody(Map::cast(map_p)->instance_type(),
+ obj->SizeFromMap(Map::cast(map_p)),
+ &unmark_visitor);
+ }
+
+
+ void MarkRootObjectRecursively(Object** root) {
+ if (search_for_any_global_) {
+ ASSERT(search_target_ == NULL);
+ } else {
+ ASSERT(search_target_->IsHeapObject());
+ }
+ found_target_ = false;
+ object_stack_.Clear();
+
+ MarkObjectRecursively(root);
+ UnmarkObjectRecursively(root);
+
+ if (found_target_) {
+ PrintF("=====================================\n");
+ PrintF("==== Path to object ====\n");
+ PrintF("=====================================\n\n");
+
+ ASSERT(!object_stack_.is_empty());
+ for (int i = 0; i < object_stack_.length(); i++) {
+ if (i > 0) PrintF("\n |\n |\n V\n\n");
+ Object* obj = object_stack_[i];
+ obj->Print();
+ }
+ PrintF("=====================================\n");
+ }
+ }
+
+ // Helper class for visiting HeapObjects recursively.
+ class MarkRootVisitor: public ObjectVisitor {
+ public:
+ explicit MarkRootVisitor(HeapDebugUtils* utils) : utils_(utils) { }
+
+ void VisitPointers(Object** start, Object** end) {
+ // Visit all HeapObject pointers in [start, end)
+ for (Object** p = start; p < end; p++) {
+ if ((*p)->IsHeapObject())
+ utils_->MarkRootObjectRecursively(p);
+ }
+ }
+
+ HeapDebugUtils* utils_;
+ };
+
+ bool search_for_any_global_;
+ Object* search_target_;
+ bool found_target_;
+ List<Object*> object_stack_;
+ Heap* heap_;
+
+ friend class Heap;
+};
+
+#endif
bool Heap::Setup(bool create_heap_objects) {
+#ifdef DEBUG
+ debug_utils_ = new HeapDebugUtils(this);
+#endif
+
// Initialize heap spaces and initial maps and objects. Whenever something
// goes wrong, just return false. The caller should check the results and
// call Heap::TearDown() to release allocated memory.
@@ -4580,13 +4750,19 @@ bool Heap::Setup(bool create_heap_objects) {
// Configuration is based on the flags new-space-size (really the semispace
// size) and old-space-size if set or the initial values of semispace_size_
// and old_generation_size_ otherwise.
- if (!heap_configured) {
+ if (!configured_) {
if (!ConfigureHeapDefault()) return false;
}
- ScavengingVisitor::Initialize();
- NewSpaceScavenger::Initialize();
- MarkCompactCollector::Initialize();
+ gc_initializer_mutex->Lock();
+ static bool initialized_gc = false;
+ if (!initialized_gc) {
+ initialized_gc = true;
+ ScavengingVisitor::Initialize();
+ NewSpaceScavenger::Initialize();
+ MarkCompactCollector::Initialize();
+ }
+ gc_initializer_mutex->Unlock();
MarkMapPointersAsEncoded(false);
@@ -4594,9 +4770,11 @@ bool Heap::Setup(bool create_heap_objects) {
// space. The chunk is double the size of the requested reserved
// new space size to ensure that we can find a pair of semispaces that
// are contiguous and aligned to their size.
- if (!MemoryAllocator::Setup(MaxReserved(), MaxExecutableSize())) return false;
+ if (!isolate_->memory_allocator()->Setup(MaxReserved(), MaxExecutableSize()))
+ return false;
void* chunk =
- MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_);
+ isolate_->memory_allocator()->ReserveInitialChunk(
+ 4 * reserved_semispace_size_);
if (chunk == NULL) return false;
// Align the pair of semispaces to their size, which must be a power
@@ -4609,13 +4787,19 @@ bool Heap::Setup(bool create_heap_objects) {
// Initialize old pointer space.
old_pointer_space_ =
- new OldSpace(max_old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE);
+ new OldSpace(this,
+ max_old_generation_size_,
+ OLD_POINTER_SPACE,
+ NOT_EXECUTABLE);
if (old_pointer_space_ == NULL) return false;
if (!old_pointer_space_->Setup(NULL, 0)) return false;
// Initialize old data space.
old_data_space_ =
- new OldSpace(max_old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE);
+ new OldSpace(this,
+ max_old_generation_size_,
+ OLD_DATA_SPACE,
+ NOT_EXECUTABLE);
if (old_data_space_ == NULL) return false;
if (!old_data_space_->Setup(NULL, 0)) return false;
@@ -4624,18 +4808,18 @@ bool Heap::Setup(bool create_heap_objects) {
// On 64-bit platform(s), we put all code objects in a 2 GB range of
// virtual address space, so that they can call each other with near calls.
if (code_range_size_ > 0) {
- if (!CodeRange::Setup(code_range_size_)) {
+ if (!isolate_->code_range()->Setup(code_range_size_)) {
return false;
}
}
code_space_ =
- new OldSpace(max_old_generation_size_, CODE_SPACE, EXECUTABLE);
+ new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE);
if (code_space_ == NULL) return false;
if (!code_space_->Setup(NULL, 0)) return false;
// Initialize map space.
- map_space_ = new MapSpace(FLAG_use_big_map_space
+ map_space_ = new MapSpace(this, FLAG_use_big_map_space
? max_old_generation_size_
: MapSpace::kMaxMapPageIndex * Page::kPageSize,
FLAG_max_map_space_pages,
@@ -4644,14 +4828,14 @@ bool Heap::Setup(bool create_heap_objects) {
if (!map_space_->Setup(NULL, 0)) return false;
// Initialize global property cell space.
- cell_space_ = new CellSpace(max_old_generation_size_, CELL_SPACE);
+ cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE);
if (cell_space_ == NULL) return false;
if (!cell_space_->Setup(NULL, 0)) return false;
// The large object code space may contain code or data. We set the memory
// to be non-executable here for safety, but this means we need to enable it
// explicitly when allocating large code objects.
- lo_space_ = new LargeObjectSpace(LO_SPACE);
+ lo_space_ = new LargeObjectSpace(this, LO_SPACE);
if (lo_space_ == NULL) return false;
if (!lo_space_->Setup()) return false;
@@ -4666,12 +4850,12 @@ bool Heap::Setup(bool create_heap_objects) {
global_contexts_list_ = undefined_value();
}
- LOG(IntPtrTEvent("heap-capacity", Capacity()));
- LOG(IntPtrTEvent("heap-available", Available()));
+ LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
+ LOG(isolate_, IntPtrTEvent("heap-available", Available()));
#ifdef ENABLE_LOGGING_AND_PROFILING
// This should be called only after initial objects have been created.
- ProducerHeapProfile::Setup();
+ isolate_->producer_heap_profile()->Setup();
#endif
return true;
@@ -4679,6 +4863,8 @@ bool Heap::Setup(bool create_heap_objects) {
void Heap::SetStackLimits() {
+ ASSERT(isolate_ != NULL);
+ ASSERT(isolate_ == isolate());
// On 64 bit machines, pointers are generally out of range of Smis. We write
// something that looks like an out of range Smi to the GC.
@@ -4686,10 +4872,10 @@ void Heap::SetStackLimits() {
// These are actually addresses, but the tag makes the GC ignore it.
roots_[kStackLimitRootIndex] =
reinterpret_cast<Object*>(
- (StackGuard::jslimit() & ~kSmiTagMask) | kSmiTag);
+ (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
roots_[kRealStackLimitRootIndex] =
reinterpret_cast<Object*>(
- (StackGuard::real_jslimit() & ~kSmiTagMask) | kSmiTag);
+ (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
}
@@ -4699,16 +4885,16 @@ void Heap::TearDown() {
PrintF("gc_count=%d ", gc_count_);
PrintF("mark_sweep_count=%d ", ms_count_);
PrintF("mark_compact_count=%d ", mc_count_);
- PrintF("max_gc_pause=%d ", GCTracer::get_max_gc_pause());
- PrintF("min_in_mutator=%d ", GCTracer::get_min_in_mutator());
+ PrintF("max_gc_pause=%d ", get_max_gc_pause());
+ PrintF("min_in_mutator=%d ", get_min_in_mutator());
PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ",
- GCTracer::get_max_alive_after_gc());
+ get_max_alive_after_gc());
PrintF("\n\n");
}
- GlobalHandles::TearDown();
+ isolate_->global_handles()->TearDown();
- ExternalStringTable::TearDown();
+ external_string_table_.TearDown();
new_space_.TearDown();
@@ -4748,7 +4934,12 @@ void Heap::TearDown() {
lo_space_ = NULL;
}
- MemoryAllocator::TearDown();
+ isolate_->memory_allocator()->TearDown();
+
+#ifdef DEBUG
+ delete debug_utils_;
+ debug_utils_ = NULL;
+#endif
}
@@ -4837,7 +5028,7 @@ class PrintHandleVisitor: public ObjectVisitor {
void Heap::PrintHandles() {
PrintF("Handles:\n");
PrintHandleVisitor v;
- HandleScopeImplementer::Iterate(&v);
+ isolate_->handle_scope_implementer()->Iterate(&v);
}
#endif
@@ -4846,19 +5037,19 @@ void Heap::PrintHandles() {
Space* AllSpaces::next() {
switch (counter_++) {
case NEW_SPACE:
- return Heap::new_space();
+ return HEAP->new_space();
case OLD_POINTER_SPACE:
- return Heap::old_pointer_space();
+ return HEAP->old_pointer_space();
case OLD_DATA_SPACE:
- return Heap::old_data_space();
+ return HEAP->old_data_space();
case CODE_SPACE:
- return Heap::code_space();
+ return HEAP->code_space();
case MAP_SPACE:
- return Heap::map_space();
+ return HEAP->map_space();
case CELL_SPACE:
- return Heap::cell_space();
+ return HEAP->cell_space();
case LO_SPACE:
- return Heap::lo_space();
+ return HEAP->lo_space();
default:
return NULL;
}
@@ -4868,15 +5059,15 @@ Space* AllSpaces::next() {
PagedSpace* PagedSpaces::next() {
switch (counter_++) {
case OLD_POINTER_SPACE:
- return Heap::old_pointer_space();
+ return HEAP->old_pointer_space();
case OLD_DATA_SPACE:
- return Heap::old_data_space();
+ return HEAP->old_data_space();
case CODE_SPACE:
- return Heap::code_space();
+ return HEAP->code_space();
case MAP_SPACE:
- return Heap::map_space();
+ return HEAP->map_space();
case CELL_SPACE:
- return Heap::cell_space();
+ return HEAP->cell_space();
default:
return NULL;
}
@@ -4887,11 +5078,11 @@ PagedSpace* PagedSpaces::next() {
OldSpace* OldSpaces::next() {
switch (counter_++) {
case OLD_POINTER_SPACE:
- return Heap::old_pointer_space();
+ return HEAP->old_pointer_space();
case OLD_DATA_SPACE:
- return Heap::old_data_space();
+ return HEAP->old_data_space();
case CODE_SPACE:
- return Heap::code_space();
+ return HEAP->code_space();
default:
return NULL;
}
@@ -4946,25 +5137,25 @@ ObjectIterator* SpaceIterator::CreateIterator() {
switch (current_space_) {
case NEW_SPACE:
- iterator_ = new SemiSpaceIterator(Heap::new_space(), size_func_);
+ iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_);
break;
case OLD_POINTER_SPACE:
- iterator_ = new HeapObjectIterator(Heap::old_pointer_space(), size_func_);
+ iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_);
break;
case OLD_DATA_SPACE:
- iterator_ = new HeapObjectIterator(Heap::old_data_space(), size_func_);
+ iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_);
break;
case CODE_SPACE:
- iterator_ = new HeapObjectIterator(Heap::code_space(), size_func_);
+ iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_);
break;
case MAP_SPACE:
- iterator_ = new HeapObjectIterator(Heap::map_space(), size_func_);
+ iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_);
break;
case CELL_SPACE:
- iterator_ = new HeapObjectIterator(Heap::cell_space(), size_func_);
+ iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_);
break;
case LO_SPACE:
- iterator_ = new LargeObjectIterator(Heap::lo_space(), size_func_);
+ iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_);
break;
}
@@ -4998,16 +5189,17 @@ class FreeListNodesFilter : public HeapObjectsFilter {
private:
void MarkFreeListNodes() {
- Heap::old_pointer_space()->MarkFreeListNodes();
- Heap::old_data_space()->MarkFreeListNodes();
- MarkCodeSpaceFreeListNodes();
- Heap::map_space()->MarkFreeListNodes();
- Heap::cell_space()->MarkFreeListNodes();
+ Heap* heap = HEAP;
+ heap->old_pointer_space()->MarkFreeListNodes();
+ heap->old_data_space()->MarkFreeListNodes();
+ MarkCodeSpaceFreeListNodes(heap);
+ heap->map_space()->MarkFreeListNodes();
+ heap->cell_space()->MarkFreeListNodes();
}
- void MarkCodeSpaceFreeListNodes() {
+ void MarkCodeSpaceFreeListNodes(Heap* heap) {
// For code space, using FreeListNode::IsFreeListNode is OK.
- HeapObjectIterator iter(Heap::code_space());
+ HeapObjectIterator iter(heap->code_space());
for (HeapObject* obj = iter.next_object();
obj != NULL;
obj = iter.next_object()) {
@@ -5069,7 +5261,7 @@ class UnreachableObjectsFilter : public HeapObjectsFilter {
obj->SetMark();
}
UnmarkingVisitor visitor;
- Heap::IterateRoots(&visitor, VISIT_ALL);
+ HEAP->IterateRoots(&visitor, VISIT_ALL);
while (visitor.can_process())
visitor.ProcessNext();
}
@@ -5372,7 +5564,7 @@ static intptr_t CountTotalHolesSize() {
}
-GCTracer::GCTracer()
+GCTracer::GCTracer(Heap* heap)
: start_time_(0.0),
start_size_(0),
gc_count_(0),
@@ -5381,14 +5573,16 @@ GCTracer::GCTracer()
marked_count_(0),
allocated_since_last_gc_(0),
spent_in_mutator_(0),
- promoted_objects_size_(0) {
+ promoted_objects_size_(0),
+ heap_(heap) {
// These two fields reflect the state of the previous full collection.
// Set them before they are changed by the collector.
- previous_has_compacted_ = MarkCompactCollector::HasCompacted();
- previous_marked_count_ = MarkCompactCollector::previous_marked_count();
+ previous_has_compacted_ = heap_->mark_compact_collector_.HasCompacted();
+ previous_marked_count_ =
+ heap_->mark_compact_collector_.previous_marked_count();
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
start_time_ = OS::TimeCurrentMillis();
- start_size_ = Heap::SizeOfObjects();
+ start_size_ = heap_->SizeOfObjects();
for (int i = 0; i < Scope::kNumberOfScopes; i++) {
scopes_[i] = 0;
@@ -5396,10 +5590,11 @@ GCTracer::GCTracer()
in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
- allocated_since_last_gc_ = Heap::SizeOfObjects() - alive_after_last_gc_;
+ allocated_since_last_gc_ =
+ heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
- if (last_gc_end_timestamp_ > 0) {
- spent_in_mutator_ = Max(start_time_ - last_gc_end_timestamp_, 0.0);
+ if (heap_->last_gc_end_timestamp_ > 0) {
+ spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
}
}
@@ -5408,20 +5603,21 @@ GCTracer::~GCTracer() {
// Printf ONE line iff flag is set.
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
- bool first_gc = (last_gc_end_timestamp_ == 0);
+ bool first_gc = (heap_->last_gc_end_timestamp_ == 0);
- alive_after_last_gc_ = Heap::SizeOfObjects();
- last_gc_end_timestamp_ = OS::TimeCurrentMillis();
+ heap_->alive_after_last_gc_ = heap_->SizeOfObjects();
+ heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis();
- int time = static_cast<int>(last_gc_end_timestamp_ - start_time_);
+ int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_);
// Update cumulative GC statistics if required.
if (FLAG_print_cumulative_gc_stat) {
- max_gc_pause_ = Max(max_gc_pause_, time);
- max_alive_after_gc_ = Max(max_alive_after_gc_, alive_after_last_gc_);
+ heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time);
+ heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_,
+ heap_->alive_after_last_gc_);
if (!first_gc) {
- min_in_mutator_ = Min(min_in_mutator_,
- static_cast<int>(spent_in_mutator_));
+ heap_->min_in_mutator_ = Min(heap_->min_in_mutator_,
+ static_cast<int>(spent_in_mutator_));
}
}
@@ -5446,7 +5642,8 @@ GCTracer::~GCTracer() {
PrintF("s");
break;
case MARK_COMPACTOR:
- PrintF(MarkCompactCollector::HasCompacted() ? "mc" : "ms");
+ PrintF("%s",
+ heap_->mark_compact_collector_.HasCompacted() ? "mc" : "ms");
break;
default:
UNREACHABLE();
@@ -5460,7 +5657,7 @@ GCTracer::~GCTracer() {
PrintF("compact=%d ", static_cast<int>(scopes_[Scope::MC_COMPACT]));
PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_);
- PrintF("total_size_after=%" V8_PTR_PREFIX "d ", Heap::SizeOfObjects());
+ PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
in_free_list_or_wasted_before_gc_);
PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize());
@@ -5472,7 +5669,7 @@ GCTracer::~GCTracer() {
}
#if defined(ENABLE_LOGGING_AND_PROFILING)
- Heap::PrintShortHeapStatistics();
+ heap_->PrintShortHeapStatistics();
#endif
}
@@ -5482,8 +5679,8 @@ const char* GCTracer::CollectorString() {
case SCAVENGER:
return "Scavenge";
case MARK_COMPACTOR:
- return MarkCompactCollector::HasCompacted() ? "Mark-compact"
- : "Mark-sweep";
+ return heap_->mark_compact_collector_.HasCompacted() ? "Mark-compact"
+ : "Mark-sweep";
}
return "Unknown GC";
}
@@ -5503,13 +5700,13 @@ int KeyedLookupCache::Lookup(Map* map, String* name) {
if ((key.map == map) && key.name->Equals(name)) {
return field_offsets_[index];
}
- return -1;
+ return kNotFound;
}
void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
String* symbol;
- if (Heap::LookupSymbolIfExists(name, &symbol)) {
+ if (HEAP->LookupSymbolIfExists(name, &symbol)) {
int index = Hash(map, symbol);
Key& key = keys_[index];
key.map = map;
@@ -5524,35 +5721,24 @@ void KeyedLookupCache::Clear() {
}
-KeyedLookupCache::Key KeyedLookupCache::keys_[KeyedLookupCache::kLength];
-
-
-int KeyedLookupCache::field_offsets_[KeyedLookupCache::kLength];
-
-
void DescriptorLookupCache::Clear() {
for (int index = 0; index < kLength; index++) keys_[index].array = NULL;
}
-DescriptorLookupCache::Key
-DescriptorLookupCache::keys_[DescriptorLookupCache::kLength];
-
-int DescriptorLookupCache::results_[DescriptorLookupCache::kLength];
-
-
#ifdef DEBUG
void Heap::GarbageCollectionGreedyCheck() {
ASSERT(FLAG_gc_greedy);
- if (Bootstrapper::IsActive()) return;
+ if (isolate_->bootstrapper()->IsActive()) return;
if (disallow_allocation_failure()) return;
CollectGarbage(NEW_SPACE);
}
#endif
-TranscendentalCache::TranscendentalCache(TranscendentalCache::Type t)
- : type_(t) {
+TranscendentalCache::SubCache::SubCache(Type t)
+ : type_(t),
+ isolate_(Isolate::Current()) {
uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
uint32_t in1 = 0xffffffffu; // generated by the FPU.
for (int i = 0; i < kCacheSize; i++) {
@@ -5563,9 +5749,6 @@ TranscendentalCache::TranscendentalCache(TranscendentalCache::Type t)
}
-TranscendentalCache* TranscendentalCache::caches_[kNumberOfCaches];
-
-
void TranscendentalCache::Clear() {
for (int i = 0; i < kNumberOfCaches; i++) {
if (caches_[i] != NULL) {
@@ -5579,8 +5762,8 @@ void TranscendentalCache::Clear() {
void ExternalStringTable::CleanUp() {
int last = 0;
for (int i = 0; i < new_space_strings_.length(); ++i) {
- if (new_space_strings_[i] == Heap::raw_unchecked_null_value()) continue;
- if (Heap::InNewSpace(new_space_strings_[i])) {
+ if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+ if (heap_->InNewSpace(new_space_strings_[i])) {
new_space_strings_[last++] = new_space_strings_[i];
} else {
old_space_strings_.Add(new_space_strings_[i]);
@@ -5589,8 +5772,8 @@ void ExternalStringTable::CleanUp() {
new_space_strings_.Rewind(last);
last = 0;
for (int i = 0; i < old_space_strings_.length(); ++i) {
- if (old_space_strings_[i] == Heap::raw_unchecked_null_value()) continue;
- ASSERT(!Heap::InNewSpace(old_space_strings_[i]));
+ if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+ ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
old_space_strings_[last++] = old_space_strings_[i];
}
old_space_strings_.Rewind(last);
@@ -5604,7 +5787,4 @@ void ExternalStringTable::TearDown() {
}
-List<Object*> ExternalStringTable::new_space_strings_;
-List<Object*> ExternalStringTable::old_space_strings_;
-
} } // namespace v8::internal
diff --git a/src/heap.h b/src/heap.h
index 6aa8339a..88074d73 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -32,6 +32,7 @@
#include "globals.h"
#include "list.h"
+#include "mark-compact.h"
#include "spaces.h"
#include "splay-tree-inl.h"
#include "v8-counters.h"
@@ -39,9 +40,14 @@
namespace v8 {
namespace internal {
+// TODO(isolates): remove HEAP here
+#define HEAP (_inline_get_heap_())
+class Heap;
+inline Heap* _inline_get_heap_();
+
// Defines all the roots in Heap.
-#define UNCONDITIONAL_STRONG_ROOT_LIST(V) \
+#define STRONG_ROOT_LIST(V) \
/* Put the byte array map early. We need it to be in place by the time */ \
/* the deserializer hits the next page, since it wants to put a byte */ \
/* array in the unused space at the end of the page. */ \
@@ -89,7 +95,7 @@ namespace internal {
V(Map, external_ascii_string_map, ExternalAsciiStringMap) \
V(Map, undetectable_string_map, UndetectableStringMap) \
V(Map, undetectable_ascii_string_map, UndetectableAsciiStringMap) \
- V(Map, pixel_array_map, PixelArrayMap) \
+ V(Map, external_pixel_array_map, ExternalPixelArrayMap) \
V(Map, external_byte_array_map, ExternalByteArrayMap) \
V(Map, external_unsigned_byte_array_map, ExternalUnsignedByteArrayMap) \
V(Map, external_short_array_map, ExternalShortArrayMap) \
@@ -114,26 +120,12 @@ namespace internal {
V(NumberDictionary, non_monomorphic_cache, NonMonomorphicCache) \
V(Code, js_entry_code, JsEntryCode) \
V(Code, js_construct_entry_code, JsConstructEntryCode) \
- V(Code, c_entry_code, CEntryCode) \
V(FixedArray, natives_source_cache, NativesSourceCache) \
V(Object, last_script_id, LastScriptId) \
V(Script, empty_script, EmptyScript) \
V(Smi, real_stack_limit, RealStackLimit) \
V(StringDictionary, intrinsic_function_names, IntrinsicFunctionNames) \
-#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
-#define STRONG_ROOT_LIST(V) \
- UNCONDITIONAL_STRONG_ROOT_LIST(V) \
- V(Code, re_c_entry_code, RegExpCEntryCode) \
- V(Code, direct_c_entry_code, DirectCEntryCode)
-#elif V8_TARGET_ARCH_ARM
-#define STRONG_ROOT_LIST(V) \
- UNCONDITIONAL_STRONG_ROOT_LIST(V) \
- V(Code, direct_c_entry_code, DirectCEntryCode)
-#else
-#define STRONG_ROOT_LIST(V) UNCONDITIONAL_STRONG_ROOT_LIST(V)
-#endif
-
#define ROOT_LIST(V) \
STRONG_ROOT_LIST(V) \
V(SymbolTable, symbol_table, SymbolTable)
@@ -185,8 +177,6 @@ namespace internal {
V(InitializeConstGlobal_symbol, "InitializeConstGlobal") \
V(KeyedLoadSpecialized_symbol, "KeyedLoadSpecialized") \
V(KeyedStoreSpecialized_symbol, "KeyedStoreSpecialized") \
- V(KeyedLoadPixelArray_symbol, "KeyedLoadPixelArray") \
- V(KeyedStorePixelArray_symbol, "KeyedStorePixelArray") \
V(stack_overflow_symbol, "kStackOverflowBoilerplate") \
V(illegal_access_symbol, "illegal access") \
V(out_of_memory_symbol, "out-of-memory") \
@@ -215,18 +205,42 @@ namespace internal {
V(identity_hash_symbol, "v8::IdentityHash") \
V(closure_symbol, "(closure)") \
V(use_strict, "use strict") \
- V(KeyedLoadExternalArray_symbol, "KeyedLoadExternalArray") \
- V(KeyedStoreExternalArray_symbol, "KeyedStoreExternalArray")
+ V(KeyedLoadExternalByteArray_symbol, "KeyedLoadExternalByteArray") \
+ V(KeyedLoadExternalUnsignedByteArray_symbol, \
+ "KeyedLoadExternalUnsignedByteArray") \
+ V(KeyedLoadExternalShortArray_symbol, \
+ "KeyedLoadExternalShortArray") \
+ V(KeyedLoadExternalUnsignedShortArray_symbol, \
+ "KeyedLoadExternalUnsignedShortArray") \
+ V(KeyedLoadExternalIntArray_symbol, "KeyedLoadExternalIntArray") \
+ V(KeyedLoadExternalUnsignedIntArray_symbol, \
+ "KeyedLoadExternalUnsignedIntArray") \
+ V(KeyedLoadExternalFloatArray_symbol, "KeyedLoadExternalFloatArray") \
+ V(KeyedLoadExternalPixelArray_symbol, "KeyedLoadExternalPixelArray") \
+ V(KeyedStoreExternalByteArray_symbol, "KeyedStoreExternalByteArray") \
+ V(KeyedStoreExternalUnsignedByteArray_symbol, \
+ "KeyedStoreExternalUnsignedByteArray") \
+ V(KeyedStoreExternalShortArray_symbol, "KeyedStoreExternalShortArray") \
+ V(KeyedStoreExternalUnsignedShortArray_symbol, \
+ "KeyedStoreExternalUnsignedShortArray") \
+ V(KeyedStoreExternalIntArray_symbol, "KeyedStoreExternalIntArray") \
+ V(KeyedStoreExternalUnsignedIntArray_symbol, \
+ "KeyedStoreExternalUnsignedIntArray") \
+ V(KeyedStoreExternalFloatArray_symbol, "KeyedStoreExternalFloatArray") \
+ V(KeyedStoreExternalPixelArray_symbol, "KeyedStoreExternalPixelArray")
// Forward declarations.
class GCTracer;
class HeapStats;
+class Isolate;
class WeakObjectRetainer;
-typedef String* (*ExternalStringTableUpdaterCallback)(Object** pointer);
+typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap,
+ Object** pointer);
-typedef bool (*DirtyRegionCallback)(Address start,
+typedef bool (*DirtyRegionCallback)(Heap* heap,
+ Address start,
Address end,
ObjectSlotCallback copy_object_func);
@@ -234,103 +248,178 @@ typedef bool (*DirtyRegionCallback)(Address start,
// The all static Heap captures the interface to the global object heap.
// All JavaScript contexts by this process share the same object heap.
-class Heap : public AllStatic {
+#ifdef DEBUG
+class HeapDebugUtils;
+#endif
+
+
+// A queue of objects promoted during scavenge. Each object is accompanied
+// by it's size to avoid dereferencing a map pointer for scanning.
+class PromotionQueue {
+ public:
+ PromotionQueue() : front_(NULL), rear_(NULL) { }
+
+ void Initialize(Address start_address) {
+ front_ = rear_ = reinterpret_cast<intptr_t*>(start_address);
+ }
+
+ bool is_empty() { return front_ <= rear_; }
+
+ inline void insert(HeapObject* target, int size);
+
+ void remove(HeapObject** target, int* size) {
+ *target = reinterpret_cast<HeapObject*>(*(--front_));
+ *size = static_cast<int>(*(--front_));
+ // Assert no underflow.
+ ASSERT(front_ >= rear_);
+ }
+
+ private:
+ // The front of the queue is higher in memory than the rear.
+ intptr_t* front_;
+ intptr_t* rear_;
+
+ DISALLOW_COPY_AND_ASSIGN(PromotionQueue);
+};
+
+
+// External strings table is a place where all external strings are
+// registered. We need to keep track of such strings to properly
+// finalize them.
+class ExternalStringTable {
+ public:
+ // Registers an external string.
+ inline void AddString(String* string);
+
+ inline void Iterate(ObjectVisitor* v);
+
+ // Restores internal invariant and gets rid of collected strings.
+ // Must be called after each Iterate() that modified the strings.
+ void CleanUp();
+
+ // Destroys all allocated memory.
+ void TearDown();
+
+ private:
+ ExternalStringTable() { }
+
+ friend class Heap;
+
+ inline void Verify();
+
+ inline void AddOldString(String* string);
+
+ // Notifies the table that only a prefix of the new list is valid.
+ inline void ShrinkNewStrings(int position);
+
+ // To speed up scavenge collections new space string are kept
+ // separate from old space strings.
+ List<Object*> new_space_strings_;
+ List<Object*> old_space_strings_;
+
+ Heap* heap_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExternalStringTable);
+};
+
+
+class Heap {
public:
// Configure heap size before setup. Return false if the heap has been
// setup already.
- static bool ConfigureHeap(int max_semispace_size,
- int max_old_gen_size,
- int max_executable_size);
- static bool ConfigureHeapDefault();
+ bool ConfigureHeap(int max_semispace_size,
+ int max_old_gen_size,
+ int max_executable_size);
+ bool ConfigureHeapDefault();
// Initializes the global object heap. If create_heap_objects is true,
// also creates the basic non-mutable objects.
// Returns whether it succeeded.
- static bool Setup(bool create_heap_objects);
+ bool Setup(bool create_heap_objects);
// Destroys all memory allocated by the heap.
- static void TearDown();
+ void TearDown();
// Set the stack limit in the roots_ array. Some architectures generate
// code that looks here, because it is faster than loading from the static
// jslimit_/real_jslimit_ variable in the StackGuard.
- static void SetStackLimits();
+ void SetStackLimits();
// Returns whether Setup has been called.
- static bool HasBeenSetup();
+ bool HasBeenSetup();
// Returns the maximum amount of memory reserved for the heap. For
// the young generation, we reserve 4 times the amount needed for a
// semi space. The young generation consists of two semi spaces and
// we reserve twice the amount needed for those in order to ensure
// that new space can be aligned to its size.
- static intptr_t MaxReserved() {
+ intptr_t MaxReserved() {
return 4 * reserved_semispace_size_ + max_old_generation_size_;
}
- static int MaxSemiSpaceSize() { return max_semispace_size_; }
- static int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
- static int InitialSemiSpaceSize() { return initial_semispace_size_; }
- static intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
- static intptr_t MaxExecutableSize() { return max_executable_size_; }
+ int MaxSemiSpaceSize() { return max_semispace_size_; }
+ int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
+ int InitialSemiSpaceSize() { return initial_semispace_size_; }
+ intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
+ intptr_t MaxExecutableSize() { return max_executable_size_; }
// Returns the capacity of the heap in bytes w/o growing. Heap grows when
// more spaces are needed until it reaches the limit.
- static intptr_t Capacity();
+ intptr_t Capacity();
// Returns the amount of memory currently committed for the heap.
- static intptr_t CommittedMemory();
+ intptr_t CommittedMemory();
// Returns the amount of executable memory currently committed for the heap.
- static intptr_t CommittedMemoryExecutable();
+ intptr_t CommittedMemoryExecutable();
// Returns the available bytes in space w/o growing.
// Heap doesn't guarantee that it can allocate an object that requires
// all available bytes. Check MaxHeapObjectSize() instead.
- static intptr_t Available();
+ intptr_t Available();
// Returns the maximum object size in paged space.
- static inline int MaxObjectSizeInPagedSpace();
+ inline int MaxObjectSizeInPagedSpace();
// Returns of size of all objects residing in the heap.
- static intptr_t SizeOfObjects();
+ intptr_t SizeOfObjects();
// Return the starting address and a mask for the new space. And-masking an
// address with the mask will result in the start address of the new space
// for all addresses in either semispace.
- static Address NewSpaceStart() { return new_space_.start(); }
- static uintptr_t NewSpaceMask() { return new_space_.mask(); }
- static Address NewSpaceTop() { return new_space_.top(); }
-
- static NewSpace* new_space() { return &new_space_; }
- static OldSpace* old_pointer_space() { return old_pointer_space_; }
- static OldSpace* old_data_space() { return old_data_space_; }
- static OldSpace* code_space() { return code_space_; }
- static MapSpace* map_space() { return map_space_; }
- static CellSpace* cell_space() { return cell_space_; }
- static LargeObjectSpace* lo_space() { return lo_space_; }
-
- static bool always_allocate() { return always_allocate_scope_depth_ != 0; }
- static Address always_allocate_scope_depth_address() {
+ Address NewSpaceStart() { return new_space_.start(); }
+ uintptr_t NewSpaceMask() { return new_space_.mask(); }
+ Address NewSpaceTop() { return new_space_.top(); }
+
+ NewSpace* new_space() { return &new_space_; }
+ OldSpace* old_pointer_space() { return old_pointer_space_; }
+ OldSpace* old_data_space() { return old_data_space_; }
+ OldSpace* code_space() { return code_space_; }
+ MapSpace* map_space() { return map_space_; }
+ CellSpace* cell_space() { return cell_space_; }
+ LargeObjectSpace* lo_space() { return lo_space_; }
+
+ bool always_allocate() { return always_allocate_scope_depth_ != 0; }
+ Address always_allocate_scope_depth_address() {
return reinterpret_cast<Address>(&always_allocate_scope_depth_);
}
- static bool linear_allocation() {
+ bool linear_allocation() {
return linear_allocation_scope_depth_ != 0;
}
- static Address* NewSpaceAllocationTopAddress() {
+ Address* NewSpaceAllocationTopAddress() {
return new_space_.allocation_top_address();
}
- static Address* NewSpaceAllocationLimitAddress() {
+ Address* NewSpaceAllocationLimitAddress() {
return new_space_.allocation_limit_address();
}
// Uncommit unused semi space.
- static bool UncommitFromSpace() { return new_space_.UncommitFromSpace(); }
+ bool UncommitFromSpace() { return new_space_.UncommitFromSpace(); }
#ifdef ENABLE_HEAP_PROTECTION
// Protect/unprotect the heap by marking all spaces read-only/writable.
- static void Protect();
- static void Unprotect();
+ void Protect();
+ void Unprotect();
#endif
// Allocates and initializes a new JavaScript object based on a
@@ -338,71 +427,65 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateJSObject(
+ MUST_USE_RESULT MaybeObject* AllocateJSObject(
JSFunction* constructor, PretenureFlag pretenure = NOT_TENURED);
// Allocates and initializes a new global object based on a constructor.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateGlobalObject(
- JSFunction* constructor);
+ MUST_USE_RESULT MaybeObject* AllocateGlobalObject(JSFunction* constructor);
// Returns a deep copy of the JavaScript object.
// Properties and elements are copied too.
// Returns failure if allocation failed.
- MUST_USE_RESULT static MaybeObject* CopyJSObject(JSObject* source);
+ MUST_USE_RESULT MaybeObject* CopyJSObject(JSObject* source);
// Allocates the function prototype.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateFunctionPrototype(
- JSFunction* function);
+ MUST_USE_RESULT MaybeObject* AllocateFunctionPrototype(JSFunction* function);
// Reinitialize an JSGlobalProxy based on a constructor. The object
// must have the same size as objects allocated using the
// constructor. The object is reinitialized and behaves as an
// object that has been freshly allocated using the constructor.
- MUST_USE_RESULT static MaybeObject* ReinitializeJSGlobalProxy(
- JSFunction* constructor,
- JSGlobalProxy* global);
+ MUST_USE_RESULT MaybeObject* ReinitializeJSGlobalProxy(
+ JSFunction* constructor, JSGlobalProxy* global);
// Allocates and initializes a new JavaScript object based on a map.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateJSObjectFromMap(
+ MUST_USE_RESULT MaybeObject* AllocateJSObjectFromMap(
Map* map, PretenureFlag pretenure = NOT_TENURED);
// Allocates a heap object based on the map.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* Allocate(Map* map, AllocationSpace space);
+ MUST_USE_RESULT MaybeObject* Allocate(Map* map, AllocationSpace space);
// Allocates a JS Map in the heap.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateMap(InstanceType instance_type,
- int instance_size);
+ MUST_USE_RESULT MaybeObject* AllocateMap(InstanceType instance_type,
+ int instance_size);
// Allocates a partial map for bootstrapping.
- MUST_USE_RESULT static MaybeObject* AllocatePartialMap(
- InstanceType instance_type,
- int instance_size);
+ MUST_USE_RESULT MaybeObject* AllocatePartialMap(InstanceType instance_type,
+ int instance_size);
// Allocate a map for the specified function
- MUST_USE_RESULT static MaybeObject* AllocateInitialMap(JSFunction* fun);
+ MUST_USE_RESULT MaybeObject* AllocateInitialMap(JSFunction* fun);
// Allocates an empty code cache.
- MUST_USE_RESULT static MaybeObject* AllocateCodeCache();
+ MUST_USE_RESULT MaybeObject* AllocateCodeCache();
// Clear the Instanceof cache (used when a prototype changes).
- static void ClearInstanceofCache() {
- set_instanceof_cache_function(the_hole_value());
- }
+ inline void ClearInstanceofCache();
// Allocates and fully initializes a String. There are two String
// encodings: ASCII and two byte. One should choose between the three string
@@ -422,16 +505,16 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateStringFromAscii(
+ MUST_USE_RESULT MaybeObject* AllocateStringFromAscii(
Vector<const char> str,
PretenureFlag pretenure = NOT_TENURED);
- MUST_USE_RESULT static inline MaybeObject* AllocateStringFromUtf8(
+ MUST_USE_RESULT inline MaybeObject* AllocateStringFromUtf8(
Vector<const char> str,
PretenureFlag pretenure = NOT_TENURED);
- MUST_USE_RESULT static MaybeObject* AllocateStringFromUtf8Slow(
+ MUST_USE_RESULT MaybeObject* AllocateStringFromUtf8Slow(
Vector<const char> str,
PretenureFlag pretenure = NOT_TENURED);
- MUST_USE_RESULT static MaybeObject* AllocateStringFromTwoByte(
+ MUST_USE_RESULT MaybeObject* AllocateStringFromTwoByte(
Vector<const uc16> str,
PretenureFlag pretenure = NOT_TENURED);
@@ -439,27 +522,25 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT static inline MaybeObject* AllocateSymbol(
- Vector<const char> str,
- int chars,
- uint32_t hash_field);
+ MUST_USE_RESULT inline MaybeObject* AllocateSymbol(Vector<const char> str,
+ int chars,
+ uint32_t hash_field);
- MUST_USE_RESULT static inline MaybeObject* AllocateAsciiSymbol(
+ MUST_USE_RESULT inline MaybeObject* AllocateAsciiSymbol(
Vector<const char> str,
uint32_t hash_field);
- MUST_USE_RESULT static inline MaybeObject* AllocateTwoByteSymbol(
+ MUST_USE_RESULT inline MaybeObject* AllocateTwoByteSymbol(
Vector<const uc16> str,
uint32_t hash_field);
- MUST_USE_RESULT static MaybeObject* AllocateInternalSymbol(
+ MUST_USE_RESULT MaybeObject* AllocateInternalSymbol(
unibrow::CharacterStream* buffer, int chars, uint32_t hash_field);
- MUST_USE_RESULT static MaybeObject* AllocateExternalSymbol(
+ MUST_USE_RESULT MaybeObject* AllocateExternalSymbol(
Vector<const char> str,
int chars);
-
// Allocates and partially initializes a String. There are two String
// encodings: ASCII and two byte. These functions allocate a string of the
// given length and set its map and length fields. The characters of the
@@ -467,10 +548,10 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateRawAsciiString(
+ MUST_USE_RESULT MaybeObject* AllocateRawAsciiString(
int length,
PretenureFlag pretenure = NOT_TENURED);
- MUST_USE_RESULT static MaybeObject* AllocateRawTwoByteString(
+ MUST_USE_RESULT MaybeObject* AllocateRawTwoByteString(
int length,
PretenureFlag pretenure = NOT_TENURED);
@@ -478,35 +559,27 @@ class Heap : public AllStatic {
// A cache is used for ascii codes.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed. Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* LookupSingleCharacterStringFromCode(
+ MUST_USE_RESULT MaybeObject* LookupSingleCharacterStringFromCode(
uint16_t code);
// Allocate a byte array of the specified length
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateByteArray(int length,
- PretenureFlag pretenure);
+ MUST_USE_RESULT MaybeObject* AllocateByteArray(int length,
+ PretenureFlag pretenure);
// Allocate a non-tenured byte array of the specified length
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateByteArray(int length);
-
- // Allocate a pixel array of the specified length
- // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
- // failed.
- // Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocatePixelArray(int length,
- uint8_t* external_pointer,
- PretenureFlag pretenure);
+ MUST_USE_RESULT MaybeObject* AllocateByteArray(int length);
// Allocates an external array of the specified length and type.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateExternalArray(
+ MUST_USE_RESULT MaybeObject* AllocateExternalArray(
int length,
ExternalArrayType array_type,
void* external_pointer,
@@ -516,132 +589,130 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateJSGlobalPropertyCell(
- Object* value);
+ MUST_USE_RESULT MaybeObject* AllocateJSGlobalPropertyCell(Object* value);
// Allocates a fixed array initialized with undefined values
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateFixedArray(
- int length,
- PretenureFlag pretenure);
+ MUST_USE_RESULT MaybeObject* AllocateFixedArray(int length,
+ PretenureFlag pretenure);
// Allocates a fixed array initialized with undefined values
- MUST_USE_RESULT static MaybeObject* AllocateFixedArray(int length);
+ MUST_USE_RESULT MaybeObject* AllocateFixedArray(int length);
// Allocates an uninitialized fixed array. It must be filled by the caller.
//
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateUninitializedFixedArray(
- int length);
+ MUST_USE_RESULT MaybeObject* AllocateUninitializedFixedArray(int length);
// Make a copy of src and return it. Returns
// Failure::RetryAfterGC(requested_bytes, space) if the allocation failed.
- MUST_USE_RESULT static inline MaybeObject* CopyFixedArray(FixedArray* src);
+ MUST_USE_RESULT inline MaybeObject* CopyFixedArray(FixedArray* src);
// Make a copy of src, set the map, and return the copy. Returns
// Failure::RetryAfterGC(requested_bytes, space) if the allocation failed.
- MUST_USE_RESULT static MaybeObject* CopyFixedArrayWithMap(FixedArray* src,
- Map* map);
+ MUST_USE_RESULT MaybeObject* CopyFixedArrayWithMap(FixedArray* src, Map* map);
// Allocates a fixed array initialized with the hole values.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithHoles(
+ MUST_USE_RESULT MaybeObject* AllocateFixedArrayWithHoles(
int length,
PretenureFlag pretenure = NOT_TENURED);
// AllocateHashTable is identical to AllocateFixedArray except
// that the resulting object has hash_table_map as map.
- MUST_USE_RESULT static MaybeObject* AllocateHashTable(
+ MUST_USE_RESULT MaybeObject* AllocateHashTable(
int length, PretenureFlag pretenure = NOT_TENURED);
// Allocate a global (but otherwise uninitialized) context.
- MUST_USE_RESULT static MaybeObject* AllocateGlobalContext();
+ MUST_USE_RESULT MaybeObject* AllocateGlobalContext();
// Allocate a function context.
- MUST_USE_RESULT static MaybeObject* AllocateFunctionContext(
- int length,
- JSFunction* closure);
+ MUST_USE_RESULT MaybeObject* AllocateFunctionContext(int length,
+ JSFunction* closure);
// Allocate a 'with' context.
- MUST_USE_RESULT static MaybeObject* AllocateWithContext(
- Context* previous,
- JSObject* extension,
- bool is_catch_context);
+ MUST_USE_RESULT MaybeObject* AllocateWithContext(Context* previous,
+ JSObject* extension,
+ bool is_catch_context);
// Allocates a new utility object in the old generation.
- MUST_USE_RESULT static MaybeObject* AllocateStruct(InstanceType type);
+ MUST_USE_RESULT MaybeObject* AllocateStruct(InstanceType type);
// Allocates a function initialized with a shared part.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateFunction(
+ MUST_USE_RESULT MaybeObject* AllocateFunction(
Map* function_map,
SharedFunctionInfo* shared,
Object* prototype,
PretenureFlag pretenure = TENURED);
- // Indicies for direct access into argument objects.
+ // Arguments object size.
static const int kArgumentsObjectSize =
JSObject::kHeaderSize + 2 * kPointerSize;
- static const int arguments_callee_index = 0;
- static const int arguments_length_index = 1;
+ // Strict mode arguments has no callee so it is smaller.
+ static const int kArgumentsObjectSizeStrict =
+ JSObject::kHeaderSize + 1 * kPointerSize;
+ // Indicies for direct access into argument objects.
+ static const int kArgumentsLengthIndex = 0;
+ // callee is only valid in non-strict mode.
+ static const int kArgumentsCalleeIndex = 1;
// Allocates an arguments object - optionally with an elements array.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateArgumentsObject(Object* callee,
- int length);
+ MUST_USE_RESULT MaybeObject* AllocateArgumentsObject(
+ Object* callee, int length);
// Same as NewNumberFromDouble, but may return a preallocated/immutable
// number object (e.g., minus_zero_value_, nan_value_)
- MUST_USE_RESULT static MaybeObject* NumberFromDouble(
+ MUST_USE_RESULT MaybeObject* NumberFromDouble(
double value, PretenureFlag pretenure = NOT_TENURED);
// Allocated a HeapNumber from value.
- MUST_USE_RESULT static MaybeObject* AllocateHeapNumber(
+ MUST_USE_RESULT MaybeObject* AllocateHeapNumber(
double value,
PretenureFlag pretenure);
- // pretenure = NOT_TENURED.
- MUST_USE_RESULT static MaybeObject* AllocateHeapNumber(double value);
+ // pretenure = NOT_TENURED
+ MUST_USE_RESULT MaybeObject* AllocateHeapNumber(double value);
// Converts an int into either a Smi or a HeapNumber object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static inline MaybeObject* NumberFromInt32(int32_t value);
+ MUST_USE_RESULT inline MaybeObject* NumberFromInt32(int32_t value);
// Converts an int into either a Smi or a HeapNumber object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static inline MaybeObject* NumberFromUint32(uint32_t value);
+ MUST_USE_RESULT inline MaybeObject* NumberFromUint32(uint32_t value);
// Allocates a new proxy object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateProxy(
- Address proxy,
- PretenureFlag pretenure = NOT_TENURED);
+ MUST_USE_RESULT MaybeObject* AllocateProxy(
+ Address proxy, PretenureFlag pretenure = NOT_TENURED);
// Allocates a new SharedFunctionInfo object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateSharedFunctionInfo(Object* name);
+ MUST_USE_RESULT MaybeObject* AllocateSharedFunctionInfo(Object* name);
// Allocates a new JSMessageObject object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note that this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateJSMessageObject(
+ MUST_USE_RESULT MaybeObject* AllocateJSMessageObject(
String* type,
JSArray* arguments,
int start_position,
@@ -654,8 +725,8 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateConsString(String* first,
- String* second);
+ MUST_USE_RESULT MaybeObject* AllocateConsString(String* first,
+ String* second);
// Allocates a new sub string object which is a substring of an underlying
// string buffer stretching from the index start (inclusive) to the index
@@ -663,7 +734,7 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateSubString(
+ MUST_USE_RESULT MaybeObject* AllocateSubString(
String* buffer,
int start,
int end,
@@ -674,28 +745,27 @@ class Heap : public AllStatic {
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* AllocateExternalStringFromAscii(
+ MUST_USE_RESULT MaybeObject* AllocateExternalStringFromAscii(
ExternalAsciiString::Resource* resource);
- MUST_USE_RESULT static MaybeObject* AllocateExternalStringFromTwoByte(
+ MUST_USE_RESULT MaybeObject* AllocateExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource);
// Finalizes an external string by deleting the associated external
// data and clearing the resource pointer.
- static inline void FinalizeExternalString(String* string);
+ inline void FinalizeExternalString(String* string);
// Allocates an uninitialized object. The memory is non-executable if the
// hardware and OS allow.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT static inline MaybeObject* AllocateRaw(
- int size_in_bytes,
- AllocationSpace space,
- AllocationSpace retry_space);
+ MUST_USE_RESULT inline MaybeObject* AllocateRaw(int size_in_bytes,
+ AllocationSpace space,
+ AllocationSpace retry_space);
// Initialize a filler object to keep the ability to iterate over the heap
// when shortening objects.
- static void CreateFillerObjectAt(Address addr, int size);
+ void CreateFillerObjectAt(Address addr, int size);
// Makes a new native code object
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
@@ -703,36 +773,36 @@ class Heap : public AllStatic {
// self_reference. This allows generated code to reference its own Code
// object by containing this pointer.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* CreateCode(const CodeDesc& desc,
- Code::Flags flags,
- Handle<Object> self_reference);
+ MUST_USE_RESULT MaybeObject* CreateCode(const CodeDesc& desc,
+ Code::Flags flags,
+ Handle<Object> self_reference,
+ bool immovable = false);
- MUST_USE_RESULT static MaybeObject* CopyCode(Code* code);
+ MUST_USE_RESULT MaybeObject* CopyCode(Code* code);
// Copy the code and scope info part of the code object, but insert
// the provided data as the relocation information.
- MUST_USE_RESULT static MaybeObject* CopyCode(Code* code,
- Vector<byte> reloc_info);
+ MUST_USE_RESULT MaybeObject* CopyCode(Code* code, Vector<byte> reloc_info);
// Finds the symbol for string in the symbol table.
// If not found, a new symbol is added to the table and returned.
// Returns Failure::RetryAfterGC(requested_bytes, space) if allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* LookupSymbol(Vector<const char> str);
- MUST_USE_RESULT static MaybeObject* LookupAsciiSymbol(Vector<const char> str);
- MUST_USE_RESULT static MaybeObject* LookupTwoByteSymbol(
+ MUST_USE_RESULT MaybeObject* LookupSymbol(Vector<const char> str);
+ MUST_USE_RESULT MaybeObject* LookupAsciiSymbol(Vector<const char> str);
+ MUST_USE_RESULT MaybeObject* LookupTwoByteSymbol(
Vector<const uc16> str);
- MUST_USE_RESULT static MaybeObject* LookupAsciiSymbol(const char* str) {
+ MUST_USE_RESULT MaybeObject* LookupAsciiSymbol(const char* str) {
return LookupSymbol(CStrVector(str));
}
- MUST_USE_RESULT static MaybeObject* LookupSymbol(String* str);
- static bool LookupSymbolIfExists(String* str, String** symbol);
- static bool LookupTwoCharsSymbolIfExists(String* str, String** symbol);
+ MUST_USE_RESULT MaybeObject* LookupSymbol(String* str);
+ bool LookupSymbolIfExists(String* str, String** symbol);
+ bool LookupTwoCharsSymbolIfExists(String* str, String** symbol);
// Compute the matching symbol map for a string if possible.
// NULL is returned if string is in new space or not flattened.
- static Map* SymbolMapForString(String* str);
+ Map* SymbolMapForString(String* str);
// Tries to flatten a string before compare operation.
//
@@ -741,60 +811,60 @@ class Heap : public AllStatic {
// string might stay non-flat even when not a failure is returned.
//
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT static inline MaybeObject* PrepareForCompare(String* str);
+ MUST_USE_RESULT inline MaybeObject* PrepareForCompare(String* str);
// Converts the given boolean condition to JavaScript boolean value.
- static Object* ToBoolean(bool condition) {
- return condition ? true_value() : false_value();
- }
+ inline Object* ToBoolean(bool condition);
// Code that should be run before and after each GC. Includes some
// reporting/verification activities when compiled with DEBUG set.
- static void GarbageCollectionPrologue();
- static void GarbageCollectionEpilogue();
+ void GarbageCollectionPrologue();
+ void GarbageCollectionEpilogue();
// Performs garbage collection operation.
// Returns whether there is a chance that another major GC could
// collect more garbage.
- static bool CollectGarbage(AllocationSpace space, GarbageCollector collector);
+ bool CollectGarbage(AllocationSpace space, GarbageCollector collector);
// Performs garbage collection operation.
// Returns whether there is a chance that another major GC could
// collect more garbage.
- inline static bool CollectGarbage(AllocationSpace space);
+ inline bool CollectGarbage(AllocationSpace space);
// Performs a full garbage collection. Force compaction if the
// parameter is true.
- static void CollectAllGarbage(bool force_compaction);
+ void CollectAllGarbage(bool force_compaction);
// Last hope GC, should try to squeeze as much as possible.
- static void CollectAllAvailableGarbage();
+ void CollectAllAvailableGarbage();
// Notify the heap that a context has been disposed.
- static int NotifyContextDisposed() { return ++contexts_disposed_; }
+ int NotifyContextDisposed() { return ++contexts_disposed_; }
// Utility to invoke the scavenger. This is needed in test code to
// ensure correct callback for weak global handles.
- static void PerformScavenge();
+ void PerformScavenge();
+
+ PromotionQueue* promotion_queue() { return &promotion_queue_; }
#ifdef DEBUG
// Utility used with flag gc-greedy.
- static void GarbageCollectionGreedyCheck();
+ void GarbageCollectionGreedyCheck();
#endif
- static void AddGCPrologueCallback(
+ void AddGCPrologueCallback(
GCEpilogueCallback callback, GCType gc_type_filter);
- static void RemoveGCPrologueCallback(GCEpilogueCallback callback);
+ void RemoveGCPrologueCallback(GCEpilogueCallback callback);
- static void AddGCEpilogueCallback(
+ void AddGCEpilogueCallback(
GCEpilogueCallback callback, GCType gc_type_filter);
- static void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
+ void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
- static void SetGlobalGCPrologueCallback(GCCallback callback) {
+ void SetGlobalGCPrologueCallback(GCCallback callback) {
ASSERT((callback == NULL) ^ (global_gc_prologue_callback_ == NULL));
global_gc_prologue_callback_ = callback;
}
- static void SetGlobalGCEpilogueCallback(GCCallback callback) {
+ void SetGlobalGCEpilogueCallback(GCCallback callback) {
ASSERT((callback == NULL) ^ (global_gc_epilogue_callback_ == NULL));
global_gc_epilogue_callback_ = callback;
}
@@ -802,10 +872,10 @@ class Heap : public AllStatic {
// Heap root getters. We have versions with and without type::cast() here.
// You can't use type::cast during GC because the assert fails.
#define ROOT_ACCESSOR(type, name, camel_name) \
- static inline type* name() { \
+ type* name() { \
return type::cast(roots_[k##camel_name##RootIndex]); \
} \
- static inline type* raw_unchecked_##name() { \
+ type* raw_unchecked_##name() { \
return reinterpret_cast<type*>(roots_[k##camel_name##RootIndex]); \
}
ROOT_LIST(ROOT_ACCESSOR)
@@ -813,13 +883,13 @@ class Heap : public AllStatic {
// Utility type maps
#define STRUCT_MAP_ACCESSOR(NAME, Name, name) \
- static inline Map* name##_map() { \
+ Map* name##_map() { \
return Map::cast(roots_[k##Name##MapRootIndex]); \
}
STRUCT_LIST(STRUCT_MAP_ACCESSOR)
#undef STRUCT_MAP_ACCESSOR
-#define SYMBOL_ACCESSOR(name, str) static inline String* name() { \
+#define SYMBOL_ACCESSOR(name, str) String* name() { \
return String::cast(roots_[k##name##RootIndex]); \
}
SYMBOL_LIST(SYMBOL_ACCESSOR)
@@ -827,19 +897,19 @@ class Heap : public AllStatic {
// The hidden_symbol is special because it is the empty string, but does
// not match the empty string.
- static String* hidden_symbol() { return hidden_symbol_; }
+ String* hidden_symbol() { return hidden_symbol_; }
- static void set_global_contexts_list(Object* object) {
+ void set_global_contexts_list(Object* object) {
global_contexts_list_ = object;
}
- static Object* global_contexts_list() { return global_contexts_list_; }
+ Object* global_contexts_list() { return global_contexts_list_; }
// Iterates over all roots in the heap.
- static void IterateRoots(ObjectVisitor* v, VisitMode mode);
+ void IterateRoots(ObjectVisitor* v, VisitMode mode);
// Iterates over all strong roots in the heap.
- static void IterateStrongRoots(ObjectVisitor* v, VisitMode mode);
+ void IterateStrongRoots(ObjectVisitor* v, VisitMode mode);
// Iterates over all the other roots in the heap.
- static void IterateWeakRoots(ObjectVisitor* v, VisitMode mode);
+ void IterateWeakRoots(ObjectVisitor* v, VisitMode mode);
enum ExpectedPageWatermarkState {
WATERMARK_SHOULD_BE_VALID,
@@ -853,7 +923,7 @@ class Heap : public AllStatic {
// can_preallocate_during_iteration should be set to true.
// All pages will be marked as having invalid watermark upon
// iteration completion.
- static void IterateDirtyRegions(
+ void IterateDirtyRegions(
PagedSpace* space,
DirtyRegionCallback visit_dirty_region,
ObjectSlotCallback callback,
@@ -863,22 +933,23 @@ class Heap : public AllStatic {
// Page::kRegionSize aligned by Page::kRegionAlignmentMask and covering
// memory interval from start to top. For each dirty region call a
// visit_dirty_region callback. Return updated bitvector of dirty marks.
- static uint32_t IterateDirtyRegions(uint32_t marks,
- Address start,
- Address end,
- DirtyRegionCallback visit_dirty_region,
- ObjectSlotCallback callback);
+ uint32_t IterateDirtyRegions(uint32_t marks,
+ Address start,
+ Address end,
+ DirtyRegionCallback visit_dirty_region,
+ ObjectSlotCallback callback);
// Iterate pointers to from semispace of new space found in memory interval
// from start to end.
// Update dirty marks for page containing start address.
- static void IterateAndMarkPointersToFromSpace(Address start,
- Address end,
- ObjectSlotCallback callback);
+ void IterateAndMarkPointersToFromSpace(Address start,
+ Address end,
+ ObjectSlotCallback callback);
// Iterate pointers to new space found in memory interval from start to end.
// Return true if pointers to new space was found.
- static bool IteratePointersInDirtyRegion(Address start,
+ static bool IteratePointersInDirtyRegion(Heap* heap,
+ Address start,
Address end,
ObjectSlotCallback callback);
@@ -886,127 +957,127 @@ class Heap : public AllStatic {
// Iterate pointers to new space found in memory interval from start to end.
// This interval is considered to belong to the map space.
// Return true if pointers to new space was found.
- static bool IteratePointersInDirtyMapsRegion(Address start,
+ static bool IteratePointersInDirtyMapsRegion(Heap* heap,
+ Address start,
Address end,
ObjectSlotCallback callback);
// Returns whether the object resides in new space.
- static inline bool InNewSpace(Object* object);
- static inline bool InFromSpace(Object* object);
- static inline bool InToSpace(Object* object);
+ inline bool InNewSpace(Object* object);
+ inline bool InFromSpace(Object* object);
+ inline bool InToSpace(Object* object);
// Checks whether an address/object in the heap (including auxiliary
// area and unused area).
- static bool Contains(Address addr);
- static bool Contains(HeapObject* value);
+ bool Contains(Address addr);
+ bool Contains(HeapObject* value);
// Checks whether an address/object in a space.
// Currently used by tests, serialization and heap verification only.
- static bool InSpace(Address addr, AllocationSpace space);
- static bool InSpace(HeapObject* value, AllocationSpace space);
+ bool InSpace(Address addr, AllocationSpace space);
+ bool InSpace(HeapObject* value, AllocationSpace space);
// Finds out which space an object should get promoted to based on its type.
- static inline OldSpace* TargetSpace(HeapObject* object);
- static inline AllocationSpace TargetSpaceId(InstanceType type);
+ inline OldSpace* TargetSpace(HeapObject* object);
+ inline AllocationSpace TargetSpaceId(InstanceType type);
// Sets the stub_cache_ (only used when expanding the dictionary).
- static void public_set_code_stubs(NumberDictionary* value) {
+ void public_set_code_stubs(NumberDictionary* value) {
roots_[kCodeStubsRootIndex] = value;
}
// Support for computing object sizes for old objects during GCs. Returns
// a function that is guaranteed to be safe for computing object sizes in
// the current GC phase.
- static HeapObjectCallback GcSafeSizeOfOldObjectFunction() {
+ HeapObjectCallback GcSafeSizeOfOldObjectFunction() {
return gc_safe_size_of_old_object_;
}
// Sets the non_monomorphic_cache_ (only used when expanding the dictionary).
- static void public_set_non_monomorphic_cache(NumberDictionary* value) {
+ void public_set_non_monomorphic_cache(NumberDictionary* value) {
roots_[kNonMonomorphicCacheRootIndex] = value;
}
- static void public_set_empty_script(Script* script) {
+ void public_set_empty_script(Script* script) {
roots_[kEmptyScriptRootIndex] = script;
}
// Update the next script id.
- static inline void SetLastScriptId(Object* last_script_id);
+ inline void SetLastScriptId(Object* last_script_id);
// Generated code can embed this address to get access to the roots.
- static Object** roots_address() { return roots_; }
+ Object** roots_address() { return roots_; }
// Get address of global contexts list for serialization support.
- static Object** global_contexts_list_address() {
+ Object** global_contexts_list_address() {
return &global_contexts_list_;
}
#ifdef DEBUG
- static void Print();
- static void PrintHandles();
+ void Print();
+ void PrintHandles();
// Verify the heap is in its normal state before or after a GC.
- static void Verify();
+ void Verify();
// Report heap statistics.
- static void ReportHeapStatistics(const char* title);
- static void ReportCodeStatistics(const char* title);
+ void ReportHeapStatistics(const char* title);
+ void ReportCodeStatistics(const char* title);
// Fill in bogus values in from space
- static void ZapFromSpace();
+ void ZapFromSpace();
#endif
#if defined(ENABLE_LOGGING_AND_PROFILING)
// Print short heap statistics.
- static void PrintShortHeapStatistics();
+ void PrintShortHeapStatistics();
#endif
// Makes a new symbol object
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT static MaybeObject* CreateSymbol(const char* str,
- int length,
- int hash);
- MUST_USE_RESULT static MaybeObject* CreateSymbol(String* str);
+ MUST_USE_RESULT MaybeObject* CreateSymbol(
+ const char* str, int length, int hash);
+ MUST_USE_RESULT MaybeObject* CreateSymbol(String* str);
// Write barrier support for address[offset] = o.
- static inline void RecordWrite(Address address, int offset);
+ inline void RecordWrite(Address address, int offset);
// Write barrier support for address[start : start + len[ = o.
- static inline void RecordWrites(Address address, int start, int len);
+ inline void RecordWrites(Address address, int start, int len);
// Given an address occupied by a live code object, return that object.
- static Object* FindCodeObject(Address a);
+ Object* FindCodeObject(Address a);
// Invoke Shrink on shrinkable spaces.
- static void Shrink();
+ void Shrink();
enum HeapState { NOT_IN_GC, SCAVENGE, MARK_COMPACT };
- static inline HeapState gc_state() { return gc_state_; }
+ inline HeapState gc_state() { return gc_state_; }
#ifdef DEBUG
- static bool IsAllocationAllowed() { return allocation_allowed_; }
- static inline bool allow_allocation(bool enable);
+ bool IsAllocationAllowed() { return allocation_allowed_; }
+ inline bool allow_allocation(bool enable);
- static bool disallow_allocation_failure() {
+ bool disallow_allocation_failure() {
return disallow_allocation_failure_;
}
- static void TracePathToObject(Object* target);
- static void TracePathToGlobal();
+ void TracePathToObject(Object* target);
+ void TracePathToGlobal();
#endif
// Callback function passed to Heap::Iterate etc. Copies an object if
// necessary, the object might be promoted to an old space. The caller must
// ensure the precondition that the object is (a) a heap object and (b) in
// the heap's from space.
- static void ScavengePointer(HeapObject** p);
+ static inline void ScavengePointer(HeapObject** p);
static inline void ScavengeObject(HeapObject** p, HeapObject* object);
// Commits from space if it is uncommitted.
- static void EnsureFromSpaceIsCommitted();
+ void EnsureFromSpaceIsCommitted();
// Support for partial snapshots. After calling this we can allocate a
// certain number of bytes using only linear allocation (with a
@@ -1014,7 +1085,7 @@ class Heap : public AllStatic {
// or causing a GC. It returns true of space was reserved or false if a GC is
// needed. For paged spaces the space requested must include the space wasted
// at the end of each page when allocating linearly.
- static void ReserveSpace(
+ void ReserveSpace(
int new_space_size,
int pointer_space_size,
int data_space_size,
@@ -1027,45 +1098,44 @@ class Heap : public AllStatic {
// Support for the API.
//
- static bool CreateApiObjects();
+ bool CreateApiObjects();
// Attempt to find the number in a small cache. If we finds it, return
// the string representation of the number. Otherwise return undefined.
- static Object* GetNumberStringCache(Object* number);
+ Object* GetNumberStringCache(Object* number);
// Update the cache with a new number-string pair.
- static void SetNumberStringCache(Object* number, String* str);
+ void SetNumberStringCache(Object* number, String* str);
// Adjusts the amount of registered external memory.
// Returns the adjusted value.
- static inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
+ inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
// Allocate uninitialized fixed array.
- MUST_USE_RESULT static MaybeObject* AllocateRawFixedArray(int length);
- MUST_USE_RESULT static MaybeObject* AllocateRawFixedArray(
- int length,
- PretenureFlag pretenure);
+ MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int length);
+ MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int length,
+ PretenureFlag pretenure);
// True if we have reached the allocation limit in the old generation that
// should force the next GC (caused normally) to be a full one.
- static bool OldGenerationPromotionLimitReached() {
+ bool OldGenerationPromotionLimitReached() {
return (PromotedSpaceSize() + PromotedExternalMemorySize())
> old_gen_promotion_limit_;
}
- static intptr_t OldGenerationSpaceAvailable() {
+ intptr_t OldGenerationSpaceAvailable() {
return old_gen_allocation_limit_ -
(PromotedSpaceSize() + PromotedExternalMemorySize());
}
// True if we have reached the allocation limit in the old generation that
// should artificially cause a GC right now.
- static bool OldGenerationAllocationLimitReached() {
+ bool OldGenerationAllocationLimitReached() {
return OldGenerationSpaceAvailable() < 0;
}
// Can be called when the embedding application is idle.
- static bool IdleNotification();
+ bool IdleNotification();
// Declare all the root indices.
enum RootListIndex {
@@ -1087,76 +1157,109 @@ class Heap : public AllStatic {
kRootListLength
};
- MUST_USE_RESULT static MaybeObject* NumberToString(
- Object* number,
- bool check_number_string_cache = true);
+ MUST_USE_RESULT MaybeObject* NumberToString(
+ Object* number, bool check_number_string_cache = true);
- static Map* MapForExternalArrayType(ExternalArrayType array_type);
- static RootListIndex RootIndexForExternalArrayType(
+ Map* MapForExternalArrayType(ExternalArrayType array_type);
+ RootListIndex RootIndexForExternalArrayType(
ExternalArrayType array_type);
- static void RecordStats(HeapStats* stats, bool take_snapshot = false);
+ void RecordStats(HeapStats* stats, bool take_snapshot = false);
// Copy block of memory from src to dst. Size of block should be aligned
// by pointer size.
static inline void CopyBlock(Address dst, Address src, int byte_size);
- static inline void CopyBlockToOldSpaceAndUpdateRegionMarks(Address dst,
- Address src,
- int byte_size);
+ inline void CopyBlockToOldSpaceAndUpdateRegionMarks(Address dst,
+ Address src,
+ int byte_size);
// Optimized version of memmove for blocks with pointer size aligned sizes and
// pointer size aligned addresses.
static inline void MoveBlock(Address dst, Address src, int byte_size);
- static inline void MoveBlockToOldSpaceAndUpdateRegionMarks(Address dst,
- Address src,
- int byte_size);
+ inline void MoveBlockToOldSpaceAndUpdateRegionMarks(Address dst,
+ Address src,
+ int byte_size);
// Check new space expansion criteria and expand semispaces if it was hit.
- static void CheckNewSpaceExpansionCriteria();
+ void CheckNewSpaceExpansionCriteria();
- static inline void IncrementYoungSurvivorsCounter(int survived) {
+ inline void IncrementYoungSurvivorsCounter(int survived) {
young_survivors_after_last_gc_ = survived;
survived_since_last_expansion_ += survived;
}
- static void UpdateNewSpaceReferencesInExternalStringTable(
+ void UpdateNewSpaceReferencesInExternalStringTable(
ExternalStringTableUpdaterCallback updater_func);
- static void ProcessWeakReferences(WeakObjectRetainer* retainer);
+ void ProcessWeakReferences(WeakObjectRetainer* retainer);
// Helper function that governs the promotion policy from new space to
// old. If the object's old address lies below the new space's age
// mark or if we've already filled the bottom 1/16th of the to space,
// we try to promote this object.
- static inline bool ShouldBePromoted(Address old_address, int object_size);
+ inline bool ShouldBePromoted(Address old_address, int object_size);
+
+ int MaxObjectSizeInNewSpace() { return kMaxObjectSizeInNewSpace; }
- static int MaxObjectSizeInNewSpace() { return kMaxObjectSizeInNewSpace; }
+ void ClearJSFunctionResultCaches();
- static void ClearJSFunctionResultCaches();
+ void ClearNormalizedMapCaches();
- static void ClearNormalizedMapCaches();
+ GCTracer* tracer() { return tracer_; }
- static GCTracer* tracer() { return tracer_; }
+ // Returns maximum GC pause.
+ int get_max_gc_pause() { return max_gc_pause_; }
+
+ // Returns maximum size of objects alive after GC.
+ intptr_t get_max_alive_after_gc() { return max_alive_after_gc_; }
+
+ // Returns minimal interval between two subsequent collections.
+ int get_min_in_mutator() { return min_in_mutator_; }
+
+ MarkCompactCollector* mark_compact_collector() {
+ return &mark_compact_collector_;
+ }
+
+ ExternalStringTable* external_string_table() {
+ return &external_string_table_;
+ }
+
+ inline Isolate* isolate();
+ bool is_safe_to_read_maps() { return is_safe_to_read_maps_; }
+
+ void CallGlobalGCPrologueCallback() {
+ if (global_gc_prologue_callback_ != NULL) global_gc_prologue_callback_();
+ }
+
+ void CallGlobalGCEpilogueCallback() {
+ if (global_gc_epilogue_callback_ != NULL) global_gc_epilogue_callback_();
+ }
private:
- static int reserved_semispace_size_;
- static int max_semispace_size_;
- static int initial_semispace_size_;
- static intptr_t max_old_generation_size_;
- static intptr_t max_executable_size_;
- static intptr_t code_range_size_;
+ Heap();
+
+ // This can be calculated directly from a pointer to the heap; however, it is
+ // more expedient to get at the isolate directly from within Heap methods.
+ Isolate* isolate_;
+
+ int reserved_semispace_size_;
+ int max_semispace_size_;
+ int initial_semispace_size_;
+ intptr_t max_old_generation_size_;
+ intptr_t max_executable_size_;
+ intptr_t code_range_size_;
// For keeping track of how much data has survived
// scavenge since last new space expansion.
- static int survived_since_last_expansion_;
+ int survived_since_last_expansion_;
- static int always_allocate_scope_depth_;
- static int linear_allocation_scope_depth_;
+ int always_allocate_scope_depth_;
+ int linear_allocation_scope_depth_;
// For keeping track of context disposals.
- static int contexts_disposed_;
+ int contexts_disposed_;
#if defined(V8_TARGET_ARCH_X64)
static const int kMaxObjectSizeInNewSpace = 1024*KB;
@@ -1164,76 +1267,78 @@ class Heap : public AllStatic {
static const int kMaxObjectSizeInNewSpace = 512*KB;
#endif
- static NewSpace new_space_;
- static OldSpace* old_pointer_space_;
- static OldSpace* old_data_space_;
- static OldSpace* code_space_;
- static MapSpace* map_space_;
- static CellSpace* cell_space_;
- static LargeObjectSpace* lo_space_;
- static HeapState gc_state_;
+ NewSpace new_space_;
+ OldSpace* old_pointer_space_;
+ OldSpace* old_data_space_;
+ OldSpace* code_space_;
+ MapSpace* map_space_;
+ CellSpace* cell_space_;
+ LargeObjectSpace* lo_space_;
+ HeapState gc_state_;
// Returns the size of object residing in non new spaces.
- static intptr_t PromotedSpaceSize();
+ intptr_t PromotedSpaceSize();
// Returns the amount of external memory registered since last global gc.
- static int PromotedExternalMemorySize();
+ int PromotedExternalMemorySize();
- static int mc_count_; // how many mark-compact collections happened
- static int ms_count_; // how many mark-sweep collections happened
- static unsigned int gc_count_; // how many gc happened
+ int mc_count_; // how many mark-compact collections happened
+ int ms_count_; // how many mark-sweep collections happened
+ unsigned int gc_count_; // how many gc happened
// Total length of the strings we failed to flatten since the last GC.
- static int unflattened_strings_length_;
+ int unflattened_strings_length_;
#define ROOT_ACCESSOR(type, name, camel_name) \
- static inline void set_##name(type* value) { \
+ inline void set_##name(type* value) { \
roots_[k##camel_name##RootIndex] = value; \
}
ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR
#ifdef DEBUG
- static bool allocation_allowed_;
+ bool allocation_allowed_;
// If the --gc-interval flag is set to a positive value, this
// variable holds the value indicating the number of allocations
// remain until the next failure and garbage collection.
- static int allocation_timeout_;
+ int allocation_timeout_;
// Do we expect to be able to handle allocation failure at this
// time?
- static bool disallow_allocation_failure_;
+ bool disallow_allocation_failure_;
+
+ HeapDebugUtils* debug_utils_;
#endif // DEBUG
// Limit that triggers a global GC on the next (normally caused) GC. This
// is checked when we have already decided to do a GC to help determine
// which collector to invoke.
- static intptr_t old_gen_promotion_limit_;
+ intptr_t old_gen_promotion_limit_;
// Limit that triggers a global GC as soon as is reasonable. This is
// checked before expanding a paged space in the old generation and on
// every allocation in large object space.
- static intptr_t old_gen_allocation_limit_;
+ intptr_t old_gen_allocation_limit_;
// Limit on the amount of externally allocated memory allowed
// between global GCs. If reached a global GC is forced.
- static intptr_t external_allocation_limit_;
+ intptr_t external_allocation_limit_;
// The amount of external memory registered through the API kept alive
// by global handles
- static int amount_of_external_allocated_memory_;
+ int amount_of_external_allocated_memory_;
// Caches the amount of external memory registered at the last global gc.
- static int amount_of_external_allocated_memory_at_last_global_gc_;
+ int amount_of_external_allocated_memory_at_last_global_gc_;
// Indicates that an allocation has failed in the old generation since the
// last GC.
- static int old_gen_exhausted_;
+ int old_gen_exhausted_;
- static Object* roots_[kRootListLength];
+ Object* roots_[kRootListLength];
- static Object* global_contexts_list_;
+ Object* global_contexts_list_;
struct StringTypeTable {
InstanceType type;
@@ -1258,7 +1363,7 @@ class Heap : public AllStatic {
// The special hidden symbol which is an empty string, but does not match
// any string when looked up in properties.
- static String* hidden_symbol_;
+ String* hidden_symbol_;
// GC callback function, called before and after mark-compact GC.
// Allocations in the callback function are disallowed.
@@ -1272,7 +1377,7 @@ class Heap : public AllStatic {
GCPrologueCallback callback;
GCType gc_type;
};
- static List<GCPrologueCallbackPair> gc_prologue_callbacks_;
+ List<GCPrologueCallbackPair> gc_prologue_callbacks_;
struct GCEpilogueCallbackPair {
GCEpilogueCallbackPair(GCEpilogueCallback callback, GCType gc_type)
@@ -1284,91 +1389,91 @@ class Heap : public AllStatic {
GCEpilogueCallback callback;
GCType gc_type;
};
- static List<GCEpilogueCallbackPair> gc_epilogue_callbacks_;
+ List<GCEpilogueCallbackPair> gc_epilogue_callbacks_;
- static GCCallback global_gc_prologue_callback_;
- static GCCallback global_gc_epilogue_callback_;
+ GCCallback global_gc_prologue_callback_;
+ GCCallback global_gc_epilogue_callback_;
// Support for computing object sizes during GC.
- static HeapObjectCallback gc_safe_size_of_old_object_;
+ HeapObjectCallback gc_safe_size_of_old_object_;
static int GcSafeSizeOfOldObject(HeapObject* object);
static int GcSafeSizeOfOldObjectWithEncodedMap(HeapObject* object);
// Update the GC state. Called from the mark-compact collector.
- static void MarkMapPointersAsEncoded(bool encoded) {
+ void MarkMapPointersAsEncoded(bool encoded) {
gc_safe_size_of_old_object_ = encoded
? &GcSafeSizeOfOldObjectWithEncodedMap
: &GcSafeSizeOfOldObject;
}
// Checks whether a global GC is necessary
- static GarbageCollector SelectGarbageCollector(AllocationSpace space);
+ GarbageCollector SelectGarbageCollector(AllocationSpace space);
// Performs garbage collection
// Returns whether there is a chance another major GC could
// collect more garbage.
- static bool PerformGarbageCollection(GarbageCollector collector,
- GCTracer* tracer);
+ bool PerformGarbageCollection(GarbageCollector collector,
+ GCTracer* tracer);
+
+ static const intptr_t kMinimumPromotionLimit = 2 * MB;
+ static const intptr_t kMinimumAllocationLimit = 8 * MB;
+
+ inline void UpdateOldSpaceLimits();
// Allocate an uninitialized object in map space. The behavior is identical
// to Heap::AllocateRaw(size_in_bytes, MAP_SPACE), except that (a) it doesn't
// have to test the allocation space argument and (b) can reduce code size
// (since both AllocateRaw and AllocateRawMap are inlined).
- MUST_USE_RESULT static inline MaybeObject* AllocateRawMap();
+ MUST_USE_RESULT inline MaybeObject* AllocateRawMap();
// Allocate an uninitialized object in the global property cell space.
- MUST_USE_RESULT static inline MaybeObject* AllocateRawCell();
+ MUST_USE_RESULT inline MaybeObject* AllocateRawCell();
// Initializes a JSObject based on its map.
- static void InitializeJSObjectFromMap(JSObject* obj,
- FixedArray* properties,
- Map* map);
+ void InitializeJSObjectFromMap(JSObject* obj,
+ FixedArray* properties,
+ Map* map);
- static bool CreateInitialMaps();
- static bool CreateInitialObjects();
+ bool CreateInitialMaps();
+ bool CreateInitialObjects();
// These five Create*EntryStub functions are here and forced to not be inlined
// because of a gcc-4.4 bug that assigns wrong vtable entries.
- NO_INLINE(static void CreateCEntryStub());
- NO_INLINE(static void CreateJSEntryStub());
- NO_INLINE(static void CreateJSConstructEntryStub());
- NO_INLINE(static void CreateRegExpCEntryStub());
- NO_INLINE(static void CreateDirectCEntryStub());
+ NO_INLINE(void CreateJSEntryStub());
+ NO_INLINE(void CreateJSConstructEntryStub());
- static void CreateFixedStubs();
+ void CreateFixedStubs();
- MUST_USE_RESULT static MaybeObject* CreateOddball(const char* to_string,
- Object* to_number);
+ MaybeObject* CreateOddball(const char* to_string,
+ Object* to_number,
+ byte kind);
// Allocate empty fixed array.
- MUST_USE_RESULT static MaybeObject* AllocateEmptyFixedArray();
+ MUST_USE_RESULT MaybeObject* AllocateEmptyFixedArray();
// Performs a minor collection in new generation.
- static void Scavenge();
+ void Scavenge();
static String* UpdateNewSpaceReferenceInExternalStringTableEntry(
+ Heap* heap,
Object** pointer);
- static Address DoScavenge(ObjectVisitor* scavenge_visitor,
- Address new_space_front);
+ Address DoScavenge(ObjectVisitor* scavenge_visitor, Address new_space_front);
// Performs a major collection in the whole heap.
- static void MarkCompact(GCTracer* tracer);
+ void MarkCompact(GCTracer* tracer);
// Code to be run before and after mark-compact.
- static void MarkCompactPrologue(bool is_compacting);
+ void MarkCompactPrologue(bool is_compacting);
// Completely clear the Instanceof cache (to stop it keeping objects alive
// around a GC).
- static void CompletelyClearInstanceofCache() {
- set_instanceof_cache_map(the_hole_value());
- set_instanceof_cache_function(the_hole_value());
- }
+ inline void CompletelyClearInstanceofCache();
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
// Record statistics before and after garbage collection.
- static void ReportStatisticsBeforeGC();
- static void ReportStatisticsAfterGC();
+ void ReportStatisticsBeforeGC();
+ void ReportStatisticsAfterGC();
#endif
// Slow part of scavenge object.
@@ -1380,39 +1485,39 @@ class Heap : public AllStatic {
// other parts of the VM could use it. Specifically, a function that creates
// instances of type JS_FUNCTION_TYPE benefit from the use of this function.
// Please note this does not perform a garbage collection.
- MUST_USE_RESULT static inline MaybeObject* InitializeFunction(
+ MUST_USE_RESULT inline MaybeObject* InitializeFunction(
JSFunction* function,
SharedFunctionInfo* shared,
Object* prototype);
- static GCTracer* tracer_;
+ GCTracer* tracer_;
// Initializes the number to string cache based on the max semispace size.
- MUST_USE_RESULT static MaybeObject* InitializeNumberStringCache();
+ MUST_USE_RESULT MaybeObject* InitializeNumberStringCache();
// Flush the number to string cache.
- static void FlushNumberStringCache();
+ void FlushNumberStringCache();
- static void UpdateSurvivalRateTrend(int start_new_space_size);
+ void UpdateSurvivalRateTrend(int start_new_space_size);
enum SurvivalRateTrend { INCREASING, STABLE, DECREASING, FLUCTUATING };
static const int kYoungSurvivalRateThreshold = 90;
static const int kYoungSurvivalRateAllowedDeviation = 15;
- static int young_survivors_after_last_gc_;
- static int high_survival_rate_period_length_;
- static double survival_rate_;
- static SurvivalRateTrend previous_survival_rate_trend_;
- static SurvivalRateTrend survival_rate_trend_;
+ int young_survivors_after_last_gc_;
+ int high_survival_rate_period_length_;
+ double survival_rate_;
+ SurvivalRateTrend previous_survival_rate_trend_;
+ SurvivalRateTrend survival_rate_trend_;
- static void set_survival_rate_trend(SurvivalRateTrend survival_rate_trend) {
+ void set_survival_rate_trend(SurvivalRateTrend survival_rate_trend) {
ASSERT(survival_rate_trend != FLUCTUATING);
previous_survival_rate_trend_ = survival_rate_trend_;
survival_rate_trend_ = survival_rate_trend;
}
- static SurvivalRateTrend survival_rate_trend() {
+ SurvivalRateTrend survival_rate_trend() {
if (survival_rate_trend_ == STABLE) {
return STABLE;
} else if (previous_survival_rate_trend_ == STABLE) {
@@ -1424,7 +1529,7 @@ class Heap : public AllStatic {
}
}
- static bool IsStableOrIncreasingSurvivalTrend() {
+ bool IsStableOrIncreasingSurvivalTrend() {
switch (survival_rate_trend()) {
case STABLE:
case INCREASING:
@@ -1434,22 +1539,64 @@ class Heap : public AllStatic {
}
}
- static bool IsIncreasingSurvivalTrend() {
+ bool IsIncreasingSurvivalTrend() {
return survival_rate_trend() == INCREASING;
}
- static bool IsHighSurvivalRate() {
+ bool IsHighSurvivalRate() {
return high_survival_rate_period_length_ > 0;
}
static const int kInitialSymbolTableSize = 2048;
static const int kInitialEvalCacheSize = 64;
+ // Maximum GC pause.
+ int max_gc_pause_;
+
+ // Maximum size of objects alive after GC.
+ intptr_t max_alive_after_gc_;
+
+ // Minimal interval between two subsequent collections.
+ int min_in_mutator_;
+
+ // Size of objects alive after last GC.
+ intptr_t alive_after_last_gc_;
+
+ double last_gc_end_timestamp_;
+
+ MarkCompactCollector mark_compact_collector_;
+
+ // This field contains the meaning of the WATERMARK_INVALIDATED flag.
+ // Instead of clearing this flag from all pages we just flip
+ // its meaning at the beginning of a scavenge.
+ intptr_t page_watermark_invalidated_mark_;
+
+ int number_idle_notifications_;
+ unsigned int last_idle_notification_gc_count_;
+ bool last_idle_notification_gc_count_init_;
+
+ // Shared state read by the scavenge collector and set by ScavengeObject.
+ PromotionQueue promotion_queue_;
+
+ // Flag is set when the heap has been configured. The heap can be repeatedly
+ // configured through the API until it is setup.
+ bool configured_;
+
+ ExternalStringTable external_string_table_;
+
+ bool is_safe_to_read_maps_;
+
friend class Factory;
+ friend class GCTracer;
friend class DisallowAllocationFailure;
friend class AlwaysAllocateScope;
friend class LinearAllocationScope;
+ friend class Page;
+ friend class Isolate;
friend class MarkCompactCollector;
+ friend class MapCompact;
+
+ DISALLOW_COPY_AND_ASSIGN(Heap);
};
@@ -1493,13 +1640,13 @@ class AlwaysAllocateScope {
// non-handle code to call handle code. The code still works but
// performance will degrade, so we want to catch this situation
// in debug mode.
- ASSERT(Heap::always_allocate_scope_depth_ == 0);
- Heap::always_allocate_scope_depth_++;
+ ASSERT(HEAP->always_allocate_scope_depth_ == 0);
+ HEAP->always_allocate_scope_depth_++;
}
~AlwaysAllocateScope() {
- Heap::always_allocate_scope_depth_--;
- ASSERT(Heap::always_allocate_scope_depth_ == 0);
+ HEAP->always_allocate_scope_depth_--;
+ ASSERT(HEAP->always_allocate_scope_depth_ == 0);
}
};
@@ -1507,12 +1654,12 @@ class AlwaysAllocateScope {
class LinearAllocationScope {
public:
LinearAllocationScope() {
- Heap::linear_allocation_scope_depth_++;
+ HEAP->linear_allocation_scope_depth_++;
}
~LinearAllocationScope() {
- Heap::linear_allocation_scope_depth_--;
- ASSERT(Heap::linear_allocation_scope_depth_ >= 0);
+ HEAP->linear_allocation_scope_depth_--;
+ ASSERT(HEAP->linear_allocation_scope_depth_ >= 0);
}
};
@@ -1529,7 +1676,7 @@ class VerifyPointersVisitor: public ObjectVisitor {
for (Object** current = start; current < end; current++) {
if ((*current)->IsHeapObject()) {
HeapObject* object = HeapObject::cast(*current);
- ASSERT(Heap::Contains(object));
+ ASSERT(HEAP->Contains(object));
ASSERT(object->map()->IsMap());
}
}
@@ -1547,10 +1694,10 @@ class VerifyPointersAndDirtyRegionsVisitor: public ObjectVisitor {
for (Object** current = start; current < end; current++) {
if ((*current)->IsHeapObject()) {
HeapObject* object = HeapObject::cast(*current);
- ASSERT(Heap::Contains(object));
+ ASSERT(HEAP->Contains(object));
ASSERT(object->map()->IsMap());
- if (Heap::InNewSpace(object)) {
- ASSERT(Heap::InToSpace(object));
+ if (HEAP->InNewSpace(object)) {
+ ASSERT(HEAP->InToSpace(object));
Address addr = reinterpret_cast<Address>(current);
ASSERT(Page::FromAddress(addr)->IsRegionDirty(addr));
}
@@ -1664,28 +1811,37 @@ class HeapIterator BASE_EMBEDDED {
class KeyedLookupCache {
public:
// Lookup field offset for (map, name). If absent, -1 is returned.
- static int Lookup(Map* map, String* name);
+ int Lookup(Map* map, String* name);
// Update an element in the cache.
- static void Update(Map* map, String* name, int field_offset);
+ void Update(Map* map, String* name, int field_offset);
// Clear the cache.
- static void Clear();
+ void Clear();
static const int kLength = 64;
static const int kCapacityMask = kLength - 1;
static const int kMapHashShift = 2;
+ static const int kNotFound = -1;
private:
+ KeyedLookupCache() {
+ for (int i = 0; i < kLength; ++i) {
+ keys_[i].map = NULL;
+ keys_[i].name = NULL;
+ field_offsets_[i] = kNotFound;
+ }
+ }
+
static inline int Hash(Map* map, String* name);
// Get the address of the keys and field_offsets arrays. Used in
// generated code to perform cache lookups.
- static Address keys_address() {
+ Address keys_address() {
return reinterpret_cast<Address>(&keys_);
}
- static Address field_offsets_address() {
+ Address field_offsets_address() {
return reinterpret_cast<Address>(&field_offsets_);
}
@@ -1693,10 +1849,13 @@ class KeyedLookupCache {
Map* map;
String* name;
};
- static Key keys_[kLength];
- static int field_offsets_[kLength];
+
+ Key keys_[kLength];
+ int field_offsets_[kLength];
friend class ExternalReference;
+ friend class Isolate;
+ DISALLOW_COPY_AND_ASSIGN(KeyedLookupCache);
};
@@ -1708,7 +1867,7 @@ class DescriptorLookupCache {
public:
// Lookup descriptor index for (map, name).
// If absent, kAbsent is returned.
- static int Lookup(DescriptorArray* array, String* name) {
+ int Lookup(DescriptorArray* array, String* name) {
if (!StringShape(name).IsSymbol()) return kAbsent;
int index = Hash(array, name);
Key& key = keys_[index];
@@ -1717,7 +1876,7 @@ class DescriptorLookupCache {
}
// Update an element in the cache.
- static void Update(DescriptorArray* array, String* name, int result) {
+ void Update(DescriptorArray* array, String* name, int result) {
ASSERT(result != kAbsent);
if (StringShape(name).IsSymbol()) {
int index = Hash(array, name);
@@ -1729,10 +1888,18 @@ class DescriptorLookupCache {
}
// Clear the cache.
- static void Clear();
+ void Clear();
static const int kAbsent = -2;
private:
+ DescriptorLookupCache() {
+ for (int i = 0; i < kLength; ++i) {
+ keys_[i].array = NULL;
+ keys_[i].name = NULL;
+ results_[i] = kAbsent;
+ }
+ }
+
static int Hash(DescriptorArray* array, String* name) {
// Uses only lower 32 bits if pointers are larger.
uint32_t array_hash =
@@ -1748,55 +1915,11 @@ class DescriptorLookupCache {
String* name;
};
- static Key keys_[kLength];
- static int results_[kLength];
-};
-
+ Key keys_[kLength];
+ int results_[kLength];
-// ----------------------------------------------------------------------------
-// Marking stack for tracing live objects.
-
-class MarkingStack {
- public:
- void Initialize(Address low, Address high) {
- top_ = low_ = reinterpret_cast<HeapObject**>(low);
- high_ = reinterpret_cast<HeapObject**>(high);
- overflowed_ = false;
- }
-
- bool is_full() { return top_ >= high_; }
-
- bool is_empty() { return top_ <= low_; }
-
- bool overflowed() { return overflowed_; }
-
- void clear_overflowed() { overflowed_ = false; }
-
- // Push the (marked) object on the marking stack if there is room,
- // otherwise mark the object as overflowed and wait for a rescan of the
- // heap.
- void Push(HeapObject* object) {
- CHECK(object->IsHeapObject());
- if (is_full()) {
- object->SetOverflow();
- overflowed_ = true;
- } else {
- *(top_++) = object;
- }
- }
-
- HeapObject* Pop() {
- ASSERT(!is_empty());
- HeapObject* object = *(--top_);
- CHECK(object->IsHeapObject());
- return object;
- }
-
- private:
- HeapObject** low_;
- HeapObject** top_;
- HeapObject** high_;
- bool overflowed_;
+ friend class Isolate;
+ DISALLOW_COPY_AND_ASSIGN(DescriptorLookupCache);
};
@@ -1813,11 +1936,11 @@ class MarkingStack {
class DisallowAllocationFailure {
public:
DisallowAllocationFailure() {
- old_state_ = Heap::disallow_allocation_failure_;
- Heap::disallow_allocation_failure_ = true;
+ old_state_ = HEAP->disallow_allocation_failure_;
+ HEAP->disallow_allocation_failure_ = true;
}
~DisallowAllocationFailure() {
- Heap::disallow_allocation_failure_ = old_state_;
+ HEAP->disallow_allocation_failure_ = old_state_;
}
private:
bool old_state_;
@@ -1826,11 +1949,11 @@ class DisallowAllocationFailure {
class AssertNoAllocation {
public:
AssertNoAllocation() {
- old_state_ = Heap::allow_allocation(false);
+ old_state_ = HEAP->allow_allocation(false);
}
~AssertNoAllocation() {
- Heap::allow_allocation(old_state_);
+ HEAP->allow_allocation(old_state_);
}
private:
@@ -1840,11 +1963,11 @@ class AssertNoAllocation {
class DisableAssertNoAllocation {
public:
DisableAssertNoAllocation() {
- old_state_ = Heap::allow_allocation(true);
+ old_state_ = HEAP->allow_allocation(true);
}
~DisableAssertNoAllocation() {
- Heap::allow_allocation(old_state_);
+ HEAP->allow_allocation(old_state_);
}
private:
@@ -1901,7 +2024,7 @@ class GCTracer BASE_EMBEDDED {
double start_time_;
};
- GCTracer();
+ explicit GCTracer(Heap* heap);
~GCTracer();
// Sets the collector.
@@ -1927,22 +2050,13 @@ class GCTracer BASE_EMBEDDED {
promoted_objects_size_ += object_size;
}
- // Returns maximum GC pause.
- static int get_max_gc_pause() { return max_gc_pause_; }
-
- // Returns maximum size of objects alive after GC.
- static intptr_t get_max_alive_after_gc() { return max_alive_after_gc_; }
-
- // Returns minimal interval between two subsequent collections.
- static int get_min_in_mutator() { return min_in_mutator_; }
-
private:
// Returns a string matching the collector.
const char* CollectorString();
// Returns size of object in heap (in MB).
double SizeOfHeapObjects() {
- return (static_cast<double>(Heap::SizeOfObjects())) / MB;
+ return (static_cast<double>(HEAP->SizeOfObjects())) / MB;
}
double start_time_; // Timestamp set in the constructor.
@@ -1991,19 +2105,7 @@ class GCTracer BASE_EMBEDDED {
// Size of objects promoted during the current collection.
intptr_t promoted_objects_size_;
- // Maximum GC pause.
- static int max_gc_pause_;
-
- // Maximum size of objects alive after GC.
- static intptr_t max_alive_after_gc_;
-
- // Minimal interval between two subsequent collections.
- static int min_in_mutator_;
-
- // Size of objects alive after last GC.
- static intptr_t alive_after_last_gc_;
-
- static double last_gc_end_timestamp_;
+ Heap* heap_;
};
@@ -2013,131 +2115,71 @@ class TranscendentalCache {
static const int kTranscendentalTypeBits = 3;
STATIC_ASSERT((1 << kTranscendentalTypeBits) >= kNumberOfCaches);
- explicit TranscendentalCache(Type t);
-
// Returns a heap number with f(input), where f is a math function specified
// by the 'type' argument.
- MUST_USE_RESULT static inline MaybeObject* Get(Type type, double input) {
- TranscendentalCache* cache = caches_[type];
- if (cache == NULL) {
- caches_[type] = cache = new TranscendentalCache(type);
- }
- return cache->Get(input);
- }
+ MUST_USE_RESULT inline MaybeObject* Get(Type type, double input);
// The cache contains raw Object pointers. This method disposes of
// them before a garbage collection.
- static void Clear();
+ void Clear();
private:
- MUST_USE_RESULT inline MaybeObject* Get(double input) {
- Converter c;
- c.dbl = input;
- int hash = Hash(c);
- Element e = elements_[hash];
- if (e.in[0] == c.integers[0] &&
- e.in[1] == c.integers[1]) {
- ASSERT(e.output != NULL);
- Counters::transcendental_cache_hit.Increment();
- return e.output;
- }
- double answer = Calculate(input);
- Counters::transcendental_cache_miss.Increment();
- Object* heap_number;
- { MaybeObject* maybe_heap_number = Heap::AllocateHeapNumber(answer);
- if (!maybe_heap_number->ToObject(&heap_number)) return maybe_heap_number;
- }
- elements_[hash].in[0] = c.integers[0];
- elements_[hash].in[1] = c.integers[1];
- elements_[hash].output = heap_number;
- return heap_number;
- }
+ class SubCache {
+ static const int kCacheSize = 512;
- inline double Calculate(double input) {
- switch (type_) {
- case ACOS:
- return acos(input);
- case ASIN:
- return asin(input);
- case ATAN:
- return atan(input);
- case COS:
- return cos(input);
- case EXP:
- return exp(input);
- case LOG:
- return log(input);
- case SIN:
- return sin(input);
- case TAN:
- return tan(input);
- default:
- return 0.0; // Never happens.
- }
- }
- static const int kCacheSize = 512;
- struct Element {
- uint32_t in[2];
- Object* output;
- };
- union Converter {
- double dbl;
- uint32_t integers[2];
- };
- inline static int Hash(const Converter& c) {
- uint32_t hash = (c.integers[0] ^ c.integers[1]);
- hash ^= static_cast<int32_t>(hash) >> 16;
- hash ^= static_cast<int32_t>(hash) >> 8;
- return (hash & (kCacheSize - 1));
- }
+ explicit SubCache(Type t);
- static Address cache_array_address() {
- // Used to create an external reference.
- return reinterpret_cast<Address>(caches_);
- }
+ MUST_USE_RESULT inline MaybeObject* Get(double input);
- // Allow access to the caches_ array as an ExternalReference.
- friend class ExternalReference;
- // Inline implementation of the cache.
- friend class TranscendentalCacheStub;
-
- static TranscendentalCache* caches_[kNumberOfCaches];
- Element elements_[kCacheSize];
- Type type_;
-};
+ inline double Calculate(double input);
+ struct Element {
+ uint32_t in[2];
+ Object* output;
+ };
-// External strings table is a place where all external strings are
-// registered. We need to keep track of such strings to properly
-// finalize them.
-class ExternalStringTable : public AllStatic {
- public:
- // Registers an external string.
- inline static void AddString(String* string);
+ union Converter {
+ double dbl;
+ uint32_t integers[2];
+ };
- inline static void Iterate(ObjectVisitor* v);
+ inline static int Hash(const Converter& c) {
+ uint32_t hash = (c.integers[0] ^ c.integers[1]);
+ hash ^= static_cast<int32_t>(hash) >> 16;
+ hash ^= static_cast<int32_t>(hash) >> 8;
+ return (hash & (kCacheSize - 1));
+ }
- // Restores internal invariant and gets rid of collected strings.
- // Must be called after each Iterate() that modified the strings.
- static void CleanUp();
+ Element elements_[kCacheSize];
+ Type type_;
+ Isolate* isolate_;
- // Destroys all allocated memory.
- static void TearDown();
+ // Allow access to the caches_ array as an ExternalReference.
+ friend class ExternalReference;
+ // Inline implementation of the cache.
+ friend class TranscendentalCacheStub;
+ // For evaluating value.
+ friend class TranscendentalCache;
- private:
- friend class Heap;
+ DISALLOW_COPY_AND_ASSIGN(SubCache);
+ };
- inline static void Verify();
+ TranscendentalCache() {
+ for (int i = 0; i < kNumberOfCaches; ++i) caches_[i] = NULL;
+ }
- inline static void AddOldString(String* string);
+ // Used to create an external reference.
+ inline Address cache_array_address();
- // Notifies the table that only a prefix of the new list is valid.
- inline static void ShrinkNewStrings(int position);
+ // Instantiation
+ friend class Isolate;
+ // Inline implementation of the caching.
+ friend class TranscendentalCacheStub;
+ // Allow access to the caches_ array as an ExternalReference.
+ friend class ExternalReference;
- // To speed up scavenge collections new space string are kept
- // separate from old space strings.
- static List<Object*> new_space_strings_;
- static List<Object*> old_space_strings_;
+ SubCache* caches_[kNumberOfCaches];
+ DISALLOW_COPY_AND_ASSIGN(TranscendentalCache);
};
@@ -2214,4 +2256,6 @@ class PathTracer : public ObjectVisitor {
} } // namespace v8::internal
+#undef HEAP
+
#endif // V8_HEAP_H_
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index c2e5c8bd..9bbe1649 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -36,6 +36,8 @@
#include "x64/lithium-x64.h"
#elif V8_TARGET_ARCH_ARM
#include "arm/lithium-arm.h"
+#elif V8_TARGET_ARCH_MIPS
+#include "mips/lithium-mips.h"
#else
#error Unsupported target architecture.
#endif
@@ -414,10 +416,7 @@ bool HValue::UpdateInferredType() {
void HValue::RegisterUse(int index, HValue* new_value) {
HValue* old_value = OperandAt(index);
if (old_value == new_value) return;
- if (old_value != NULL) {
- ASSERT(old_value->uses_.Contains(this));
- old_value->uses_.RemoveElement(this);
- }
+ if (old_value != NULL) old_value->uses_.RemoveElement(this);
if (new_value != NULL) {
new_value->uses_.Add(this);
}
@@ -933,6 +932,14 @@ void HPhi::AddInput(HValue* value) {
}
+bool HPhi::HasRealUses() {
+ for (int i = 0; i < uses()->length(); i++) {
+ if (!uses()->at(i)->IsPhi()) return true;
+ }
+ return false;
+}
+
+
HValue* HPhi::GetRedundantReplacement() {
HValue* candidate = NULL;
int count = OperandCount();
@@ -1038,7 +1045,7 @@ HConstant* HConstant::CopyToRepresentation(Representation r) const {
HConstant* HConstant::CopyToTruncatedInt32() const {
if (!has_double_value_) return NULL;
int32_t truncated = NumberToInt32(*handle_);
- return new HConstant(Factory::NewNumberFromInt(truncated),
+ return new HConstant(FACTORY->NewNumberFromInt(truncated),
Representation::Integer32());
}
@@ -1049,7 +1056,7 @@ void HConstant::PrintDataTo(StringStream* stream) {
bool HArrayLiteral::IsCopyOnWrite() const {
- return constant_elements()->map() == Heap::fixed_cow_array_map();
+ return constant_elements()->map() == HEAP->fixed_cow_array_map();
}
@@ -1151,6 +1158,60 @@ void HLoadNamedField::PrintDataTo(StringStream* stream) {
}
+HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* object,
+ ZoneMapList* types,
+ Handle<String> name)
+ : HUnaryOperation(object),
+ types_(Min(types->length(), kMaxLoadPolymorphism)),
+ name_(name),
+ need_generic_(false) {
+ set_representation(Representation::Tagged());
+ SetFlag(kDependsOnMaps);
+ for (int i = 0;
+ i < types->length() && types_.length() < kMaxLoadPolymorphism;
+ ++i) {
+ Handle<Map> map = types->at(i);
+ LookupResult lookup;
+ map->LookupInDescriptors(NULL, *name, &lookup);
+ if (lookup.IsProperty() && lookup.type() == FIELD) {
+ types_.Add(types->at(i));
+ int index = lookup.GetLocalFieldIndexFromMap(*map);
+ if (index < 0) {
+ SetFlag(kDependsOnInobjectFields);
+ } else {
+ SetFlag(kDependsOnBackingStoreFields);
+ }
+ }
+ }
+
+ if (types_.length() == types->length() && FLAG_deoptimize_uncommon_cases) {
+ SetFlag(kUseGVN);
+ } else {
+ SetAllSideEffects();
+ need_generic_ = true;
+ }
+}
+
+
+bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
+ HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
+ if (types_.length() != other->types()->length()) return false;
+ if (!name_.is_identical_to(other->name())) return false;
+ if (need_generic_ != other->need_generic_) return false;
+ for (int i = 0; i < types_.length(); i++) {
+ bool found = false;
+ for (int j = 0; j < types_.length(); j++) {
+ if (types_.at(j).is_identical_to(other->types()->at(i))) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return false;
+ }
+ return true;
+}
+
+
void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
stream->Add("[");
@@ -1167,8 +1228,36 @@ void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) {
}
-void HLoadPixelArrayElement::PrintDataTo(StringStream* stream) {
+void HLoadKeyedSpecializedArrayElement::PrintDataTo(
+ StringStream* stream) {
external_pointer()->PrintNameTo(stream);
+ stream->Add(".");
+ switch (array_type()) {
+ case kExternalByteArray:
+ stream->Add("byte");
+ break;
+ case kExternalUnsignedByteArray:
+ stream->Add("u_byte");
+ break;
+ case kExternalShortArray:
+ stream->Add("short");
+ break;
+ case kExternalUnsignedShortArray:
+ stream->Add("u_short");
+ break;
+ case kExternalIntArray:
+ stream->Add("int");
+ break;
+ case kExternalUnsignedIntArray:
+ stream->Add("u_int");
+ break;
+ case kExternalFloatArray:
+ stream->Add("float");
+ break;
+ case kExternalPixelArray:
+ stream->Add("pixel");
+ break;
+ }
stream->Add("[");
key()->PrintNameTo(stream);
stream->Add("]");
@@ -1216,8 +1305,36 @@ void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
}
-void HStorePixelArrayElement::PrintDataTo(StringStream* stream) {
+void HStoreKeyedSpecializedArrayElement::PrintDataTo(
+ StringStream* stream) {
external_pointer()->PrintNameTo(stream);
+ stream->Add(".");
+ switch (array_type()) {
+ case kExternalByteArray:
+ stream->Add("byte");
+ break;
+ case kExternalUnsignedByteArray:
+ stream->Add("u_byte");
+ break;
+ case kExternalShortArray:
+ stream->Add("short");
+ break;
+ case kExternalUnsignedShortArray:
+ stream->Add("u_short");
+ break;
+ case kExternalIntArray:
+ stream->Add("int");
+ break;
+ case kExternalUnsignedIntArray:
+ stream->Add("u_int");
+ break;
+ case kExternalFloatArray:
+ stream->Add("float");
+ break;
+ case kExternalPixelArray:
+ stream->Add("pixel");
+ break;
+ }
stream->Add("[");
key()->PrintNameTo(stream);
stream->Add("] = ");
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index cc753546..fed4b8bf 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -29,7 +29,9 @@
#define V8_HYDROGEN_INSTRUCTIONS_H_
#include "v8.h"
+
#include "code-stubs.h"
+#include "small-pointer-list.h"
#include "string-stream.h"
#include "zone.h"
@@ -91,6 +93,7 @@ class LChunkBuilder;
V(CheckNonSmi) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
+ V(ClassOfTest) \
V(Compare) \
V(CompareJSObjectEq) \
V(CompareMap) \
@@ -100,40 +103,40 @@ class LChunkBuilder;
V(Deoptimize) \
V(Div) \
V(EnterInlined) \
+ V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
V(GlobalReceiver) \
V(Goto) \
+ V(HasInstanceType) \
+ V(HasCachedArrayIndex) \
V(InstanceOf) \
V(InstanceOfKnownGlobal) \
V(IsNull) \
V(IsObject) \
V(IsSmi) \
V(IsConstructCall) \
- V(HasInstanceType) \
- V(HasCachedArrayIndex) \
V(JSArrayLength) \
- V(ClassOfTest) \
V(LeaveInlined) \
V(LoadContextSlot) \
V(LoadElements) \
+ V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
+ V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
+ V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
- V(LoadPixelArrayElement) \
- V(LoadPixelArrayExternalPointer) \
V(Mod) \
V(Mul) \
V(ObjectLiteral) \
V(OsrEntry) \
V(OuterContext) \
V(Parameter) \
- V(PixelArrayLength) \
V(Power) \
V(PushArgument) \
V(RegExpLiteral) \
@@ -146,15 +149,17 @@ class LChunkBuilder;
V(StoreContextSlot) \
V(StoreGlobal) \
V(StoreKeyedFastElement) \
- V(StorePixelArrayElement) \
+ V(StoreKeyedSpecializedArrayElement) \
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(StringCharCodeAt) \
+ V(StringCharFromCode) \
V(StringLength) \
V(Sub) \
V(Test) \
V(Throw) \
+ V(ToFastProperties) \
V(Typeof) \
V(TypeofIs) \
V(UnaryMathOperation) \
@@ -166,7 +171,7 @@ class LChunkBuilder;
V(InobjectFields) \
V(BackingStoreFields) \
V(ArrayElements) \
- V(PixelArrayElements) \
+ V(SpecializedArrayElements) \
V(GlobalVars) \
V(Maps) \
V(ArrayLengths) \
@@ -449,7 +454,6 @@ class HValue: public ZoneObject {
HValue() : block_(NULL),
id_(kNoNumber),
- uses_(2),
type_(HType::Tagged()),
range_(NULL),
flags_(0) {}
@@ -461,9 +465,9 @@ class HValue: public ZoneObject {
int id() const { return id_; }
void set_id(int id) { id_ = id; }
- const ZoneList<HValue*>* uses() const { return &uses_; }
+ SmallPointerList<HValue>* uses() { return &uses_; }
- virtual bool EmitAtUses() const { return false; }
+ virtual bool EmitAtUses() { return false; }
Representation representation() const { return representation_; }
void ChangeRepresentation(Representation r) {
// Representation was already set and is allowed to be changed.
@@ -605,7 +609,7 @@ class HValue: public ZoneObject {
int id_;
Representation representation_;
- ZoneList<HValue*> uses_;
+ SmallPointerList<HValue> uses_;
HType type_;
Range* range_;
int flags_;
@@ -756,15 +760,33 @@ class HBlockEntry: public HTemplateInstruction<0> {
};
-class HDeoptimize: public HTemplateControlInstruction<0> {
+class HDeoptimize: public HControlInstruction {
public:
- HDeoptimize() : HTemplateControlInstruction<0>(NULL, NULL) { }
+ explicit HDeoptimize(int environment_length)
+ : HControlInstruction(NULL, NULL),
+ values_(environment_length) { }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::None();
}
+ virtual int OperandCount() { return values_.length(); }
+ virtual HValue* OperandAt(int index) { return values_[index]; }
+
+ void AddEnvironmentValue(HValue* value) {
+ values_.Add(NULL);
+ SetOperandAt(values_.length() - 1, value);
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
+
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value) {
+ values_[index] = value;
+ }
+
+ private:
+ ZoneList<HValue*> values_;
};
@@ -1225,7 +1247,8 @@ class HCallConstantFunction: public HCall<0> {
Handle<JSFunction> function() const { return function_; }
bool IsApplyFunction() const {
- return function_->code() == Builtins::builtin(Builtins::FunctionApply);
+ return function_->code() ==
+ Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply);
}
virtual void PrintDataTo(StringStream* stream);
@@ -1358,12 +1381,12 @@ class HCallNew: public HBinaryCall {
class HCallRuntime: public HCall<0> {
public:
HCallRuntime(Handle<String> name,
- Runtime::Function* c_function,
+ const Runtime::Function* c_function,
int argument_count)
: HCall<0>(argument_count), c_function_(c_function), name_(name) { }
virtual void PrintDataTo(StringStream* stream);
- Runtime::Function* function() const { return c_function_; }
+ const Runtime::Function* function() const { return c_function_; }
Handle<String> name() const { return name_; }
virtual Representation RequiredInputRepresentation(int index) const {
@@ -1373,7 +1396,7 @@ class HCallRuntime: public HCall<0> {
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call_runtime")
private:
- Runtime::Function* c_function_;
+ const Runtime::Function* c_function_;
Handle<String> name_;
};
@@ -1385,8 +1408,9 @@ class HJSArrayLength: public HUnaryOperation {
// object. It is guaranteed to be 32 bit integer, but it can be
// represented as either a smi or heap number.
set_representation(Representation::Tagged());
- SetFlag(kDependsOnArrayLengths);
SetFlag(kUseGVN);
+ SetFlag(kDependsOnArrayLengths);
+ SetFlag(kDependsOnMaps);
}
virtual Representation RequiredInputRepresentation(int index) const {
@@ -1404,8 +1428,8 @@ class HFixedArrayLength: public HUnaryOperation {
public:
explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged());
- SetFlag(kDependsOnArrayLengths);
SetFlag(kUseGVN);
+ SetFlag(kDependsOnArrayLengths);
}
virtual Representation RequiredInputRepresentation(int index) const {
@@ -1419,9 +1443,9 @@ class HFixedArrayLength: public HUnaryOperation {
};
-class HPixelArrayLength: public HUnaryOperation {
+class HExternalArrayLength: public HUnaryOperation {
public:
- explicit HPixelArrayLength(HValue* value) : HUnaryOperation(value) {
+ explicit HExternalArrayLength(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Integer32());
// The result of this instruction is idempotent as long as its inputs don't
// change. The length of a pixel array cannot change once set, so it's not
@@ -1433,7 +1457,7 @@ class HPixelArrayLength: public HUnaryOperation {
return Representation::Tagged();
}
- DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel_array_length")
+ DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external_array_length")
protected:
virtual bool DataEquals(HValue* other) { return true; }
@@ -1557,13 +1581,13 @@ class HLoadElements: public HUnaryOperation {
};
-class HLoadPixelArrayExternalPointer: public HUnaryOperation {
+class HLoadExternalArrayPointer: public HUnaryOperation {
public:
- explicit HLoadPixelArrayExternalPointer(HValue* value)
+ explicit HLoadExternalArrayPointer(HValue* value)
: HUnaryOperation(value) {
set_representation(Representation::External());
// The result of this instruction is idempotent as long as its inputs don't
- // change. The external array of a pixel array elements object cannot
+ // change. The external array of a specialized array elements object cannot
// change once set, so it's no necessary to introduce any additional
// dependencies on top of the inputs.
SetFlag(kUseGVN);
@@ -1573,8 +1597,8 @@ class HLoadPixelArrayExternalPointer: public HUnaryOperation {
return Representation::Tagged();
}
- DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer,
- "load-pixel-array-external-pointer")
+ DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer,
+ "load-external-array-pointer")
protected:
virtual bool DataEquals(HValue* other) { return true; }
@@ -1751,7 +1775,7 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
}
virtual intptr_t Hashcode() {
- ASSERT(!Heap::IsAllocationAllowed());
+ ASSERT(!HEAP->IsAllocationAllowed());
intptr_t hash = reinterpret_cast<intptr_t>(*prototype());
hash = 17 * hash + reinterpret_cast<intptr_t>(*holder());
return hash;
@@ -1800,7 +1824,8 @@ class HPhi: public HValue {
explicit HPhi(int merged_index)
: inputs_(2),
merged_index_(merged_index),
- phi_id_(-1) {
+ phi_id_(-1),
+ is_live_(false) {
for (int i = 0; i < Representation::kNumRepresentations; i++) {
non_phi_uses_[i] = 0;
indirect_uses_[i] = 0;
@@ -1834,6 +1859,7 @@ class HPhi: public HValue {
virtual HValue* OperandAt(int index) { return inputs_[index]; }
HValue* GetRedundantReplacement();
void AddInput(HValue* value);
+ bool HasRealUses();
bool IsReceiver() { return merged_index_ == 0; }
@@ -1872,6 +1898,8 @@ class HPhi: public HValue {
return indirect_uses_[Representation::kDouble];
}
int phi_id() { return phi_id_; }
+ bool is_live() { return is_live_; }
+ void set_is_live(bool b) { is_live_ = b; }
protected:
virtual void DeleteFromGraph();
@@ -1886,6 +1914,7 @@ class HPhi: public HValue {
int non_phi_uses_[Representation::kNumRepresentations];
int indirect_uses_[Representation::kNumRepresentations];
int phi_id_;
+ bool is_live_;
};
@@ -1910,13 +1939,13 @@ class HConstant: public HTemplateInstruction<0> {
Handle<Object> handle() const { return handle_; }
- bool InOldSpace() const { return !Heap::InNewSpace(*handle_); }
+ bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::None();
}
- virtual bool EmitAtUses() const { return !representation().IsDouble(); }
+ virtual bool EmitAtUses() { return !representation().IsDouble(); }
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
bool IsInteger() const { return handle_->IsSmi(); }
@@ -1935,7 +1964,7 @@ class HConstant: public HTemplateInstruction<0> {
bool HasStringValue() const { return handle_->IsString(); }
virtual intptr_t Hashcode() {
- ASSERT(!Heap::allow_allocation(false));
+ ASSERT(!HEAP->allow_allocation(false));
return reinterpret_cast<intptr_t>(*handle());
}
@@ -2191,7 +2220,7 @@ class HCompare: public HBinaryOperation {
void SetInputRepresentation(Representation r);
- virtual bool EmitAtUses() const {
+ virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
}
@@ -2230,9 +2259,10 @@ class HCompareJSObjectEq: public HBinaryOperation {
: HBinaryOperation(left, right) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
+ SetFlag(kDependsOnMaps);
}
- virtual bool EmitAtUses() const {
+ virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
}
@@ -2255,7 +2285,7 @@ class HUnaryPredicate: public HUnaryOperation {
SetFlag(kUseGVN);
}
- virtual bool EmitAtUses() const {
+ virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
}
@@ -2315,7 +2345,7 @@ class HIsConstructCall: public HTemplateInstruction<0> {
SetFlag(kUseGVN);
}
- virtual bool EmitAtUses() const {
+ virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
}
@@ -2437,7 +2467,7 @@ class HInstanceOf: public HTemplateInstruction<3> {
HValue* left() { return OperandAt(1); }
HValue* right() { return OperandAt(2); }
- virtual bool EmitAtUses() const {
+ virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
}
@@ -2562,6 +2592,16 @@ class HMod: public HArithmeticBinaryOperation {
SetFlag(kCanBeDivByZero);
}
+ bool HasPowerOf2Divisor() {
+ if (right()->IsConstant() &&
+ HConstant::cast(right())->HasInteger32Value()) {
+ int32_t value = HConstant::cast(right())->Integer32Value();
+ return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value));
+ }
+
+ return false;
+ }
+
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
DECLARE_CONCRETE_INSTRUCTION(Mod, "mod")
@@ -2784,7 +2824,7 @@ class HLoadGlobal: public HTemplateInstruction<0> {
virtual void PrintDataTo(StringStream* stream);
virtual intptr_t Hashcode() {
- ASSERT(!Heap::allow_allocation(false));
+ ASSERT(!HEAP->allow_allocation(false));
return reinterpret_cast<intptr_t>(*cell_);
}
@@ -2905,6 +2945,7 @@ class HLoadNamedField: public HUnaryOperation {
offset_(offset) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
+ SetFlag(kDependsOnMaps);
if (is_in_object) {
SetFlag(kDependsOnInobjectFields);
} else {
@@ -2935,6 +2976,37 @@ class HLoadNamedField: public HUnaryOperation {
};
+class HLoadNamedFieldPolymorphic: public HUnaryOperation {
+ public:
+ HLoadNamedFieldPolymorphic(HValue* object,
+ ZoneMapList* types,
+ Handle<String> name);
+
+ HValue* object() { return OperandAt(0); }
+ ZoneMapList* types() { return &types_; }
+ Handle<String> name() { return name_; }
+ bool need_generic() { return need_generic_; }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic,
+ "load_named_field_polymorphic")
+
+ static const int kMaxLoadPolymorphism = 4;
+
+ protected:
+ virtual bool DataEquals(HValue* value);
+
+ private:
+ ZoneMapList types_;
+ Handle<String> name_;
+ bool need_generic_;
+};
+
+
+
class HLoadNamedGeneric: public HBinaryOperation {
public:
HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
@@ -3007,13 +3079,20 @@ class HLoadKeyedFastElement: public HBinaryOperation {
};
-class HLoadPixelArrayElement: public HBinaryOperation {
+class HLoadKeyedSpecializedArrayElement: public HBinaryOperation {
public:
- HLoadPixelArrayElement(HValue* external_elements, HValue* key)
- : HBinaryOperation(external_elements, key) {
- set_representation(Representation::Integer32());
- SetFlag(kDependsOnPixelArrayElements);
- // Native code could change the pixel array.
+ HLoadKeyedSpecializedArrayElement(HValue* external_elements,
+ HValue* key,
+ ExternalArrayType array_type)
+ : HBinaryOperation(external_elements, key),
+ array_type_(array_type) {
+ if (array_type == kExternalFloatArray) {
+ set_representation(Representation::Double());
+ } else {
+ set_representation(Representation::Integer32());
+ }
+ SetFlag(kDependsOnSpecializedArrayElements);
+ // Native code could change the specialized array.
SetFlag(kDependsOnCalls);
SetFlag(kUseGVN);
}
@@ -3029,12 +3108,21 @@ class HLoadPixelArrayElement: public HBinaryOperation {
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
+ ExternalArrayType array_type() const { return array_type_; }
- DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
- "load_pixel_array_element")
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
+ "load_keyed_specialized_array_element")
protected:
- virtual bool DataEquals(HValue* other) { return true; }
+ virtual bool DataEquals(HValue* other) {
+ if (!other->IsLoadKeyedSpecializedArrayElement()) return false;
+ HLoadKeyedSpecializedArrayElement* cast_other =
+ HLoadKeyedSpecializedArrayElement::cast(other);
+ return array_type_ == cast_other->array_type();
+ }
+
+ private:
+ ExternalArrayType array_type_;
};
@@ -3169,10 +3257,14 @@ class HStoreKeyedFastElement: public HTemplateInstruction<3> {
};
-class HStorePixelArrayElement: public HTemplateInstruction<3> {
+class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
public:
- HStorePixelArrayElement(HValue* external_elements, HValue* key, HValue* val) {
- SetFlag(kChangesPixelArrayElements);
+ HStoreKeyedSpecializedArrayElement(HValue* external_elements,
+ HValue* key,
+ HValue* val,
+ ExternalArrayType array_type)
+ : array_type_(array_type) {
+ SetFlag(kChangesSpecializedArrayElements);
SetOperandAt(0, external_elements);
SetOperandAt(1, key);
SetOperandAt(2, val);
@@ -3184,16 +3276,23 @@ class HStorePixelArrayElement: public HTemplateInstruction<3> {
if (index == 0) {
return Representation::External();
} else {
- return Representation::Integer32();
+ if (index == 2 && array_type() == kExternalFloatArray) {
+ return Representation::Double();
+ } else {
+ return Representation::Integer32();
+ }
}
}
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
+ ExternalArrayType array_type() const { return array_type_; }
- DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
- "store_pixel_array_element")
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
+ "store_keyed_specialized_array_element")
+ private:
+ ExternalArrayType array_type_;
};
@@ -3231,6 +3330,7 @@ class HStringCharCodeAt: public HBinaryOperation {
: HBinaryOperation(string, index) {
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
+ SetFlag(kDependsOnMaps);
}
virtual Representation RequiredInputRepresentation(int index) const {
@@ -3253,11 +3353,29 @@ class HStringCharCodeAt: public HBinaryOperation {
};
+class HStringCharFromCode: public HUnaryOperation {
+ public:
+ explicit HStringCharFromCode(HValue* char_code) : HUnaryOperation(char_code) {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Integer32();
+ }
+
+ virtual bool DataEquals(HValue* other) { return true; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string_char_from_code")
+};
+
+
class HStringLength: public HUnaryOperation {
public:
explicit HStringLength(HValue* string) : HUnaryOperation(string) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
+ SetFlag(kDependsOnMaps);
}
virtual Representation RequiredInputRepresentation(int index) const {
@@ -3330,10 +3448,12 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
Handle<FixedArray> constant_properties,
bool fast_elements,
int literal_index,
- int depth)
+ int depth,
+ bool has_function)
: HMaterializedLiteral<1>(literal_index, depth),
constant_properties_(constant_properties),
- fast_elements_(fast_elements) {
+ fast_elements_(fast_elements),
+ has_function_(has_function) {
SetOperandAt(0, context);
}
@@ -3342,6 +3462,7 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
return constant_properties_;
}
bool fast_elements() const { return fast_elements_; }
+ bool has_function() const { return has_function_; }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
@@ -3352,6 +3473,7 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
private:
Handle<FixedArray> constant_properties_;
bool fast_elements_;
+ bool has_function_;
};
@@ -3415,6 +3537,24 @@ class HTypeof: public HUnaryOperation {
};
+class HToFastProperties: public HUnaryOperation {
+ public:
+ explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
+ // This instruction is not marked as having side effects, but
+ // changes the map of the input operand. Use it only when creating
+ // object literals.
+ ASSERT(value->IsObjectLiteral());
+ set_representation(Representation::Tagged());
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to_fast_properties")
+};
+
+
class HValueOf: public HUnaryOperation {
public:
explicit HValueOf(HValue* value) : HUnaryOperation(value) {
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 158bfbe3..23831925 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -25,6 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "v8.h"
#include "hydrogen.h"
#include "codegen.h"
@@ -42,6 +43,8 @@
#include "x64/lithium-codegen-x64.h"
#elif V8_TARGET_ARCH_ARM
#include "arm/lithium-codegen-arm.h"
+#elif V8_TARGET_ARCH_MIPS
+#include "mips/lithium-codegen-mips.h"
#else
#error Unsupported target architecture.
#endif
@@ -92,7 +95,7 @@ void HBasicBlock::AddPhi(HPhi* phi) {
void HBasicBlock::RemovePhi(HPhi* phi) {
ASSERT(phi->block() == this);
ASSERT(phis_.Contains(phi));
- ASSERT(phi->HasNoUses());
+ ASSERT(phi->HasNoUses() || !phi->is_live());
phi->ClearOperands();
phis_.RemoveElement(phi);
phi->SetBlock(NULL);
@@ -113,6 +116,21 @@ void HBasicBlock::AddInstruction(HInstruction* instr) {
}
+HDeoptimize* HBasicBlock::CreateDeoptimize() {
+ ASSERT(HasEnvironment());
+ HEnvironment* environment = last_environment();
+
+ HDeoptimize* instr = new HDeoptimize(environment->length());
+
+ for (int i = 0; i < environment->length(); i++) {
+ HValue* val = environment->values()->at(i);
+ instr->AddEnvironmentValue(val);
+ }
+
+ return instr;
+}
+
+
HSimulate* HBasicBlock::CreateSimulate(int id) {
ASSERT(HasEnvironment());
HEnvironment* environment = last_environment();
@@ -150,6 +168,10 @@ void HBasicBlock::Finish(HControlInstruction* end) {
void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) {
+ if (block->IsInlineReturnTarget()) {
+ AddInstruction(new HLeaveInlined);
+ last_environment_ = last_environment()->outer();
+ }
AddSimulate(AstNode::kNoNumber);
HGoto* instr = new HGoto(block);
instr->set_include_stack_check(include_stack_check);
@@ -157,6 +179,18 @@ void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) {
}
+void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
+ ASSERT(target->IsInlineReturnTarget());
+ ASSERT(return_value != NULL);
+ AddInstruction(new HLeaveInlined);
+ last_environment_ = last_environment()->outer();
+ last_environment()->Push(return_value);
+ AddSimulate(AstNode::kNoNumber);
+ HGoto* instr = new HGoto(target);
+ Finish(instr);
+}
+
+
void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
ASSERT(!HasEnvironment());
ASSERT(first() == NULL);
@@ -286,6 +320,13 @@ void HBasicBlock::Verify() {
// Check that every block is finished.
ASSERT(IsFinished());
ASSERT(block_id() >= 0);
+
+ // Check that the incoming edges are in edge split form.
+ if (predecessors_.length() > 1) {
+ for (int i = 0; i < predecessors_.length(); ++i) {
+ ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL);
+ }
+ }
}
#endif
@@ -473,12 +514,12 @@ HConstant* HGraph::GetConstantMinus1() {
HConstant* HGraph::GetConstantTrue() {
- return GetConstant(&constant_true_, Heap::true_value());
+ return GetConstant(&constant_true_, isolate()->heap()->true_value());
}
HConstant* HGraph::GetConstantFalse() {
- return GetConstant(&constant_false_, Heap::false_value());
+ return GetConstant(&constant_false_, isolate()->heap()->false_value());
}
@@ -534,13 +575,16 @@ void HBasicBlock::FinishExit(HControlInstruction* instruction) {
HGraph::HGraph(CompilationInfo* info)
- : HSubgraph(this),
+ : isolate_(info->isolate()),
next_block_id_(0),
+ entry_block_(NULL),
blocks_(8),
values_(16),
phi_list_(NULL) {
start_environment_ = new HEnvironment(NULL, info->scope(), info->closure());
start_environment_->set_ast_id(info->function()->id());
+ entry_block_ = CreateBasicBlock();
+ entry_block_->SetInitialEnvironment(start_environment_);
}
@@ -615,7 +659,7 @@ void HGraph::OrderBlocks() {
HBasicBlock* start = blocks_[0];
Postorder(start, &visited, &reverse_result, NULL);
- blocks_.Clear();
+ blocks_.Rewind(0);
int index = 0;
for (int i = reverse_result.length() - 1; i >= 0; --i) {
HBasicBlock* b = reverse_result[i];
@@ -680,8 +724,7 @@ void HGraph::AssignDominators() {
void HGraph::EliminateRedundantPhis() {
- HPhase phase("Phi elimination", this);
- ZoneList<HValue*> uses_to_replace(2);
+ HPhase phase("Redundant phi elimination", this);
// Worklist of phis that can potentially be eliminated. Initialized
// with all phi nodes. When elimination of a phi node modifies
@@ -704,26 +747,57 @@ void HGraph::EliminateRedundantPhis() {
if (value != NULL) {
// Iterate through uses finding the ones that should be
// replaced.
- const ZoneList<HValue*>* uses = phi->uses();
- for (int i = 0; i < uses->length(); ++i) {
- HValue* use = uses->at(i);
- if (!use->block()->IsStartBlock()) {
- uses_to_replace.Add(use);
+ SmallPointerList<HValue>* uses = phi->uses();
+ while (!uses->is_empty()) {
+ HValue* use = uses->RemoveLast();
+ if (use != NULL) {
+ phi->ReplaceAtUse(use, value);
+ if (use->IsPhi()) worklist.Add(HPhi::cast(use));
}
}
- // Replace the uses and add phis modified to the work list.
- for (int i = 0; i < uses_to_replace.length(); ++i) {
- HValue* use = uses_to_replace[i];
- phi->ReplaceAtUse(use, value);
- if (use->IsPhi()) worklist.Add(HPhi::cast(use));
- }
- uses_to_replace.Rewind(0);
block->RemovePhi(phi);
- } else if (FLAG_eliminate_dead_phis && phi->HasNoUses() &&
- !phi->IsReceiver()) {
+ }
+ }
+}
+
+
+void HGraph::EliminateUnreachablePhis() {
+ HPhase phase("Unreachable phi elimination", this);
+
+ // Initialize worklist.
+ ZoneList<HPhi*> phi_list(blocks_.length());
+ ZoneList<HPhi*> worklist(blocks_.length());
+ for (int i = 0; i < blocks_.length(); ++i) {
+ for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
+ HPhi* phi = blocks_[i]->phis()->at(j);
+ phi_list.Add(phi);
// We can't eliminate phis in the receiver position in the environment
// because in case of throwing an error we need this value to
// construct a stack trace.
+ if (phi->HasRealUses() || phi->IsReceiver()) {
+ phi->set_is_live(true);
+ worklist.Add(phi);
+ }
+ }
+ }
+
+ // Iteratively mark live phis.
+ while (!worklist.is_empty()) {
+ HPhi* phi = worklist.RemoveLast();
+ for (int i = 0; i < phi->OperandCount(); i++) {
+ HValue* operand = phi->OperandAt(i);
+ if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) {
+ HPhi::cast(operand)->set_is_live(true);
+ worklist.Add(HPhi::cast(operand));
+ }
+ }
+ }
+
+ // Remove unreachable phis.
+ for (int i = 0; i < phi_list.length(); i++) {
+ HPhi* phi = phi_list[i];
+ if (!phi->is_live()) {
+ HBasicBlock* block = phi->block();
block->RemovePhi(phi);
block->RecordDeletedPhi(phi->merged_index());
}
@@ -732,11 +806,11 @@ void HGraph::EliminateRedundantPhis() {
bool HGraph::CollectPhis() {
- const ZoneList<HBasicBlock*>* blocks = graph_->blocks();
- phi_list_ = new ZoneList<HPhi*>(blocks->length());
- for (int i = 0; i < blocks->length(); ++i) {
- for (int j = 0; j < blocks->at(i)->phis()->length(); j++) {
- HPhi* phi = blocks->at(i)->phis()->at(j);
+ int block_count = blocks_.length();
+ phi_list_ = new ZoneList<HPhi*>(block_count);
+ for (int i = 0; i < block_count; ++i) {
+ for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
+ HPhi* phi = blocks_[i]->phis()->at(j);
phi_list_->Add(phi);
// We don't support phi uses of arguments for now.
if (phi->CheckFlag(HValue::kIsArguments)) return false;
@@ -845,13 +919,15 @@ void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) {
ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
if (test->value()->IsCompare()) {
HCompare* compare = HCompare::cast(test->value());
- Token::Value op = compare->token();
- if (test->SecondSuccessor() == dest) {
- op = Token::NegateCompareOp(op);
+ if (compare->GetInputRepresentation().IsInteger32()) {
+ Token::Value op = compare->token();
+ if (test->SecondSuccessor() == dest) {
+ op = Token::NegateCompareOp(op);
+ }
+ Token::Value inverted_op = Token::InvertCompareOp(op);
+ InferControlFlowRange(op, compare->left(), compare->right());
+ InferControlFlowRange(inverted_op, compare->right(), compare->left());
}
- Token::Value inverted_op = Token::InvertCompareOp(op);
- InferControlFlowRange(op, compare->left(), compare->right());
- InferControlFlowRange(inverted_op, compare->right(), compare->left());
}
}
@@ -954,8 +1030,8 @@ HValueMap::HValueMap(const HValueMap* other)
lists_size_(other->lists_size_),
count_(other->count_),
present_flags_(other->present_flags_),
- array_(Zone::NewArray<HValueMapListElement>(other->array_size_)),
- lists_(Zone::NewArray<HValueMapListElement>(other->lists_size_)),
+ array_(ZONE->NewArray<HValueMapListElement>(other->array_size_)),
+ lists_(ZONE->NewArray<HValueMapListElement>(other->lists_size_)),
free_list_head_(other->free_list_head_) {
memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement));
memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
@@ -1034,7 +1110,7 @@ void HValueMap::Resize(int new_size) {
}
HValueMapListElement* new_array =
- Zone::NewArray<HValueMapListElement>(new_size);
+ ZONE->NewArray<HValueMapListElement>(new_size);
memset(new_array, 0, sizeof(HValueMapListElement) * new_size);
HValueMapListElement* old_array = array_;
@@ -1072,7 +1148,7 @@ void HValueMap::ResizeLists(int new_size) {
ASSERT(new_size > lists_size_);
HValueMapListElement* new_lists =
- Zone::NewArray<HValueMapListElement>(new_size);
+ ZONE->NewArray<HValueMapListElement>(new_size);
memset(new_lists, 0, sizeof(HValueMapListElement) * new_size);
HValueMapListElement* old_lists = lists_;
@@ -1175,12 +1251,12 @@ class HGlobalValueNumberer BASE_EMBEDDED {
info_(info),
block_side_effects_(graph_->blocks()->length()),
loop_side_effects_(graph_->blocks()->length()) {
- ASSERT(Heap::allow_allocation(false));
+ ASSERT(info->isolate()->heap()->allow_allocation(false));
block_side_effects_.AddBlock(0, graph_->blocks()->length());
loop_side_effects_.AddBlock(0, graph_->blocks()->length());
}
~HGlobalValueNumberer() {
- ASSERT(!Heap::allow_allocation(true));
+ ASSERT(!info_->isolate()->heap()->allow_allocation(true));
}
void Analyze();
@@ -1722,15 +1798,18 @@ int CompareConversionUses(HValue* a,
}
-void HGraph::InsertRepresentationChanges(HValue* current) {
+void HGraph::InsertRepresentationChangesForValue(
+ HValue* current,
+ ZoneList<HValue*>* to_convert,
+ ZoneList<Representation>* to_convert_reps) {
Representation r = current->representation();
if (r.IsNone()) return;
if (current->uses()->length() == 0) return;
// Collect the representation changes in a sorted list. This allows
// us to avoid duplicate changes without searching the list.
- ZoneList<HValue*> to_convert(2);
- ZoneList<Representation> to_convert_reps(2);
+ ASSERT(to_convert->is_empty());
+ ASSERT(to_convert_reps->is_empty());
for (int i = 0; i < current->uses()->length(); ++i) {
HValue* use = current->uses()->at(i);
// The occurrences index means the index within the operand array of "use"
@@ -1750,10 +1829,10 @@ void HGraph::InsertRepresentationChanges(HValue* current) {
Representation req = use->RequiredInputRepresentation(operand_index);
if (req.IsNone() || req.Equals(r)) continue;
int index = 0;
- while (to_convert.length() > index &&
- CompareConversionUses(to_convert[index],
+ while (index < to_convert->length() &&
+ CompareConversionUses(to_convert->at(index),
use,
- to_convert_reps[index],
+ to_convert_reps->at(index),
req) < 0) {
++index;
}
@@ -1763,13 +1842,13 @@ void HGraph::InsertRepresentationChanges(HValue* current) {
current->id(),
use->id());
}
- to_convert.InsertAt(index, use);
- to_convert_reps.InsertAt(index, req);
+ to_convert->InsertAt(index, use);
+ to_convert_reps->InsertAt(index, req);
}
- for (int i = 0; i < to_convert.length(); ++i) {
- HValue* use = to_convert[i];
- Representation r_to = to_convert_reps[i];
+ for (int i = 0; i < to_convert->length(); ++i) {
+ HValue* use = to_convert->at(i);
+ Representation r_to = to_convert_reps->at(i);
InsertRepresentationChangeForUse(current, use, r_to);
}
@@ -1777,6 +1856,8 @@ void HGraph::InsertRepresentationChanges(HValue* current) {
ASSERT(current->IsConstant());
current->Delete();
}
+ to_convert->Rewind(0);
+ to_convert_reps->Rewind(0);
}
@@ -1812,17 +1893,19 @@ void HGraph::InsertRepresentationChanges() {
}
}
+ ZoneList<HValue*> value_list(4);
+ ZoneList<Representation> rep_list(4);
for (int i = 0; i < blocks_.length(); ++i) {
// Process phi instructions first.
for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
HPhi* phi = blocks_[i]->phis()->at(j);
- InsertRepresentationChanges(phi);
+ InsertRepresentationChangesForValue(phi, &value_list, &rep_list);
}
// Process normal instructions.
HInstruction* current = blocks_[i]->first();
while (current != NULL) {
- InsertRepresentationChanges(current);
+ InsertRepresentationChangesForValue(current, &value_list, &rep_list);
current = current->next();
}
}
@@ -1979,20 +2062,8 @@ void TestContext::BuildBranch(HValue* value) {
HTest* test = new HTest(value, empty_true, empty_false);
builder->current_block()->Finish(test);
- HValue* const no_return_value = NULL;
- HBasicBlock* true_target = if_true();
- if (true_target->IsInlineReturnTarget()) {
- empty_true->AddLeaveInlined(no_return_value, true_target);
- } else {
- empty_true->Goto(true_target);
- }
-
- HBasicBlock* false_target = if_false();
- if (false_target->IsInlineReturnTarget()) {
- empty_false->AddLeaveInlined(no_return_value, false_target);
- } else {
- empty_false->Goto(false_target);
- }
+ empty_true->Goto(if_true(), false);
+ empty_false->Goto(if_false(), false);
builder->set_current_block(NULL);
}
@@ -2032,36 +2103,6 @@ void TestContext::BuildBranch(HValue* value) {
} while (false)
-// 'thing' could be an expression, statement, or list of statements.
-#define ADD_TO_SUBGRAPH(graph, thing) \
- do { \
- AddToSubgraph(graph, thing); \
- if (HasStackOverflow()) return; \
- } while (false)
-
-
-class HGraphBuilder::SubgraphScope BASE_EMBEDDED {
- public:
- SubgraphScope(HGraphBuilder* builder, HSubgraph* new_subgraph)
- : builder_(builder) {
- old_subgraph_ = builder_->current_subgraph_;
- subgraph_ = new_subgraph;
- builder_->current_subgraph_ = subgraph_;
- }
-
- ~SubgraphScope() {
- builder_->current_subgraph_ = old_subgraph_;
- }
-
- HSubgraph* subgraph() const { return subgraph_; }
-
- private:
- HGraphBuilder* builder_;
- HSubgraph* old_subgraph_;
- HSubgraph* subgraph_;
-};
-
-
void HGraphBuilder::Bailout(const char* reason) {
if (FLAG_trace_bailout) {
SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
@@ -2113,13 +2154,12 @@ void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) {
HGraph* HGraphBuilder::CreateGraph() {
- ASSERT(subgraph() == NULL);
graph_ = new HGraph(info());
+ if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info());
{
HPhase phase("Block building");
- graph()->Initialize(CreateBasicBlock(graph()->start_environment()));
- current_subgraph_ = graph();
+ current_block_ = graph()->entry_block();
Scope* scope = info()->scope();
if (scope->HasIllegalRedeclaration()) {
@@ -2163,6 +2203,7 @@ HGraph* HGraphBuilder::CreateGraph() {
graph()->OrderBlocks();
graph()->AssignDominators();
graph()->EliminateRedundantPhis();
+ if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis();
if (!graph()->CollectPhis()) {
Bailout("Phi-use of arguments object");
return NULL;
@@ -2196,25 +2237,6 @@ HGraph* HGraphBuilder::CreateGraph() {
}
-void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) {
- SubgraphScope scope(this, graph);
- Visit(stmt);
-}
-
-
-void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) {
- SubgraphScope scope(this, graph);
- VisitForValue(expr);
-}
-
-
-void HGraphBuilder::AddToSubgraph(HSubgraph* graph,
- ZoneList<Statement*>* stmts) {
- SubgraphScope scope(this, graph);
- VisitStatements(stmts);
-}
-
-
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
ASSERT(current_block() != NULL);
current_block()->AddInstruction(instr);
@@ -2259,8 +2281,8 @@ void HGraphBuilder::SetupScope(Scope* scope) {
// We don't yet handle the function name for named function expressions.
if (scope->function() != NULL) BAILOUT("named function expression");
- HConstant* undefined_constant =
- new HConstant(Factory::undefined_value(), Representation::Tagged());
+ HConstant* undefined_constant = new HConstant(
+ isolate()->factory()->undefined_value(), Representation::Tagged());
AddInstruction(undefined_constant);
graph_->set_undefined_constant(undefined_constant);
@@ -2281,14 +2303,17 @@ void HGraphBuilder::SetupScope(Scope* scope) {
// not have declarations).
if (scope->arguments() != NULL) {
if (!scope->arguments()->IsStackAllocated() ||
- !scope->arguments_shadow()->IsStackAllocated()) {
+ (scope->arguments_shadow() != NULL &&
+ !scope->arguments_shadow()->IsStackAllocated())) {
BAILOUT("context-allocated arguments");
}
HArgumentsObject* object = new HArgumentsObject;
AddInstruction(object);
graph()->SetArgumentsObject(object);
environment()->Bind(scope->arguments(), object);
- environment()->Bind(scope->arguments_shadow(), object);
+ if (scope->arguments_shadow() != NULL) {
+ environment()->Bind(scope->arguments_shadow(), object);
+ }
}
}
@@ -2308,33 +2333,6 @@ HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
}
-HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer,
- Handle<JSFunction> target,
- FunctionLiteral* function) {
- HConstant* undefined = graph()->GetConstantUndefined();
- HEnvironment* inner =
- outer->CopyForInlining(target, function, true, undefined);
- HSubgraph* subgraph = new HSubgraph(graph());
- subgraph->Initialize(CreateBasicBlock(inner));
- return subgraph;
-}
-
-
-HSubgraph* HGraphBuilder::CreateEmptySubgraph() {
- HSubgraph* subgraph = new HSubgraph(graph());
- subgraph->Initialize(graph()->CreateBasicBlock());
- return subgraph;
-}
-
-
-HSubgraph* HGraphBuilder::CreateBranchSubgraph(HEnvironment* env) {
- HSubgraph* subgraph = new HSubgraph(graph());
- HEnvironment* new_env = env->Copy();
- subgraph->Initialize(CreateBasicBlock(new_env));
- return subgraph;
-}
-
-
HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
HBasicBlock* header = graph()->CreateBasicBlock();
HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
@@ -2458,20 +2456,16 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
VisitForControl(stmt->expression(),
test->if_true(),
test->if_false());
+ } else if (context->IsEffect()) {
+ VISIT_FOR_EFFECT(stmt->expression());
+ current_block()->Goto(function_return(), false);
} else {
- HValue* return_value = NULL;
- if (context->IsEffect()) {
- VISIT_FOR_EFFECT(stmt->expression());
- return_value = graph()->GetConstantUndefined();
- } else {
- ASSERT(context->IsValue());
- VISIT_FOR_VALUE(stmt->expression());
- return_value = environment()->Pop();
- }
- current_block()->AddLeaveInlined(return_value,
- function_return());
- set_current_block(NULL);
+ ASSERT(context->IsValue());
+ VISIT_FOR_VALUE(stmt->expression());
+ HValue* return_value = environment()->Pop();
+ current_block()->AddLeaveInlined(return_value, function_return());
}
+ set_current_block(NULL);
}
}
@@ -2486,173 +2480,122 @@ void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
}
-HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph,
- HValue* switch_value,
- CaseClause* clause) {
- AddToSubgraph(subgraph, clause->label());
- if (HasStackOverflow()) return NULL;
- HValue* clause_value = subgraph->exit_block()->last_environment()->Pop();
- HCompare* compare = new HCompare(switch_value,
- clause_value,
- Token::EQ_STRICT);
- compare->SetInputRepresentation(Representation::Integer32());
- subgraph->exit_block()->AddInstruction(compare);
- return compare;
-}
-
-
void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
+ // We only optimize switch statements with smi-literal smi comparisons,
+ // with a bounded number of clauses.
+ const int kCaseClauseLimit = 128;
+ ZoneList<CaseClause*>* clauses = stmt->cases();
+ int clause_count = clauses->length();
+ if (clause_count > kCaseClauseLimit) {
+ BAILOUT("SwitchStatement: too many clauses");
+ }
+
VISIT_FOR_VALUE(stmt->tag());
- // TODO(3168478): simulate added for tag should be enough.
AddSimulate(stmt->EntryId());
- HValue* switch_value = Pop();
-
- ZoneList<CaseClause*>* clauses = stmt->cases();
- int num_clauses = clauses->length();
- if (num_clauses == 0) return;
- if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses");
+ HValue* tag_value = Pop();
+ HBasicBlock* first_test_block = current_block();
- int num_smi_clauses = num_clauses;
- for (int i = 0; i < num_clauses; i++) {
+ // 1. Build all the tests, with dangling true branches. Unconditionally
+ // deoptimize if we encounter a non-smi comparison.
+ for (int i = 0; i < clause_count; ++i) {
CaseClause* clause = clauses->at(i);
if (clause->is_default()) continue;
- clause->RecordTypeFeedback(oracle());
- if (!clause->IsSmiCompare()) {
- if (i == 0) BAILOUT("SwitchStatement: no smi compares");
- // We will deoptimize if the first non-smi compare is reached.
- num_smi_clauses = i;
- break;
- }
if (!clause->label()->IsSmiLiteral()) {
BAILOUT("SwitchStatement: non-literal switch label");
}
- }
-
- // The single exit block of the whole switch statement.
- HBasicBlock* single_exit_block = graph_->CreateBasicBlock();
-
- // Build a series of empty subgraphs for the comparisons.
- // The default clause does not have a comparison subgraph.
- ZoneList<HSubgraph*> compare_graphs(num_smi_clauses);
- for (int i = 0; i < num_smi_clauses; i++) {
- if (clauses->at(i)->is_default()) {
- compare_graphs.Add(NULL);
- } else {
- compare_graphs.Add(CreateEmptySubgraph());
- }
- }
- HSubgraph* prev_graph = current_subgraph_;
- HCompare* prev_compare_inst = NULL;
- for (int i = 0; i < num_smi_clauses; i++) {
- CaseClause* clause = clauses->at(i);
- if (clause->is_default()) continue;
-
- // Finish the previous graph by connecting it to the current.
- HSubgraph* subgraph = compare_graphs.at(i);
- if (prev_compare_inst == NULL) {
- ASSERT(prev_graph == current_subgraph_);
- prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block()));
- } else {
- HBasicBlock* empty = graph()->CreateBasicBlock();
- prev_graph->exit_block()->Finish(new HTest(prev_compare_inst,
- empty,
- subgraph->entry_block()));
+ // Unconditionally deoptimize on the first non-smi compare.
+ clause->RecordTypeFeedback(oracle());
+ if (!clause->IsSmiCompare()) {
+ current_block()->FinishExitWithDeoptimization();
+ set_current_block(NULL);
+ break;
}
- // Build instructions for current subgraph.
- ASSERT(clause->IsSmiCompare());
- prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause);
- if (HasStackOverflow()) return;
-
- prev_graph = subgraph;
- }
-
- // Finish last comparison if there was at least one comparison.
- // last_false_block is the (empty) false-block of the last comparison. If
- // there are no comparisons at all (a single default clause), it is just
- // the last block of the current subgraph.
- HBasicBlock* last_false_block = current_block();
- if (prev_graph != current_subgraph_) {
- last_false_block = graph()->CreateBasicBlock();
- HBasicBlock* empty = graph()->CreateBasicBlock();
- prev_graph->exit_block()->Finish(new HTest(prev_compare_inst,
- empty,
- last_false_block));
- }
-
- // If we have a non-smi compare clause, we deoptimize after trying
- // all the previous compares.
- if (num_smi_clauses < num_clauses) {
- last_false_block->Finish(new HDeoptimize);
- }
+ // Otherwise generate a compare and branch.
+ VISIT_FOR_VALUE(clause->label());
+ HValue* label_value = Pop();
+ HCompare* compare = new HCompare(tag_value, label_value, Token::EQ_STRICT);
+ compare->SetInputRepresentation(Representation::Integer32());
+ ASSERT(!compare->HasSideEffects());
+ AddInstruction(compare);
+ HBasicBlock* body_block = graph()->CreateBasicBlock();
+ HBasicBlock* next_test_block = graph()->CreateBasicBlock();
+ HTest* branch = new HTest(compare, body_block, next_test_block);
+ current_block()->Finish(branch);
+ set_current_block(next_test_block);
+ }
+
+ // Save the current block to use for the default or to join with the
+ // exit. This block is NULL if we deoptimized.
+ HBasicBlock* last_block = current_block();
+
+ // 2. Loop over the clauses and the linked list of tests in lockstep,
+ // translating the clause bodies.
+ HBasicBlock* curr_test_block = first_test_block;
+ HBasicBlock* fall_through_block = NULL;
+ BreakAndContinueInfo break_info(stmt);
+ { BreakAndContinueScope push(&break_info, this);
+ for (int i = 0; i < clause_count; ++i) {
+ CaseClause* clause = clauses->at(i);
+
+ // Identify the block where normal (non-fall-through) control flow
+ // goes to.
+ HBasicBlock* normal_block = NULL;
+ if (clause->is_default() && last_block != NULL) {
+ normal_block = last_block;
+ last_block = NULL; // Cleared to indicate we've handled it.
+ } else if (!curr_test_block->end()->IsDeoptimize()) {
+ normal_block = curr_test_block->end()->FirstSuccessor();
+ curr_test_block = curr_test_block->end()->SecondSuccessor();
+ }
- // Build statement blocks, connect them to their comparison block and
- // to the previous statement block, if there is a fall-through.
- HSubgraph* previous_subgraph = NULL;
- for (int i = 0; i < num_clauses; i++) {
- CaseClause* clause = clauses->at(i);
- // Subgraph for the statements of the clause is only created when
- // it's reachable either from the corresponding compare or as a
- // fall-through from previous statements.
- HSubgraph* subgraph = NULL;
-
- if (i < num_smi_clauses) {
- if (clause->is_default()) {
- if (!last_false_block->IsFinished()) {
- // Default clause: Connect it to the last false block.
- subgraph = CreateEmptySubgraph();
- last_false_block->Finish(new HGoto(subgraph->entry_block()));
+ // Identify a block to emit the body into.
+ if (normal_block == NULL) {
+ if (fall_through_block == NULL) {
+ // (a) Unreachable.
+ if (clause->is_default()) {
+ continue; // Might still be reachable clause bodies.
+ } else {
+ break;
+ }
+ } else {
+ // (b) Reachable only as fall through.
+ set_current_block(fall_through_block);
}
+ } else if (fall_through_block == NULL) {
+ // (c) Reachable only normally.
+ set_current_block(normal_block);
} else {
- ASSERT(clause->IsSmiCompare());
- // Connect with the corresponding comparison.
- subgraph = CreateEmptySubgraph();
- HBasicBlock* empty =
- compare_graphs.at(i)->exit_block()->end()->FirstSuccessor();
- empty->Finish(new HGoto(subgraph->entry_block()));
+ // (d) Reachable both ways.
+ HBasicBlock* join = CreateJoin(fall_through_block,
+ normal_block,
+ clause->EntryId());
+ set_current_block(join);
}
- }
-
- // Check for fall-through from previous statement block.
- if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) {
- if (subgraph == NULL) subgraph = CreateEmptySubgraph();
- previous_subgraph->exit_block()->
- Finish(new HGoto(subgraph->entry_block()));
- }
- if (subgraph != NULL) {
- BreakAndContinueInfo break_info(stmt);
- { BreakAndContinueScope push(&break_info, this);
- ADD_TO_SUBGRAPH(subgraph, clause->statements());
- }
- if (break_info.break_block() != NULL) {
- break_info.break_block()->SetJoinId(stmt->ExitId());
- break_info.break_block()->Finish(new HGoto(single_exit_block));
- }
+ VisitStatements(clause->statements());
+ CHECK_BAILOUT;
+ fall_through_block = current_block();
}
-
- previous_subgraph = subgraph;
- }
-
- // If the last statement block has a fall-through, connect it to the
- // single exit block.
- if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) {
- previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block));
- }
-
- // If there is no default clause finish the last comparison's false target.
- if (!last_false_block->IsFinished()) {
- last_false_block->Finish(new HGoto(single_exit_block));
}
- if (single_exit_block->HasPredecessor()) {
- set_current_block(single_exit_block);
+ // Create an up-to-3-way join. Use the break block if it exists since
+ // it's already a join block.
+ HBasicBlock* break_block = break_info.break_block();
+ if (break_block == NULL) {
+ set_current_block(CreateJoin(fall_through_block,
+ last_block,
+ stmt->ExitId()));
} else {
- set_current_block(NULL);
+ if (fall_through_block != NULL) fall_through_block->Goto(break_block);
+ if (last_block != NULL) last_block->Goto(break_block);
+ break_block->SetJoinId(stmt->ExitId());
+ set_current_block(break_block);
}
}
+
bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) {
return statement->OsrEntryId() == info()->osr_ast_id();
}
@@ -2847,18 +2790,22 @@ void HGraphBuilder::VisitConditional(Conditional* expr) {
cond_true->SetJoinId(expr->ThenId());
cond_false->SetJoinId(expr->ElseId());
- // TOOD(kmillikin): Visit the subexpressions in the same AST context as
- // the whole expression.
+ // Visit the true and false subexpressions in the same AST context as the
+ // whole expression.
set_current_block(cond_true);
- VISIT_FOR_VALUE(expr->then_expression());
+ Visit(expr->then_expression());
+ CHECK_BAILOUT;
HBasicBlock* other = current_block();
set_current_block(cond_false);
- VISIT_FOR_VALUE(expr->else_expression());
+ Visit(expr->else_expression());
+ CHECK_BAILOUT;
- HBasicBlock* join = CreateJoin(other, current_block(), expr->id());
- set_current_block(join);
- ast_context()->ReturnValue(Pop());
+ if (!ast_context()->IsTest()) {
+ HBasicBlock* join = CreateJoin(other, current_block(), expr->id());
+ set_current_block(join);
+ if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
+ }
}
@@ -2960,7 +2907,8 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
expr->constant_properties(),
expr->fast_elements(),
expr->literal_index(),
- expr->depth()));
+ expr->depth(),
+ expr->has_function()));
// The object is expected in the bailout environment during computation
// of the property values and is the value of the entire expression.
PushAndAdd(literal);
@@ -3001,7 +2949,19 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
default: UNREACHABLE();
}
}
- ast_context()->ReturnValue(Pop());
+
+ if (expr->has_function()) {
+ // Return the result of the transformation to fast properties
+ // instead of the original since this operation changes the map
+ // of the object. This makes sure that the original object won't
+ // be used by other optimized code before it is transformed
+ // (e.g. because of code motion).
+ HToFastProperties* result = new HToFastProperties(Pop());
+ AddInstruction(result);
+ ast_context()->ReturnValue(result);
+ } else {
+ ast_context()->ReturnValue(Pop());
+ }
}
@@ -3049,55 +3009,6 @@ void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
}
-HBasicBlock* HGraphBuilder::BuildTypeSwitch(HValue* receiver,
- ZoneMapList* maps,
- ZoneList<HSubgraph*>* body_graphs,
- HSubgraph* default_graph,
- int join_id) {
- ASSERT(maps->length() == body_graphs->length());
- HBasicBlock* join_block = graph()->CreateBasicBlock();
- AddInstruction(new HCheckNonSmi(receiver));
-
- for (int i = 0; i < maps->length(); ++i) {
- // Build the branches, connect all the target subgraphs to the join
- // block. Use the default as a target of the last branch.
- HSubgraph* if_true = body_graphs->at(i);
- HSubgraph* if_false = (i == maps->length() - 1)
- ? default_graph
- : CreateBranchSubgraph(environment());
- HCompareMap* compare =
- new HCompareMap(receiver,
- maps->at(i),
- if_true->entry_block(),
- if_false->entry_block());
- current_block()->Finish(compare);
-
- if (if_true->exit_block() != NULL) {
- // In an effect context the value of the type switch is not needed.
- // There is no need to merge it at the join block only to discard it.
- if (ast_context()->IsEffect()) {
- if_true->exit_block()->last_environment()->Drop(1);
- }
- if_true->exit_block()->Goto(join_block);
- }
-
- set_current_block(if_false->exit_block());
- }
-
- // Connect the default if necessary.
- if (current_block() != NULL) {
- if (ast_context()->IsEffect()) {
- environment()->Drop(1);
- }
- current_block()->Goto(join_block);
- }
-
- if (join_block->predecessors()->is_empty()) return NULL;
- join_block->SetJoinId(join_id);
- return join_block;
-}
-
-
// Sets the lookup result and returns true if the store can be inlined.
static bool ComputeStoredField(Handle<Map> type,
Handle<String> name,
@@ -3229,7 +3140,7 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
// know about and do not want to handle ones we've never seen. Otherwise
// use a generic IC.
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
- current_block()->FinishExit(new HDeoptimize);
+ current_block()->FinishExitWithDeoptimization();
} else {
HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
instr->set_position(expr->position());
@@ -3306,11 +3217,14 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
if (expr->IsMonomorphic()) {
Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
- // An object has either fast elements or pixel array elements, but never
- // both. Pixel array maps that are assigned to pixel array elements are
- // always created with the fast elements flag cleared.
- if (receiver_type->has_pixel_array_elements()) {
- instr = BuildStoreKeyedPixelArrayElement(object, key, value, expr);
+ // An object has either fast elements or external array elements, but
+ // never both. Pixel array maps that are assigned to pixel array elements
+ // are always created with the fast elements flag cleared.
+ if (receiver_type->has_external_array_elements()) {
+ instr = BuildStoreKeyedSpecializedArrayElement(object,
+ key,
+ value,
+ expr);
} else if (receiver_type->has_fast_elements()) {
instr = BuildStoreKeyedFastElement(object, key, value, expr);
}
@@ -3534,69 +3448,6 @@ void HGraphBuilder::VisitThrow(Throw* expr) {
}
-void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
- HValue* object,
- ZoneMapList* types,
- Handle<String> name) {
- // TODO(ager): We should recognize when the prototype chains for different
- // maps are identical. In that case we can avoid repeatedly generating the
- // same prototype map checks.
- int count = 0;
- HBasicBlock* join = NULL;
- for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
- Handle<Map> map = types->at(i);
- LookupResult lookup;
- map->LookupInDescriptors(NULL, *name, &lookup);
- if (lookup.IsProperty() && lookup.type() == FIELD) {
- if (count == 0) {
- AddInstruction(new HCheckNonSmi(object)); // Only needed once.
- join = graph()->CreateBasicBlock();
- }
- ++count;
- HBasicBlock* if_true = graph()->CreateBasicBlock();
- HBasicBlock* if_false = graph()->CreateBasicBlock();
- HCompareMap* compare = new HCompareMap(object, map, if_true, if_false);
- current_block()->Finish(compare);
-
- set_current_block(if_true);
- HLoadNamedField* instr =
- BuildLoadNamedField(object, expr, map, &lookup, false);
- instr->set_position(expr->position());
- instr->ClearFlag(HValue::kUseGVN);
- AddInstruction(instr);
- if (!ast_context()->IsEffect()) Push(instr);
- current_block()->Goto(join);
-
- set_current_block(if_false);
- }
- }
-
- // Finish up. Unconditionally deoptimize if we've handled all the maps we
- // know about and do not want to handle ones we've never seen. Otherwise
- // use a generic IC.
- if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
- current_block()->FinishExit(new HDeoptimize);
- } else {
- HInstruction* instr = BuildLoadNamedGeneric(object, expr);
- instr->set_position(expr->position());
-
- if (join != NULL) {
- AddInstruction(instr);
- if (!ast_context()->IsEffect()) Push(instr);
- current_block()->Goto(join);
- } else {
- ast_context()->ReturnInstruction(instr, expr->id());
- return;
- }
- }
-
- ASSERT(join != NULL);
- join->SetJoinId(expr->id());
- set_current_block(join);
- if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
-}
-
-
HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
Property* expr,
Handle<Map> type,
@@ -3686,25 +3537,28 @@ HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
}
-HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object,
- HValue* key,
- Property* expr) {
+HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement(
+ HValue* object,
+ HValue* key,
+ Property* expr) {
ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
AddInstruction(new HCheckNonSmi(object));
Handle<Map> map = expr->GetMonomorphicReceiverType();
ASSERT(!map->has_fast_elements());
- ASSERT(map->has_pixel_array_elements());
+ ASSERT(map->has_external_array_elements());
AddInstruction(new HCheckMap(object, map));
HLoadElements* elements = new HLoadElements(object);
AddInstruction(elements);
- HInstruction* length = new HPixelArrayLength(elements);
+ HInstruction* length = new HExternalArrayLength(elements);
AddInstruction(length);
AddInstruction(new HBoundsCheck(key, length));
- HLoadPixelArrayExternalPointer* external_elements =
- new HLoadPixelArrayExternalPointer(elements);
+ HLoadExternalArrayPointer* external_elements =
+ new HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
- HLoadPixelArrayElement* pixel_array_value =
- new HLoadPixelArrayElement(external_elements, key);
+ HLoadKeyedSpecializedArrayElement* pixel_array_value =
+ new HLoadKeyedSpecializedArrayElement(external_elements,
+ key,
+ expr->GetExternalArrayType());
return pixel_array_value;
}
@@ -3728,7 +3582,8 @@ HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
ASSERT(map->has_fast_elements());
AddInstruction(new HCheckMap(object, map));
HInstruction* elements = AddInstruction(new HLoadElements(object));
- AddInstruction(new HCheckMap(elements, Factory::fixed_array_map()));
+ AddInstruction(new HCheckMap(elements,
+ isolate()->factory()->fixed_array_map()));
bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
HInstruction* length = NULL;
if (is_array) {
@@ -3741,25 +3596,29 @@ HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
}
-HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement(
+HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement(
HValue* object,
HValue* key,
HValue* val,
- Expression* expr) {
+ Assignment* expr) {
ASSERT(expr->IsMonomorphic());
AddInstruction(new HCheckNonSmi(object));
Handle<Map> map = expr->GetMonomorphicReceiverType();
ASSERT(!map->has_fast_elements());
- ASSERT(map->has_pixel_array_elements());
+ ASSERT(map->has_external_array_elements());
AddInstruction(new HCheckMap(object, map));
HLoadElements* elements = new HLoadElements(object);
AddInstruction(elements);
- HInstruction* length = AddInstruction(new HPixelArrayLength(elements));
+ HInstruction* length = AddInstruction(new HExternalArrayLength(elements));
AddInstruction(new HBoundsCheck(key, length));
- HLoadPixelArrayExternalPointer* external_elements =
- new HLoadPixelArrayExternalPointer(elements);
+ HLoadExternalArrayPointer* external_elements =
+ new HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
- return new HStorePixelArrayElement(external_elements, key, val);
+ return new HStoreKeyedSpecializedArrayElement(
+ external_elements,
+ key,
+ val,
+ expr->GetExternalArrayType());
}
@@ -3815,6 +3674,13 @@ void HGraphBuilder::VisitProperty(Property* expr) {
FIRST_STRING_TYPE,
LAST_STRING_TYPE));
instr = new HStringLength(string);
+ } else if (expr->IsStringAccess()) {
+ VISIT_FOR_VALUE(expr->key());
+ HValue* index = Pop();
+ HValue* string = Pop();
+ HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
+ AddInstruction(char_code);
+ instr = new HStringCharFromCode(char_code);
} else if (expr->IsFunctionPrototype()) {
HValue* function = Pop();
@@ -3829,9 +3695,8 @@ void HGraphBuilder::VisitProperty(Property* expr) {
if (expr->IsMonomorphic()) {
instr = BuildLoadNamed(obj, expr, types->first(), name);
} else if (types != NULL && types->length() > 1) {
- HandlePolymorphicLoadNamedField(expr, obj, types, name);
- return;
-
+ AddInstruction(new HCheckNonSmi(obj));
+ instr = new HLoadNamedFieldPolymorphic(obj, types, name);
} else {
instr = BuildLoadNamedGeneric(obj, expr);
}
@@ -3847,8 +3712,8 @@ void HGraphBuilder::VisitProperty(Property* expr) {
// An object has either fast elements or pixel array elements, but never
// both. Pixel array maps that are assigned to pixel array elements are
// always created with the fast elements flag cleared.
- if (receiver_type->has_pixel_array_elements()) {
- instr = BuildLoadKeyedPixelArrayElement(obj, key, expr);
+ if (receiver_type->has_external_array_elements()) {
+ instr = BuildLoadKeyedSpecializedArrayElement(obj, key, expr);
} else if (receiver_type->has_fast_elements()) {
instr = BuildLoadKeyedFastElement(obj, key, expr);
}
@@ -3885,22 +3750,26 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
HValue* receiver,
ZoneMapList* types,
Handle<String> name) {
- int argument_count = expr->arguments()->length() + 1; // Plus receiver.
- int number_of_types = Min(types->length(), kMaxCallPolymorphism);
- ZoneMapList maps(number_of_types);
- ZoneList<HSubgraph*> subgraphs(number_of_types);
- bool needs_generic = (types->length() > kMaxCallPolymorphism);
-
- // Build subgraphs for each of the specific maps.
- //
// TODO(ager): We should recognize when the prototype chains for different
// maps are identical. In that case we can avoid repeatedly generating the
// same prototype map checks.
- for (int i = 0; i < number_of_types; ++i) {
+ int argument_count = expr->arguments()->length() + 1; // Includes receiver.
+ int count = 0;
+ HBasicBlock* join = NULL;
+ for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) {
Handle<Map> map = types->at(i);
if (expr->ComputeTarget(map, name)) {
- HSubgraph* subgraph = CreateBranchSubgraph(environment());
- SubgraphScope scope(this, subgraph);
+ if (count == 0) {
+ AddInstruction(new HCheckNonSmi(receiver)); // Only needed once.
+ join = graph()->CreateBasicBlock();
+ }
+ ++count;
+ HBasicBlock* if_true = graph()->CreateBasicBlock();
+ HBasicBlock* if_false = graph()->CreateBasicBlock();
+ HCompareMap* compare = new HCompareMap(receiver, map, if_true, if_false);
+ current_block()->Finish(compare);
+
+ set_current_block(if_true);
AddCheckConstantFunction(expr, receiver, map, false);
if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
PrintF("Trying to inline the polymorphic call to %s\n",
@@ -3911,53 +3780,49 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
// during hydrogen processing.
CHECK_BAILOUT;
HCallConstantFunction* call =
- new HCallConstantFunction(expr->target(), argument_count);
+ new HCallConstantFunction(expr->target(), argument_count);
call->set_position(expr->position());
PreProcessCall(call);
- PushAndAdd(call);
+ AddInstruction(call);
+ if (!ast_context()->IsEffect()) Push(call);
}
- maps.Add(map);
- subgraphs.Add(subgraph);
- } else {
- needs_generic = true;
+
+ if (current_block() != NULL) current_block()->Goto(join);
+ set_current_block(if_false);
}
}
- // If we couldn't compute the target for any of the maps just perform an
- // IC call.
- if (maps.length() == 0) {
+ // Finish up. Unconditionally deoptimize if we've handled all the maps we
+ // know about and do not want to handle ones we've never seen. Otherwise
+ // use a generic IC.
+ if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
+ current_block()->FinishExitWithDeoptimization();
+ } else {
HContext* context = new HContext;
AddInstruction(context);
HCallNamed* call = new HCallNamed(context, name, argument_count);
call->set_position(expr->position());
PreProcessCall(call);
- ast_context()->ReturnInstruction(call, expr->id());
- } else {
- // Build subgraph for generic call through IC.
- HSubgraph* default_graph = CreateBranchSubgraph(environment());
- { SubgraphScope scope(this, default_graph);
- if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
- default_graph->exit_block()->FinishExit(new HDeoptimize());
- default_graph->set_exit_block(NULL);
- } else {
- HContext* context = new HContext;
- AddInstruction(context);
- HCallNamed* call = new HCallNamed(context, name, argument_count);
- call->set_position(expr->position());
- PreProcessCall(call);
- PushAndAdd(call);
- }
- }
- HBasicBlock* new_exit_block =
- BuildTypeSwitch(receiver, &maps, &subgraphs, default_graph, expr->id());
- set_current_block(new_exit_block);
- // In an effect context, we did not materialized the value in the
- // predecessor environments so there's no need to handle it here.
- if (new_exit_block != NULL && !ast_context()->IsEffect()) {
- ast_context()->ReturnValue(Pop());
+ if (join != NULL) {
+ AddInstruction(call);
+ if (!ast_context()->IsEffect()) Push(call);
+ current_block()->Goto(join);
+ } else {
+ ast_context()->ReturnInstruction(call, expr->id());
+ return;
}
}
+
+ // We assume that control flow is always live after an expression. So
+ // even without predecessors to the join block, we set it as the exit
+ // block and continue by adding instructions there.
+ ASSERT(join != NULL);
+ set_current_block(join);
+ if (join->HasPredecessor()) {
+ join->SetJoinId(expr->id());
+ if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
+ }
}
@@ -4030,7 +3895,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
CompilationInfo target_info(target);
if (!ParserApi::Parse(&target_info) ||
!Scope::Analyze(&target_info)) {
- if (Top::has_pending_exception()) {
+ if (target_info.isolate()->has_pending_exception()) {
// Parse or scope error, never optimize this function.
SetStackOverflow();
target->shared()->set_optimization_disabled(true);
@@ -4103,9 +3968,16 @@ bool HGraphBuilder::TryInline(Call* expr) {
Handle<Context>(target->context()->global_context()));
FunctionState target_state(this, &target_info, &target_oracle);
- HSubgraph* body = CreateInlinedSubgraph(env, target, function);
- body->exit_block()->AddInstruction(new HEnterInlined(target, function));
- AddToSubgraph(body, function->body());
+ HConstant* undefined = graph()->GetConstantUndefined();
+ HEnvironment* inner_env =
+ environment()->CopyForInlining(target, function, true, undefined);
+ HBasicBlock* body_entry = CreateBasicBlock(inner_env);
+ current_block()->Goto(body_entry);
+
+ body_entry->SetJoinId(expr->ReturnId());
+ set_current_block(body_entry);
+ AddInstruction(new HEnterInlined(target, function));
+ VisitStatements(function->body());
if (HasStackOverflow()) {
// Bail out if the inline function did, as we cannot residualize a call
// instead.
@@ -4118,13 +3990,17 @@ bool HGraphBuilder::TryInline(Call* expr) {
TraceInline(target, NULL);
- if (body->exit_block() != NULL) {
+ if (current_block() != NULL) {
// Add a return of undefined if control can fall off the body. In a
// test context, undefined is false.
- HValue* return_value = graph()->GetConstantUndefined();
if (inlined_test_context() == NULL) {
ASSERT(function_return() != NULL);
- body->exit_block()->AddLeaveInlined(return_value, function_return());
+ ASSERT(call_context()->IsEffect() || call_context()->IsValue());
+ if (call_context()->IsEffect()) {
+ current_block()->Goto(function_return(), false);
+ } else {
+ current_block()->AddLeaveInlined(undefined, function_return());
+ }
} else {
// The graph builder assumes control can reach both branches of a
// test, so we materialize the undefined value and test it rather than
@@ -4133,24 +4009,14 @@ bool HGraphBuilder::TryInline(Call* expr) {
// TODO(3168478): refactor to avoid this.
HBasicBlock* empty_true = graph()->CreateBasicBlock();
HBasicBlock* empty_false = graph()->CreateBasicBlock();
- HTest* test = new HTest(return_value, empty_true, empty_false);
- body->exit_block()->Finish(test);
-
- HValue* const no_return_value = NULL;
- empty_true->AddLeaveInlined(no_return_value,
- inlined_test_context()->if_true());
- empty_false->AddLeaveInlined(no_return_value,
- inlined_test_context()->if_false());
+ HTest* test = new HTest(undefined, empty_true, empty_false);
+ current_block()->Finish(test);
+
+ empty_true->Goto(inlined_test_context()->if_true(), false);
+ empty_false->Goto(inlined_test_context()->if_false(), false);
}
- body->set_exit_block(NULL);
}
- // Record the environment at the inlined function call.
- AddSimulate(expr->ReturnId());
-
- // Jump to the function entry (without re-recording the environment).
- current_block()->Finish(new HGoto(body->entry_block()));
-
// Fix up the function exits.
if (inlined_test_context() != NULL) {
HBasicBlock* if_true = inlined_test_context()->if_true();
@@ -4162,20 +4028,10 @@ bool HGraphBuilder::TryInline(Call* expr) {
ClearInlinedTestContext();
// Forward to the real test context.
- HValue* const no_return_value = NULL;
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
- if (true_target->IsInlineReturnTarget()) {
- if_true->AddLeaveInlined(no_return_value, true_target);
- } else {
- if_true->Goto(true_target);
- }
-
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
- if (false_target->IsInlineReturnTarget()) {
- if_false->AddLeaveInlined(no_return_value, false_target);
- } else {
- if_false->Goto(false_target);
- }
+ if_true->Goto(true_target, false);
+ if_false->Goto(false_target, false);
// TODO(kmillikin): Come up with a better way to handle this. It is too
// subtle. NULL here indicates that the enclosing context has no control
@@ -4191,16 +4047,6 @@ bool HGraphBuilder::TryInline(Call* expr) {
}
-void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
- ASSERT(target->IsInlineReturnTarget());
- AddInstruction(new HLeaveInlined);
- HEnvironment* outer = last_environment()->outer();
- if (return_value != NULL) outer->Push(return_value);
- UpdateEnvironment(outer);
- Goto(target);
-}
-
-
bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
HValue* receiver,
Handle<Map> receiver_map,
@@ -4212,6 +4058,7 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
switch (id) {
case kStringCharCodeAt:
+ case kStringCharAt:
if (argument_count == 2 && check_type == STRING_CHECK) {
HValue* index = Pop();
HValue* string = Pop();
@@ -4219,7 +4066,13 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
AddInstruction(new HCheckPrototypeMaps(
oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
expr->holder()));
- HStringCharCodeAt* result = BuildStringCharCodeAt(string, index);
+ HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
+ if (id == kStringCharCodeAt) {
+ ast_context()->ReturnInstruction(char_code, expr->id());
+ return true;
+ }
+ AddInstruction(char_code);
+ HStringCharFromCode* result = new HStringCharFromCode(char_code);
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
@@ -4331,13 +4184,6 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
}
-static bool HasCustomCallGenerator(Handle<JSFunction> function) {
- SharedFunctionInfo* info = function->shared();
- return info->HasBuiltinFunctionId() &&
- CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id());
-}
-
-
void HGraphBuilder::VisitCall(Call* expr) {
Expression* callee = expr->expression();
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
@@ -4395,11 +4241,11 @@ void HGraphBuilder::VisitCall(Call* expr) {
return;
}
- if (HasCustomCallGenerator(expr->target()) ||
+ if (CallStubCompiler::HasCustomCallGenerator(*expr->target()) ||
expr->check_type() != RECEIVER_MAP_CHECK) {
// When the target has a custom call IC generator, use the IC,
- // because it is likely to generate better code. Also use the
- // IC when a primitive receiver check is required.
+ // because it is likely to generate better code. Also use the IC
+ // when a primitive receiver check is required.
HContext* context = new HContext;
AddInstruction(context);
call = PreProcessCall(new HCallNamed(context, name, argument_count));
@@ -4407,16 +4253,6 @@ void HGraphBuilder::VisitCall(Call* expr) {
AddCheckConstantFunction(expr, receiver, receiver_map, true);
if (TryInline(expr)) {
- if (current_block() != NULL) {
- HValue* return_value = Pop();
- // If we inlined a function in a test context then we need to emit
- // a simulate here to shadow the ones at the end of the
- // predecessor blocks. Those environments contain the return
- // value on top and do not correspond to any actual state of the
- // unoptimized code.
- if (ast_context()->IsEffect()) AddSimulate(expr->id());
- ast_context()->ReturnValue(return_value);
- }
return;
} else {
// Check for bailout, as the TryInline call in the if condition above
@@ -4480,16 +4316,6 @@ void HGraphBuilder::VisitCall(Call* expr) {
environment()->SetExpressionStackAt(receiver_index, global_receiver);
if (TryInline(expr)) {
- if (current_block() != NULL) {
- HValue* return_value = Pop();
- // If we inlined a function in a test context then we need to
- // emit a simulate here to shadow the ones at the end of the
- // predecessor blocks. Those environments contain the return
- // value on top and do not correspond to any actual state of the
- // unoptimized code.
- if (ast_context()->IsEffect()) AddSimulate(expr->id());
- ast_context()->ReturnValue(return_value);
- }
return;
}
// Check for bailout, as trying to inline might fail due to bailout
@@ -4569,7 +4395,7 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
BAILOUT("call to a JavaScript runtime function");
}
- Runtime::Function* function = expr->function();
+ const Runtime::Function* function = expr->function();
ASSERT(function != NULL);
if (function->intrinsic_type == Runtime::INLINE) {
ASSERT(expr->name()->length() > 0);
@@ -4666,7 +4492,12 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
VisitForEffect(expr->expression());
}
- } else if (op == Token::BIT_NOT || op == Token::SUB) {
+ } else if (op == Token::TYPEOF) {
+ VISIT_FOR_VALUE(expr->expression());
+ HValue* value = Pop();
+ ast_context()->ReturnInstruction(new HTypeof(value), expr->id());
+
+ } else {
VISIT_FOR_VALUE(expr->expression());
HValue* value = Pop();
HInstruction* instr = NULL;
@@ -4675,19 +4506,16 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
instr = new HBitNot(value);
break;
case Token::SUB:
- instr = new HMul(graph_->GetConstantMinus1(), value);
+ instr = new HMul(value, graph_->GetConstantMinus1());
+ break;
+ case Token::ADD:
+ instr = new HMul(value, graph_->GetConstant1());
break;
default:
- UNREACHABLE();
+ BAILOUT("Value: unsupported unary operation");
break;
}
ast_context()->ReturnInstruction(instr, expr->id());
- } else if (op == Token::TYPEOF) {
- VISIT_FOR_VALUE(expr->expression());
- HValue* value = Pop();
- ast_context()->ReturnInstruction(new HTypeof(value), expr->id());
- } else {
- BAILOUT("Value: unsupported unary operation");
}
}
@@ -5106,7 +4934,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue()));
// If the function is in new space we assume it's more likely to
// change and thus prefer the general IC code.
- if (!Heap::InNewSpace(*candidate)) {
+ if (!isolate()->heap()->InNewSpace(*candidate)) {
target = candidate;
}
}
@@ -5325,19 +5153,24 @@ void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
// Fast support for string.charAt(n) and string[n].
void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
- BAILOUT("inlined runtime function: StringCharFromCode");
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
+ HValue* char_code = Pop();
+ HStringCharFromCode* result = new HStringCharFromCode(char_code);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Fast support for string.charAt(n) and string[n].
void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
- ASSERT_EQ(2, call->arguments()->length());
- VisitArgumentList(call->arguments());
- CHECK_BAILOUT;
- HContext* context = new HContext;
- AddInstruction(context);
- HCallStub* result = new HCallStub(context, CodeStub::StringCharAt, 2);
- Drop(2);
+ ASSERT(call->arguments()->length() == 2);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
+ VISIT_FOR_VALUE(call->arguments()->at(1));
+ HValue* index = Pop();
+ HValue* string = Pop();
+ HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
+ AddInstruction(char_code);
+ HStringCharFromCode* result = new HStringCharFromCode(char_code);
ast_context()->ReturnInstruction(result, call->id());
}
@@ -5887,12 +5720,12 @@ void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
Tag tag(this, "intervals");
PrintStringProperty("name", name);
- const ZoneList<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
+ const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
for (int i = 0; i < fixed_d->length(); ++i) {
TraceLiveRange(fixed_d->at(i), "fixed");
}
- const ZoneList<LiveRange*>* fixed = allocator->fixed_live_ranges();
+ const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
for (int i = 0; i < fixed->length(); ++i) {
TraceLiveRange(fixed->at(i), "fixed");
}
@@ -5963,6 +5796,11 @@ void HTracer::FlushToFile() {
}
+void HStatistics::Initialize(CompilationInfo* info) {
+ source_size_ += info->shared_info()->SourceSize();
+}
+
+
void HStatistics::Print() {
PrintF("Timing results:\n");
int64_t sum = 0;
@@ -5980,9 +5818,15 @@ void HStatistics::Print() {
double size_percent = static_cast<double>(size) * 100 / total_size_;
PrintF(" %8u bytes / %4.1f %%\n", size, size_percent);
}
- PrintF("%30s - %7.3f ms %8u bytes\n", "Sum",
- static_cast<double>(sum) / 1000,
- total_size_);
+ double source_size_in_kb = static_cast<double>(source_size_) / 1024;
+ double normalized_time = source_size_in_kb > 0
+ ? (static_cast<double>(sum) / 1000) / source_size_in_kb
+ : 0;
+ double normalized_bytes = source_size_in_kb > 0
+ ? total_size_ / source_size_in_kb
+ : 0;
+ PrintF("%30s - %7.3f ms %7.3f bytes\n", "Sum",
+ normalized_time, normalized_bytes);
PrintF("---------------------------------------------------------------\n");
PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n",
"Total",
@@ -6027,13 +5871,13 @@ void HPhase::Begin(const char* name,
if (allocator != NULL && chunk_ == NULL) {
chunk_ = allocator->chunk();
}
- if (FLAG_time_hydrogen) start_ = OS::Ticks();
+ if (FLAG_hydrogen_stats) start_ = OS::Ticks();
start_allocation_size_ = Zone::allocation_size_;
}
void HPhase::End() const {
- if (FLAG_time_hydrogen) {
+ if (FLAG_hydrogen_stats) {
int64_t end = OS::Ticks();
unsigned size = Zone::allocation_size_ - start_allocation_size_;
HStatistics::Instance()->SaveTiming(name_, end - start_, size);
diff --git a/src/hydrogen.h b/src/hydrogen.h
index d8b1cfb6..e14799a2 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -124,6 +124,10 @@ class HBasicBlock: public ZoneObject {
void AddSimulate(int id) { AddInstruction(CreateSimulate(id)); }
void AssignCommonDominator(HBasicBlock* other);
+ void FinishExitWithDeoptimization() {
+ FinishExit(CreateDeoptimize());
+ }
+
// Add the inlined function exit sequence, adding an HLeaveInlined
// instruction and updating the bailout environment.
void AddLeaveInlined(HValue* return_value, HBasicBlock* target);
@@ -146,6 +150,7 @@ class HBasicBlock: public ZoneObject {
void AddDominatedBlock(HBasicBlock* block);
HSimulate* CreateSimulate(int id);
+ HDeoptimize* CreateDeoptimize();
int block_id_;
HGraph* graph_;
@@ -192,40 +197,13 @@ class HLoopInformation: public ZoneObject {
};
-class HSubgraph: public ZoneObject {
- public:
- explicit HSubgraph(HGraph* graph)
- : graph_(graph),
- entry_block_(NULL),
- exit_block_(NULL) {
- }
-
- HGraph* graph() const { return graph_; }
- HBasicBlock* entry_block() const { return entry_block_; }
- HBasicBlock* exit_block() const { return exit_block_; }
- void set_exit_block(HBasicBlock* block) {
- exit_block_ = block;
- }
-
- void Initialize(HBasicBlock* block) {
- ASSERT(entry_block_ == NULL);
- entry_block_ = block;
- exit_block_ = block;
- }
-
- protected:
- HGraph* graph_; // The graph this is a subgraph of.
- HBasicBlock* entry_block_;
- HBasicBlock* exit_block_;
-};
-
-
-class HGraph: public HSubgraph {
+class HGraph: public ZoneObject {
public:
explicit HGraph(CompilationInfo* info);
const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
+ HBasicBlock* entry_block() const { return entry_block_; }
HEnvironment* start_environment() const { return start_environment_; }
void InitializeInferredTypes();
@@ -234,6 +212,7 @@ class HGraph: public HSubgraph {
void ComputeMinusZeroChecks();
bool ProcessArgumentsObject();
void EliminateRedundantPhis();
+ void EliminateUnreachablePhis();
void Canonicalize();
void OrderBlocks();
void AssignDominators();
@@ -295,12 +274,18 @@ class HGraph: public HSubgraph {
void InsertRepresentationChangeForUse(HValue* value,
HValue* use,
Representation to);
- void InsertRepresentationChanges(HValue* current);
+ void InsertRepresentationChangesForValue(HValue* current,
+ ZoneList<HValue*>* value_list,
+ ZoneList<Representation>* rep_list);
void InferTypes(ZoneList<HValue*>* worklist);
void InitializeInferredTypes(int from_inclusive, int to_inclusive);
void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
+ Isolate* isolate() { return isolate_; }
+
+ Isolate* isolate_;
int next_block_id_;
+ HBasicBlock* entry_block_;
HEnvironment* start_environment_;
ZoneList<HBasicBlock*> blocks_;
ZoneList<HValue*> values_;
@@ -312,8 +297,6 @@ class HGraph: public HSubgraph {
SetOncePointer<HConstant> constant_false_;
SetOncePointer<HArgumentsObject> arguments_object_;
- friend class HSubgraph;
-
DISALLOW_COPY_AND_ASSIGN(HGraph);
};
@@ -404,7 +387,7 @@ class HEnvironment: public ZoneObject {
void ClearHistory() {
pop_count_ = 0;
push_count_ = 0;
- assigned_variables_.Clear();
+ assigned_variables_.Rewind(0);
}
void SetValueAt(int index, HValue* value) {
@@ -640,7 +623,7 @@ class HGraphBuilder: public AstVisitor {
ast_context_(NULL),
break_scope_(NULL),
graph_(NULL),
- current_subgraph_(NULL),
+ current_block_(NULL),
inlined_count_(0) {
// This is not initialized in the initializer list because the
// constructor for the initial state relies on function_state_ == NULL
@@ -652,14 +635,11 @@ class HGraphBuilder: public AstVisitor {
// Simple accessors.
HGraph* graph() const { return graph_; }
- HSubgraph* subgraph() const { return current_subgraph_; }
BreakAndContinueScope* break_scope() const { return break_scope_; }
void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
- HBasicBlock* current_block() const { return subgraph()->exit_block(); }
- void set_current_block(HBasicBlock* block) {
- subgraph()->set_exit_block(block);
- }
+ HBasicBlock* current_block() const { return current_block_; }
+ void set_current_block(HBasicBlock* block) { current_block_ = block; }
HEnvironment* environment() const {
return current_block()->last_environment();
}
@@ -750,10 +730,6 @@ class HGraphBuilder: public AstVisitor {
HBasicBlock* exit_block,
HBasicBlock* continue_block);
- void AddToSubgraph(HSubgraph* graph, ZoneList<Statement*>* stmts);
- void AddToSubgraph(HSubgraph* graph, Statement* stmt);
- void AddToSubgraph(HSubgraph* graph, Expression* expr);
-
HValue* Top() const { return environment()->Top(); }
void Drop(int n) { environment()->Drop(n); }
void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
@@ -791,12 +767,7 @@ class HGraphBuilder: public AstVisitor {
#undef DECLARE_VISIT
HBasicBlock* CreateBasicBlock(HEnvironment* env);
- HSubgraph* CreateEmptySubgraph();
- HSubgraph* CreateBranchSubgraph(HEnvironment* env);
HBasicBlock* CreateLoopHeaderBlock();
- HSubgraph* CreateInlinedSubgraph(HEnvironment* outer,
- Handle<JSFunction> target,
- FunctionLiteral* function);
// Helpers for flow graph construction.
void LookupGlobalPropertyCell(Variable* var,
@@ -823,10 +794,6 @@ class HGraphBuilder: public AstVisitor {
void HandlePropertyAssignment(Assignment* expr);
void HandleCompoundAssignment(Assignment* expr);
- void HandlePolymorphicLoadNamedField(Property* expr,
- HValue* object,
- ZoneMapList* types,
- Handle<String> name);
void HandlePolymorphicStoreNamedField(Assignment* expr,
HValue* object,
HValue* value,
@@ -852,9 +819,9 @@ class HGraphBuilder: public AstVisitor {
HInstruction* BuildLoadKeyedFastElement(HValue* object,
HValue* key,
Property* expr);
- HInstruction* BuildLoadKeyedPixelArrayElement(HValue* object,
- HValue* key,
- Property* expr);
+ HInstruction* BuildLoadKeyedSpecializedArrayElement(HValue* object,
+ HValue* key,
+ Property* expr);
HInstruction* BuildLoadKeyedGeneric(HValue* object,
HValue* key);
@@ -883,14 +850,11 @@ class HGraphBuilder: public AstVisitor {
HValue* val,
Expression* expr);
- HInstruction* BuildStoreKeyedPixelArrayElement(HValue* object,
- HValue* key,
- HValue* val,
- Expression* expr);
-
- HCompare* BuildSwitchCompare(HSubgraph* subgraph,
- HValue* switch_value,
- CaseClause* clause);
+ HInstruction* BuildStoreKeyedSpecializedArrayElement(
+ HValue* object,
+ HValue* key,
+ HValue* val,
+ Assignment* expr);
HValue* BuildContextChainWalk(Variable* var);
@@ -900,12 +864,6 @@ class HGraphBuilder: public AstVisitor {
bool smi_and_map_check);
- HBasicBlock* BuildTypeSwitch(HValue* receiver,
- ZoneMapList* maps,
- ZoneList<HSubgraph*>* body_graphs,
- HSubgraph* default_graph,
- int join_id);
-
// The translation state of the currently-being-translated function.
FunctionState* function_state_;
@@ -920,7 +878,7 @@ class HGraphBuilder: public AstVisitor {
BreakAndContinueScope* break_scope_;
HGraph* graph_;
- HSubgraph* current_subgraph_;
+ HBasicBlock* current_block_;
int inlined_count_;
@@ -986,6 +944,7 @@ class HValueMap: public ZoneObject {
class HStatistics: public Malloced {
public:
+ void Initialize(CompilationInfo* info);
void Print();
void SaveTiming(const char* name, int64_t ticks, unsigned size);
static HStatistics* Instance() {
@@ -1004,7 +963,8 @@ class HStatistics: public Malloced {
sizes_(5),
total_(0),
total_size_(0),
- full_code_gen_(0) { }
+ full_code_gen_(0),
+ source_size_(0) { }
List<int64_t> timing_;
List<const char*> names_;
@@ -1012,6 +972,7 @@ class HStatistics: public Malloced {
int64_t total_;
unsigned total_size_;
int64_t full_code_gen_;
+ double source_size_;
};
diff --git a/src/ia32/assembler-ia32-inl.h b/src/ia32/assembler-ia32-inl.h
index d5fd7b87..1da3f81f 100644
--- a/src/ia32/assembler-ia32-inl.h
+++ b/src/ia32/assembler-ia32-inl.h
@@ -204,11 +204,12 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
visitor->VisitExternalReference(target_reference_address());
CPU::FlushICache(pc_, sizeof(Address));
#ifdef ENABLE_DEBUGGER_SUPPORT
- } else if (Debug::has_break_points() &&
- ((RelocInfo::IsJSReturn(mode) &&
+ // TODO(isolates): Get a cached isolate below.
+ } else if (((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
- IsPatchedDebugBreakSlotSequence()))) {
+ IsPatchedDebugBreakSlotSequence())) &&
+ Isolate::Current()->debug()->has_break_points()) {
visitor->VisitDebugTarget(this);
#endif
} else if (mode == RelocInfo::RUNTIME_ENTRY) {
@@ -218,10 +219,10 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
template<typename StaticVisitor>
-void RelocInfo::Visit() {
+void RelocInfo::Visit(Heap* heap) {
RelocInfo::Mode mode = rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
- StaticVisitor::VisitPointer(target_object_address());
+ StaticVisitor::VisitPointer(heap, target_object_address());
CPU::FlushICache(pc_, sizeof(Address));
} else if (RelocInfo::IsCodeTarget(mode)) {
StaticVisitor::VisitCodeTarget(this);
@@ -231,7 +232,7 @@ void RelocInfo::Visit() {
StaticVisitor::VisitExternalReference(target_reference_address());
CPU::FlushICache(pc_, sizeof(Address));
#ifdef ENABLE_DEBUGGER_SUPPORT
- } else if (Debug::has_break_points() &&
+ } else if (heap->isolate()->debug()->has_break_points() &&
((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
@@ -266,7 +267,7 @@ Immediate::Immediate(Label* internal_offset) {
Immediate::Immediate(Handle<Object> handle) {
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
- ASSERT(!Heap::InNewSpace(obj));
+ ASSERT(!HEAP->InNewSpace(obj));
if (obj->IsHeapObject()) {
x_ = reinterpret_cast<intptr_t>(handle.location());
rmode_ = RelocInfo::EMBEDDED_OBJECT;
@@ -299,7 +300,7 @@ void Assembler::emit(uint32_t x) {
void Assembler::emit(Handle<Object> handle) {
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
- ASSERT(!Heap::InNewSpace(obj));
+ ASSERT(!isolate()->heap()->InNewSpace(obj));
if (obj->IsHeapObject()) {
emit(reinterpret_cast<intptr_t>(handle.location()),
RelocInfo::EMBEDDED_OBJECT);
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index 6652df27..e6d245ef 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -48,16 +48,17 @@ namespace internal {
// -----------------------------------------------------------------------------
// Implementation of CpuFeatures
-// Safe default is no features.
-uint64_t CpuFeatures::supported_ = 0;
-uint64_t CpuFeatures::enabled_ = 0;
-uint64_t CpuFeatures::found_by_runtime_probing_ = 0;
+CpuFeatures::CpuFeatures()
+ : supported_(0),
+ enabled_(0),
+ found_by_runtime_probing_(0) {
+}
// The Probe method needs executable memory, so it uses Heap::CreateCode.
// Allocation failure is silent and leads to safe default.
void CpuFeatures::Probe(bool portable) {
- ASSERT(Heap::HasBeenSetup());
+ ASSERT(HEAP->HasBeenSetup());
ASSERT(supported_ == 0);
if (portable && Serializer::enabled()) {
supported_ |= OS::CpuFeaturesImpliedByPlatform();
@@ -120,16 +121,17 @@ void CpuFeatures::Probe(bool portable) {
CodeDesc desc;
assm.GetCode(&desc);
-
Object* code;
- { MaybeObject* maybe_code = Heap::CreateCode(desc,
- Code::ComputeFlags(Code::STUB),
- Handle<Code>::null());
+ { MaybeObject* maybe_code =
+ assm.isolate()->heap()->CreateCode(desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Code>::null());
if (!maybe_code->ToObject(&code)) return;
}
if (!code->IsCode()) return;
- PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
+ PROFILE(ISOLATE,
+ CodeCreateEvent(Logger::BUILTIN_TAG,
Code::cast(code), "CpuFeatures::Probe"));
typedef uint64_t (*F0)();
F0 probe = FUNCTION_CAST<F0>(Code::cast(code)->entry());
@@ -295,19 +297,18 @@ bool Operand::is_reg(Register reg) const {
static void InitCoverageLog();
#endif
-// Spare buffer.
-byte* Assembler::spare_buffer_ = NULL;
-
Assembler::Assembler(void* buffer, int buffer_size)
- : positions_recorder_(this) {
+ : AssemblerBase(Isolate::Current()),
+ positions_recorder_(this),
+ emit_debug_code_(FLAG_debug_code) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
buffer_size = kMinimalBufferSize;
- if (spare_buffer_ != NULL) {
- buffer = spare_buffer_;
- spare_buffer_ = NULL;
+ if (isolate()->assembler_spare_buffer() != NULL) {
+ buffer = isolate()->assembler_spare_buffer();
+ isolate()->set_assembler_spare_buffer(NULL);
}
}
if (buffer == NULL) {
@@ -348,8 +349,9 @@ Assembler::Assembler(void* buffer, int buffer_size)
Assembler::~Assembler() {
if (own_buffer_) {
- if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
- spare_buffer_ = buffer_;
+ if (isolate()->assembler_spare_buffer() == NULL &&
+ buffer_size_ == kMinimalBufferSize) {
+ isolate()->set_assembler_spare_buffer(buffer_);
} else {
DeleteArray(buffer_);
}
@@ -367,8 +369,6 @@ void Assembler::GetCode(CodeDesc* desc) {
desc->instr_size = pc_offset();
desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
desc->origin = this;
-
- Counters::reloc_info_size.Increment(desc->reloc_size);
}
@@ -386,7 +386,7 @@ void Assembler::CodeTargetAlign() {
void Assembler::cpuid() {
- ASSERT(CpuFeatures::IsEnabled(CPUID));
+ ASSERT(isolate()->cpu_features()->IsEnabled(CPUID));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x0F);
@@ -747,7 +747,7 @@ void Assembler::movzx_w(Register dst, const Operand& src) {
void Assembler::cmov(Condition cc, Register dst, int32_t imm32) {
- ASSERT(CpuFeatures::IsEnabled(CMOV));
+ ASSERT(isolate()->cpu_features()->IsEnabled(CMOV));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
UNIMPLEMENTED();
@@ -758,7 +758,7 @@ void Assembler::cmov(Condition cc, Register dst, int32_t imm32) {
void Assembler::cmov(Condition cc, Register dst, Handle<Object> handle) {
- ASSERT(CpuFeatures::IsEnabled(CMOV));
+ ASSERT(isolate()->cpu_features()->IsEnabled(CMOV));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
UNIMPLEMENTED();
@@ -769,7 +769,7 @@ void Assembler::cmov(Condition cc, Register dst, Handle<Object> handle) {
void Assembler::cmov(Condition cc, Register dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(CMOV));
+ ASSERT(isolate()->cpu_features()->IsEnabled(CMOV));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
// Opcode: 0f 40 + cc /r.
@@ -1450,7 +1450,7 @@ void Assembler::nop() {
void Assembler::rdtsc() {
- ASSERT(CpuFeatures::IsEnabled(RDTSC));
+ ASSERT(isolate()->cpu_features()->IsEnabled(RDTSC));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x0F);
@@ -1856,7 +1856,7 @@ void Assembler::fistp_s(const Operand& adr) {
void Assembler::fisttp_s(const Operand& adr) {
- ASSERT(CpuFeatures::IsEnabled(SSE3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE3));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xDB);
@@ -1865,7 +1865,7 @@ void Assembler::fisttp_s(const Operand& adr) {
void Assembler::fisttp_d(const Operand& adr) {
- ASSERT(CpuFeatures::IsEnabled(SSE3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE3));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xDD);
@@ -2134,7 +2134,7 @@ void Assembler::setcc(Condition cc, Register reg) {
void Assembler::cvttss2si(Register dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF3);
@@ -2145,7 +2145,7 @@ void Assembler::cvttss2si(Register dst, const Operand& src) {
void Assembler::cvttsd2si(Register dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2);
@@ -2156,7 +2156,7 @@ void Assembler::cvttsd2si(Register dst, const Operand& src) {
void Assembler::cvtsi2sd(XMMRegister dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2);
@@ -2167,7 +2167,7 @@ void Assembler::cvtsi2sd(XMMRegister dst, const Operand& src) {
void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF3);
@@ -2177,8 +2177,19 @@ void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
}
+void Assembler::cvtsd2ss(XMMRegister dst, XMMRegister src) {
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0xF2);
+ EMIT(0x0F);
+ EMIT(0x5A);
+ emit_sse_operand(dst, src);
+}
+
+
void Assembler::addsd(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2);
@@ -2189,7 +2200,7 @@ void Assembler::addsd(XMMRegister dst, XMMRegister src) {
void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2);
@@ -2200,7 +2211,7 @@ void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
void Assembler::subsd(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2);
@@ -2211,7 +2222,7 @@ void Assembler::subsd(XMMRegister dst, XMMRegister src) {
void Assembler::divsd(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2);
@@ -2222,7 +2233,7 @@ void Assembler::divsd(XMMRegister dst, XMMRegister src) {
void Assembler::xorpd(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2253,7 +2264,7 @@ void Assembler::andpd(XMMRegister dst, XMMRegister src) {
void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2264,7 +2275,7 @@ void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
void Assembler::movmskpd(Register dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2275,7 +2286,7 @@ void Assembler::movmskpd(Register dst, XMMRegister src) {
void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2);
@@ -2287,7 +2298,7 @@ void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) {
void Assembler::movaps(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x0F);
@@ -2297,7 +2308,7 @@ void Assembler::movaps(XMMRegister dst, XMMRegister src) {
void Assembler::movdqa(const Operand& dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2308,7 +2319,7 @@ void Assembler::movdqa(const Operand& dst, XMMRegister src) {
void Assembler::movdqa(XMMRegister dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2319,7 +2330,7 @@ void Assembler::movdqa(XMMRegister dst, const Operand& src) {
void Assembler::movdqu(const Operand& dst, XMMRegister src ) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF3);
@@ -2330,7 +2341,7 @@ void Assembler::movdqu(const Operand& dst, XMMRegister src ) {
void Assembler::movdqu(XMMRegister dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF3);
@@ -2341,7 +2352,7 @@ void Assembler::movdqu(XMMRegister dst, const Operand& src) {
void Assembler::movntdqa(XMMRegister dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(SSE4_1));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE4_1));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2353,7 +2364,7 @@ void Assembler::movntdqa(XMMRegister dst, const Operand& src) {
void Assembler::movntdq(const Operand& dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2389,7 +2400,7 @@ void Assembler::movdbl(const Operand& dst, XMMRegister src) {
void Assembler::movsd(const Operand& dst, XMMRegister src ) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2); // double
@@ -2400,7 +2411,7 @@ void Assembler::movsd(const Operand& dst, XMMRegister src ) {
void Assembler::movsd(XMMRegister dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2); // double
@@ -2411,7 +2422,7 @@ void Assembler::movsd(XMMRegister dst, const Operand& src) {
void Assembler::movsd(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF2);
@@ -2421,8 +2432,41 @@ void Assembler::movsd(XMMRegister dst, XMMRegister src) {
}
+void Assembler::movss(const Operand& dst, XMMRegister src ) {
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0xF3); // float
+ EMIT(0x0F);
+ EMIT(0x11); // store
+ emit_sse_operand(src, dst);
+}
+
+
+void Assembler::movss(XMMRegister dst, const Operand& src) {
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0xF3); // float
+ EMIT(0x0F);
+ EMIT(0x10); // load
+ emit_sse_operand(dst, src);
+}
+
+
+void Assembler::movss(XMMRegister dst, XMMRegister src) {
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0xF3);
+ EMIT(0x0F);
+ EMIT(0x10);
+ emit_sse_operand(dst, src);
+}
+
+
void Assembler::movd(XMMRegister dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2433,7 +2477,7 @@ void Assembler::movd(XMMRegister dst, const Operand& src) {
void Assembler::movd(const Operand& dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2444,7 +2488,7 @@ void Assembler::movd(const Operand& dst, XMMRegister src) {
void Assembler::pand(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2455,7 +2499,7 @@ void Assembler::pand(XMMRegister dst, XMMRegister src) {
void Assembler::pxor(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2466,7 +2510,7 @@ void Assembler::pxor(XMMRegister dst, XMMRegister src) {
void Assembler::por(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2477,7 +2521,7 @@ void Assembler::por(XMMRegister dst, XMMRegister src) {
void Assembler::ptest(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE4_1));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE4_1));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2489,7 +2533,7 @@ void Assembler::ptest(XMMRegister dst, XMMRegister src) {
void Assembler::psllq(XMMRegister reg, int8_t shift) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2501,7 +2545,7 @@ void Assembler::psllq(XMMRegister reg, int8_t shift) {
void Assembler::psllq(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2512,7 +2556,7 @@ void Assembler::psllq(XMMRegister dst, XMMRegister src) {
void Assembler::psrlq(XMMRegister reg, int8_t shift) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2524,7 +2568,7 @@ void Assembler::psrlq(XMMRegister reg, int8_t shift) {
void Assembler::psrlq(XMMRegister dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2535,7 +2579,7 @@ void Assembler::psrlq(XMMRegister dst, XMMRegister src) {
void Assembler::pshufd(XMMRegister dst, XMMRegister src, int8_t shuffle) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2547,7 +2591,7 @@ void Assembler::pshufd(XMMRegister dst, XMMRegister src, int8_t shuffle) {
void Assembler::pextrd(const Operand& dst, XMMRegister src, int8_t offset) {
- ASSERT(CpuFeatures::IsEnabled(SSE4_1));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE4_1));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2560,7 +2604,7 @@ void Assembler::pextrd(const Operand& dst, XMMRegister src, int8_t offset) {
void Assembler::pinsrd(XMMRegister dst, const Operand& src, int8_t offset) {
- ASSERT(CpuFeatures::IsEnabled(SSE4_1));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE4_1));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x66);
@@ -2629,7 +2673,7 @@ void Assembler::GrowBuffer() {
// Some internal data structures overflow for very large buffers,
// they must ensure that kMaximalBufferSize is not too large.
if ((desc.buffer_size > kMaximalBufferSize) ||
- (desc.buffer_size > Heap::MaxOldGenerationSize())) {
+ (desc.buffer_size > isolate()->heap()->MaxOldGenerationSize())) {
V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
}
@@ -2652,8 +2696,9 @@ void Assembler::GrowBuffer() {
reloc_info_writer.pos(), desc.reloc_size);
// Switch buffers.
- if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
- spare_buffer_ = buffer_;
+ if (isolate()->assembler_spare_buffer() == NULL &&
+ buffer_size_ == kMinimalBufferSize) {
+ isolate()->set_assembler_spare_buffer(buffer_);
} else {
DeleteArray(buffer_);
}
@@ -2761,7 +2806,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Serializer::TooLateToEnableNow();
}
#endif
- if (!Serializer::enabled() && !FLAG_debug_code) {
+ if (!Serializer::enabled() && !emit_debug_code()) {
return;
}
}
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index b60157c7..8e0c762a 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -37,6 +37,7 @@
#ifndef V8_IA32_ASSEMBLER_IA32_H_
#define V8_IA32_ASSEMBLER_IA32_H_
+#include "isolate.h"
#include "serialize.h"
namespace v8 {
@@ -445,16 +446,16 @@ class Displacement BASE_EMBEDDED {
// } else {
// // Generate standard x87 floating point code.
// }
-class CpuFeatures : public AllStatic {
+class CpuFeatures {
public:
// Detect features of the target CPU. If the portable flag is set,
// the method sets safe defaults if the serializer is enabled
// (snapshots must be portable).
- static void Probe(bool portable);
- static void Clear() { supported_ = 0; }
+ void Probe(bool portable);
+ void Clear() { supported_ = 0; }
// Check whether a feature is supported by the target CPU.
- static bool IsSupported(CpuFeature f) {
+ bool IsSupported(CpuFeature f) const {
if (f == SSE2 && !FLAG_enable_sse2) return false;
if (f == SSE3 && !FLAG_enable_sse3) return false;
if (f == SSE4_1 && !FLAG_enable_sse4_1) return false;
@@ -463,36 +464,51 @@ class CpuFeatures : public AllStatic {
return (supported_ & (static_cast<uint64_t>(1) << f)) != 0;
}
// Check whether a feature is currently enabled.
- static bool IsEnabled(CpuFeature f) {
+ bool IsEnabled(CpuFeature f) const {
return (enabled_ & (static_cast<uint64_t>(1) << f)) != 0;
}
// Enable a specified feature within a scope.
class Scope BASE_EMBEDDED {
#ifdef DEBUG
public:
- explicit Scope(CpuFeature f) {
+ explicit Scope(CpuFeature f)
+ : cpu_features_(Isolate::Current()->cpu_features()),
+ isolate_(Isolate::Current()) {
uint64_t mask = static_cast<uint64_t>(1) << f;
- ASSERT(CpuFeatures::IsSupported(f));
- ASSERT(!Serializer::enabled() || (found_by_runtime_probing_ & mask) == 0);
- old_enabled_ = CpuFeatures::enabled_;
- CpuFeatures::enabled_ |= mask;
+ ASSERT(cpu_features_->IsSupported(f));
+ ASSERT(!Serializer::enabled() ||
+ (cpu_features_->found_by_runtime_probing_ & mask) == 0);
+ old_enabled_ = cpu_features_->enabled_;
+ cpu_features_->enabled_ |= mask;
+ }
+ ~Scope() {
+ ASSERT_EQ(Isolate::Current(), isolate_);
+ cpu_features_->enabled_ = old_enabled_;
}
- ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
private:
uint64_t old_enabled_;
+ CpuFeatures* cpu_features_;
+ Isolate* isolate_;
#else
public:
explicit Scope(CpuFeature f) {}
#endif
};
+
private:
- static uint64_t supported_;
- static uint64_t enabled_;
- static uint64_t found_by_runtime_probing_;
+ CpuFeatures();
+
+ uint64_t supported_;
+ uint64_t enabled_;
+ uint64_t found_by_runtime_probing_;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
};
-class Assembler : public Malloced {
+class Assembler : public AssemblerBase {
private:
// We check before assembling an instruction that there is sufficient
// space to write an instruction and its relocation information.
@@ -522,6 +538,9 @@ class Assembler : public Malloced {
Assembler(void* buffer, int buffer_size);
~Assembler();
+ // Overrides the default provided by FLAG_debug_code.
+ void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
+
// GetCode emits any pending (non-emitted) code and fills the descriptor
// desc. GetCode() is idempotent; it returns the same result if no other
// Assembler functions are invoked in between GetCode() calls.
@@ -885,6 +904,7 @@ class Assembler : public Malloced {
void cvtsi2sd(XMMRegister dst, const Operand& src);
void cvtss2sd(XMMRegister dst, XMMRegister src);
+ void cvtsd2ss(XMMRegister dst, XMMRegister src);
void addsd(XMMRegister dst, XMMRegister src);
void subsd(XMMRegister dst, XMMRegister src);
@@ -915,6 +935,10 @@ class Assembler : public Malloced {
void movd(const Operand& src, XMMRegister dst);
void movsd(XMMRegister dst, XMMRegister src);
+ void movss(XMMRegister dst, const Operand& src);
+ void movss(const Operand& src, XMMRegister dst);
+ void movss(XMMRegister dst, XMMRegister src);
+
void pand(XMMRegister dst, XMMRegister src);
void pxor(XMMRegister dst, XMMRegister src);
void por(XMMRegister dst, XMMRegister src);
@@ -982,6 +1006,8 @@ class Assembler : public Malloced {
static const int kMinimalBufferSize = 4*KB;
protected:
+ bool emit_debug_code() const { return emit_debug_code_; }
+
void movsd(XMMRegister dst, const Operand& src);
void movsd(const Operand& dst, XMMRegister src);
@@ -989,7 +1015,8 @@ class Assembler : public Malloced {
void emit_sse_operand(XMMRegister dst, XMMRegister src);
void emit_sse_operand(Register dst, XMMRegister src);
- byte* addr_at(int pos) { return buffer_ + pos; }
+ byte* addr_at(int pos) { return buffer_ + pos; }
+
private:
byte byte_at(int pos) { return buffer_[pos]; }
void set_byte_at(int pos, byte value) { buffer_[pos] = value; }
@@ -1045,8 +1072,6 @@ class Assembler : public Malloced {
int buffer_size_;
// True if the assembler owns the buffer, false if buffer is external.
bool own_buffer_;
- // A previously allocated buffer of kMinimalBufferSize bytes, or NULL.
- static byte* spare_buffer_;
// code generation
byte* pc_; // the program counter; moves forward
@@ -1057,6 +1082,8 @@ class Assembler : public Malloced {
PositionsRecorder positions_recorder_;
+ bool emit_debug_code_;
+
friend class PositionsRecorder;
};
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index c7e55270..2970a0e0 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -70,7 +70,7 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm,
// JumpToExternalReference expects eax to contain the number of arguments
// including the receiver and the extra arguments.
__ add(Operand(eax), Immediate(num_extra_args + 1));
- __ JumpToExternalReference(ExternalReference(id));
+ __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
}
@@ -100,8 +100,9 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// Set expected number of arguments to zero (not changing eax).
__ Set(ebx, Immediate(0));
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
- __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
- RelocInfo::CODE_TARGET);
+ Handle<Code> arguments_adaptor =
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+ __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
}
@@ -128,7 +129,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Label undo_allocation;
#ifdef ENABLE_DEBUGGER_SUPPORT
ExternalReference debug_step_in_fp =
- ExternalReference::debug_step_in_fp_address();
+ ExternalReference::debug_step_in_fp_address(masm->isolate());
__ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
__ j(not_equal, &rt_call);
#endif
@@ -184,7 +185,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// ebx: JSObject
// edi: start of next object
__ mov(Operand(ebx, JSObject::kMapOffset), eax);
- __ mov(ecx, Factory::empty_fixed_array());
+ Factory* factory = masm->isolate()->factory();
+ __ mov(ecx, factory->empty_fixed_array());
__ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
__ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
// Set extra fields in the newly allocated object.
@@ -194,9 +196,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
{ Label loop, entry;
// To allow for truncation.
if (count_constructions) {
- __ mov(edx, Factory::one_pointer_filler_map());
+ __ mov(edx, factory->one_pointer_filler_map());
} else {
- __ mov(edx, Factory::undefined_value());
+ __ mov(edx, factory->undefined_value());
}
__ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
__ jmp(&entry);
@@ -252,7 +254,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// edi: FixedArray
// edx: number of elements
// ecx: start of next object
- __ mov(eax, Factory::fixed_array_map());
+ __ mov(eax, factory->fixed_array_map());
__ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
__ SmiTag(edx);
__ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
@@ -262,7 +264,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// edi: FixedArray
// ecx: start of next object
{ Label loop, entry;
- __ mov(edx, Factory::undefined_value());
+ __ mov(edx, factory->undefined_value());
__ lea(eax, Operand(edi, FixedArray::kHeaderSize));
__ jmp(&entry);
__ bind(&loop);
@@ -334,8 +336,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Call the function.
if (is_api_function) {
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
- Handle<Code> code = Handle<Code>(
- Builtins::builtin(Builtins::HandleApiCallConstruct));
+ Handle<Code> code =
+ masm->isolate()->builtins()->HandleApiCallConstruct();
ParameterCount expected(0);
__ InvokeCode(code, expected, expected,
RelocInfo::CODE_TARGET, CALL_FUNCTION);
@@ -376,7 +378,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ pop(ecx);
__ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
__ push(ecx);
- __ IncrementCounter(&Counters::constructed_objects, 1);
+ __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
__ ret(0);
}
@@ -436,7 +438,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// Invoke the code.
if (is_construct) {
- __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
+ __ call(masm->isolate()->builtins()->JSConstructCall(),
RelocInfo::CODE_TARGET);
} else {
ParameterCount actual(eax);
@@ -561,12 +563,14 @@ void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
+ Factory* factory = masm->isolate()->factory();
+
// 1. Make sure we have at least one argument.
{ Label done;
__ test(eax, Operand(eax));
__ j(not_zero, &done, taken);
__ pop(ebx);
- __ push(Immediate(Factory::undefined_value()));
+ __ push(Immediate(factory->undefined_value()));
__ push(ebx);
__ inc(eax);
__ bind(&done);
@@ -600,9 +604,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ test(ebx, Immediate(kSmiTagMask));
__ j(zero, &convert_to_object);
- __ cmp(ebx, Factory::null_value());
+ __ cmp(ebx, factory->null_value());
__ j(equal, &use_global_receiver);
- __ cmp(ebx, Factory::undefined_value());
+ __ cmp(ebx, factory->undefined_value());
__ j(equal, &use_global_receiver);
// We don't use IsObjectJSObjectType here because we jump on success.
@@ -674,7 +678,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ j(not_zero, &function, taken);
__ Set(ebx, Immediate(0));
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
- __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+ __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
}
@@ -688,7 +692,8 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
__ SmiUntag(ebx);
__ cmp(eax, Operand(ebx));
- __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline)));
+ __ j(not_equal,
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
ParameterCount expected(0);
__ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
@@ -707,7 +712,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
// limit" is checked.
Label okay;
ExternalReference real_stack_limit =
- ExternalReference::address_of_real_stack_limit();
+ ExternalReference::address_of_real_stack_limit(masm->isolate());
__ mov(edi, Operand::StaticVariable(real_stack_limit));
// Make ecx the space we have left. The stack might already be overflowed
// here which will cause ecx to become negative.
@@ -753,9 +758,10 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
// Compute the receiver in non-strict mode.
__ test(ebx, Immediate(kSmiTagMask));
__ j(zero, &call_to_object);
- __ cmp(ebx, Factory::null_value());
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(ebx, factory->null_value());
__ j(equal, &use_global_receiver);
- __ cmp(ebx, Factory::undefined_value());
+ __ cmp(ebx, factory->undefined_value());
__ j(equal, &use_global_receiver);
// If given receiver is already a JavaScript object then there's no
@@ -795,7 +801,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments
// Use inline caching to speed up access to arguments.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
__ call(ic, RelocInfo::CODE_TARGET);
// It is important that we do not have a test instruction after the
// call. A test instruction after the call is used to indicate that
@@ -866,8 +872,9 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// scratch1: initial map
// scratch2: start of next object
__ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
+ Factory* factory = masm->isolate()->factory();
__ mov(FieldOperand(result, JSArray::kPropertiesOffset),
- Factory::empty_fixed_array());
+ factory->empty_fixed_array());
// Field JSArray::kElementsOffset is initialized later.
__ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
@@ -875,7 +882,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// fixed array.
if (initial_capacity == 0) {
__ mov(FieldOperand(result, JSArray::kElementsOffset),
- Factory::empty_fixed_array());
+ factory->empty_fixed_array());
return;
}
@@ -892,7 +899,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// scratch1: elements array
// scratch2: start of next object
__ mov(FieldOperand(scratch1, FixedArray::kMapOffset),
- Factory::fixed_array_map());
+ factory->fixed_array_map());
__ mov(FieldOperand(scratch1, FixedArray::kLengthOffset),
Immediate(Smi::FromInt(initial_capacity)));
@@ -903,7 +910,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
if (initial_capacity <= kLoopUnfoldLimit) {
// Use a scratch register here to have only one reloc info when unfolding
// the loop.
- __ mov(scratch3, Factory::the_hole_value());
+ __ mov(scratch3, factory->the_hole_value());
for (int i = 0; i < initial_capacity; i++) {
__ mov(FieldOperand(scratch1,
FixedArray::kHeaderSize + i * kPointerSize),
@@ -913,7 +920,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
Label loop, entry;
__ jmp(&entry);
__ bind(&loop);
- __ mov(Operand(scratch1, 0), Factory::the_hole_value());
+ __ mov(Operand(scratch1, 0), factory->the_hole_value());
__ add(Operand(scratch1), Immediate(kPointerSize));
__ bind(&entry);
__ cmp(scratch1, Operand(scratch2));
@@ -968,7 +975,8 @@ static void AllocateJSArray(MacroAssembler* masm,
// elements_array_end: start of next object
// array_size: size of array (smi)
__ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
- __ mov(elements_array, Factory::empty_fixed_array());
+ Factory* factory = masm->isolate()->factory();
+ __ mov(elements_array, factory->empty_fixed_array());
__ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
// Field JSArray::kElementsOffset is initialized later.
__ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
@@ -987,7 +995,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// elements_array_end: start of next object
// array_size: size of array (smi)
__ mov(FieldOperand(elements_array, FixedArray::kMapOffset),
- Factory::fixed_array_map());
+ factory->fixed_array_map());
// For non-empty JSArrays the length of the FixedArray and the JSArray is the
// same.
__ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
@@ -999,7 +1007,7 @@ static void AllocateJSArray(MacroAssembler* masm,
__ SmiUntag(array_size);
__ lea(edi, Operand(elements_array,
FixedArray::kHeaderSize - kHeapObjectTag));
- __ mov(eax, Factory::the_hole_value());
+ __ mov(eax, factory->the_hole_value());
__ cld();
// Do not use rep stos when filling less than kRepStosThreshold
// words.
@@ -1063,7 +1071,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
edi,
kPreallocatedArrayElements,
&prepare_generic_code_call);
- __ IncrementCounter(&Counters::array_function_native, 1);
+ __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
__ pop(ebx);
if (construct_call) {
__ pop(edi);
@@ -1119,7 +1127,8 @@ static void ArrayNativeCode(MacroAssembler* masm,
edi,
true,
&prepare_generic_code_call);
- __ IncrementCounter(&Counters::array_function_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->array_function_native(), 1);
__ mov(eax, ebx);
__ pop(ebx);
if (construct_call) {
@@ -1146,7 +1155,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
edi,
false,
&prepare_generic_code_call);
- __ IncrementCounter(&Counters::array_function_native, 1);
+ __ IncrementCounter(counters->array_function_native(), 1);
__ mov(eax, ebx);
__ pop(ebx);
if (construct_call) {
@@ -1232,8 +1241,8 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
// Jump to the generic array code in case the specialized code cannot handle
// the construction.
__ bind(&generic_array_code);
- Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
- Handle<Code> array_code(code);
+ Handle<Code> array_code =
+ masm->isolate()->builtins()->ArrayCodeGeneric();
__ jmp(array_code, RelocInfo::CODE_TARGET);
}
@@ -1266,8 +1275,8 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
// Jump to the generic construct code in case the specialized code cannot
// handle the construction.
__ bind(&generic_constructor);
- Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
- Handle<Code> generic_construct_stub(code);
+ Handle<Code> generic_construct_stub =
+ masm->isolate()->builtins()->JSConstructStubGeneric();
__ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
}
@@ -1280,7 +1289,8 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
- __ IncrementCounter(&Counters::string_ctor_calls, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->string_ctor_calls(), 1);
if (FLAG_debug_code) {
__ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
@@ -1309,7 +1319,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
edx, // Scratch 2.
false, // Input is known to be smi?
&not_cached);
- __ IncrementCounter(&Counters::string_ctor_cached_number, 1);
+ __ IncrementCounter(counters->string_ctor_cached_number(), 1);
__ bind(&argument_is_string);
// ----------- S t a t e -------------
// -- ebx : argument converted to string
@@ -1338,7 +1348,8 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
__ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
// Set properties and elements.
- __ Set(ecx, Immediate(Factory::empty_fixed_array()));
+ Factory* factory = masm->isolate()->factory();
+ __ Set(ecx, Immediate(factory->empty_fixed_array()));
__ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
__ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
@@ -1361,12 +1372,12 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
__ j(NegateCondition(is_string), &convert_argument);
__ mov(ebx, eax);
- __ IncrementCounter(&Counters::string_ctor_string_value, 1);
+ __ IncrementCounter(counters->string_ctor_string_value(), 1);
__ jmp(&argument_is_string);
// Invoke the conversion builtin and put the result into ebx.
__ bind(&convert_argument);
- __ IncrementCounter(&Counters::string_ctor_conversions, 1);
+ __ IncrementCounter(counters->string_ctor_conversions(), 1);
__ EnterInternalFrame();
__ push(edi); // Preserve the function.
__ push(eax);
@@ -1379,7 +1390,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// Load the empty string into ebx, remove the receiver from the
// stack, and jump back to the case where the argument is a string.
__ bind(&no_arguments);
- __ Set(ebx, Immediate(Factory::empty_string()));
+ __ Set(ebx, Immediate(factory->empty_string()));
__ pop(ecx);
__ lea(esp, Operand(esp, kPointerSize));
__ push(ecx);
@@ -1388,7 +1399,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// At this point the argument is already a string. Call runtime to
// create a string wrapper.
__ bind(&gc_required);
- __ IncrementCounter(&Counters::string_ctor_gc_required, 1);
+ __ IncrementCounter(counters->string_ctor_gc_required(), 1);
__ EnterInternalFrame();
__ push(ebx);
__ CallRuntime(Runtime::kNewStringWrapper, 1);
@@ -1439,7 +1450,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// -----------------------------------
Label invoke, dont_adapt_arguments;
- __ IncrementCounter(&Counters::arguments_adaptors, 1);
+ __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
Label enough, too_few;
__ cmp(eax, Operand(ebx));
@@ -1487,7 +1498,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
Label fill;
__ bind(&fill);
__ inc(ecx);
- __ push(Immediate(Factory::undefined_value()));
+ __ push(Immediate(masm->isolate()->factory()->undefined_value()));
__ cmp(ecx, Operand(ebx));
__ j(less, &fill);
@@ -1515,8 +1526,9 @@ void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
// We shouldn't be performing on-stack replacement in the first
// place if the CPU features we need for the optimized Crankshaft
// code aren't supported.
- CpuFeatures::Probe(false);
- if (!CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures* cpu_features = masm->isolate()->cpu_features();
+ cpu_features->Probe(false);
+ if (!cpu_features->IsSupported(SSE2)) {
__ Abort("Unreachable code: Cannot optimize without SSE2 support.");
return;
}
@@ -1560,7 +1572,7 @@ void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
__ bind(&stack_check);
NearLabel ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(masm->isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &ok, taken);
StackCheckStub stub;
@@ -1582,7 +1594,7 @@ void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
#undef __
-
-} } // namespace v8::internal
+}
+} // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 7efa9340..96faae99 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -32,6 +32,7 @@
#include "code-stubs.h"
#include "bootstrapper.h"
#include "jsregexp.h"
+#include "isolate.h"
#include "regexp-macro-assembler.h"
namespace v8 {
@@ -48,7 +49,8 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
__ bind(&check_heap_number);
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
- __ cmp(Operand(ebx), Immediate(Factory::heap_number_map()));
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(Operand(ebx), Immediate(factory->heap_number_map()));
__ j(not_equal, &call_builtin);
__ ret(0);
@@ -69,25 +71,30 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
// Get the function info from the stack.
__ mov(edx, Operand(esp, 1 * kPointerSize));
+ int map_index = strict_mode_ == kStrictMode
+ ? Context::STRICT_MODE_FUNCTION_MAP_INDEX
+ : Context::FUNCTION_MAP_INDEX;
+
// Compute the function map in the current global context and set that
// as the map of the allocated object.
__ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset));
- __ mov(ecx, Operand(ecx, Context::SlotOffset(Context::FUNCTION_MAP_INDEX)));
+ __ mov(ecx, Operand(ecx, Context::SlotOffset(map_index)));
__ mov(FieldOperand(eax, JSObject::kMapOffset), ecx);
// Initialize the rest of the function. We don't have to update the
// write barrier because the allocated object is in new space.
- __ mov(ebx, Immediate(Factory::empty_fixed_array()));
+ Factory* factory = masm->isolate()->factory();
+ __ mov(ebx, Immediate(factory->empty_fixed_array()));
__ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ebx);
__ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx);
__ mov(FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset),
- Immediate(Factory::the_hole_value()));
+ Immediate(factory->the_hole_value()));
__ mov(FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset), edx);
__ mov(FieldOperand(eax, JSFunction::kContextOffset), esi);
__ mov(FieldOperand(eax, JSFunction::kLiteralsOffset), ebx);
__ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset),
- Immediate(Factory::undefined_value()));
+ Immediate(factory->undefined_value()));
// Initialize the code pointer in the function to be the one
// found in the shared function info object.
@@ -104,7 +111,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
__ pop(edx);
__ push(esi);
__ push(edx);
- __ push(Immediate(Factory::false_value()));
+ __ push(Immediate(factory->false_value()));
__ push(ecx); // Restore return address.
__ TailCallRuntime(Runtime::kNewClosure, 3, 1);
}
@@ -121,7 +128,8 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
__ mov(ecx, Operand(esp, 1 * kPointerSize));
// Setup the object header.
- __ mov(FieldOperand(eax, HeapObject::kMapOffset), Factory::context_map());
+ Factory* factory = masm->isolate()->factory();
+ __ mov(FieldOperand(eax, HeapObject::kMapOffset), factory->context_map());
__ mov(FieldOperand(eax, Context::kLengthOffset),
Immediate(Smi::FromInt(length)));
@@ -140,7 +148,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
__ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx);
// Initialize the rest of the slots to undefined.
- __ mov(ebx, Factory::undefined_value());
+ __ mov(ebx, factory->undefined_value());
for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
__ mov(Operand(eax, Context::SlotOffset(i)), ebx);
}
@@ -176,7 +184,8 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
STATIC_ASSERT(kSmiTag == 0);
__ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size,
FixedArray::kHeaderSize));
- __ cmp(ecx, Factory::undefined_value());
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(ecx, factory->undefined_value());
__ j(equal, &slow_case);
if (FLAG_debug_code) {
@@ -184,11 +193,11 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
Handle<Map> expected_map;
if (mode_ == CLONE_ELEMENTS) {
message = "Expected (writable) fixed array";
- expected_map = Factory::fixed_array_map();
+ expected_map = factory->fixed_array_map();
} else {
ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS);
message = "Expected copy-on-write fixed array";
- expected_map = Factory::fixed_cow_array_map();
+ expected_map = factory->fixed_cow_array_map();
}
__ push(ecx);
__ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
@@ -237,7 +246,8 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ mov(eax, Operand(esp, 1 * kPointerSize));
// 'null' => false.
- __ cmp(eax, Factory::null_value());
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(eax, factory->null_value());
__ j(equal, &false_result);
// Get the map and type of the heap object.
@@ -263,7 +273,7 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
__ bind(&not_string);
// HeapNumber => false iff +0, -0, or NaN.
- __ cmp(edx, Factory::heap_number_map());
+ __ cmp(edx, factory->heap_number_map());
__ j(not_equal, &true_result);
__ fldz();
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
@@ -284,7 +294,8 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
const char* GenericBinaryOpStub::GetName() {
if (name_ != NULL) return name_;
const int kMaxNameLength = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
+ kMaxNameLength);
if (name_ == NULL) return "OOM";
const char* op_name = Token::Name(op_);
const char* overwrite_name;
@@ -358,7 +369,8 @@ void GenericBinaryOpStub::GenerateCall(
// Update flags to indicate that arguments are in registers.
SetArgsInRegisters();
- __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
+ __ IncrementCounter(
+ masm->isolate()->counters()->generic_binary_stub_calls_regs(), 1);
}
// Call the stub.
@@ -394,7 +406,8 @@ void GenericBinaryOpStub::GenerateCall(
// Update flags to indicate that arguments are in registers.
SetArgsInRegisters();
- __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
+ __ IncrementCounter(
+ masm->isolate()->counters()->generic_binary_stub_calls_regs(), 1);
}
// Call the stub.
@@ -429,7 +442,8 @@ void GenericBinaryOpStub::GenerateCall(
}
// Update flags to indicate that arguments are in registers.
SetArgsInRegisters();
- __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->generic_binary_stub_calls_regs(), 1);
}
// Call the stub.
@@ -757,7 +771,7 @@ void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
// number in eax.
__ AllocateHeapNumber(eax, ecx, ebx, slow);
// Store the result in the HeapNumber and return.
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ cvtsi2sd(xmm0, Operand(left));
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
@@ -807,7 +821,7 @@ void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
}
if (runtime_operands_type_ != BinaryOpIC::UNINIT_OR_SMI) {
__ AllocateHeapNumber(ecx, ebx, no_reg, slow);
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
FloatingPointHelper::LoadSSE2Smis(masm, ebx);
switch (op_) {
@@ -872,7 +886,8 @@ void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
Label call_runtime;
- __ IncrementCounter(&Counters::generic_binary_stub_calls, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->generic_binary_stub_calls(), 1);
if (runtime_operands_type_ == BinaryOpIC::UNINIT_OR_SMI) {
Label slow;
@@ -911,7 +926,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
}
Label not_floats;
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
if (static_operands_type_.IsNumber()) {
if (FLAG_debug_code) {
@@ -1045,7 +1060,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
default: UNREACHABLE();
}
// Store the result in the HeapNumber and return.
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ cvtsi2sd(xmm0, Operand(ebx));
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
@@ -1263,7 +1278,7 @@ void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
// Patch the caller to an appropriate specialized stub and return the
// operation result to the caller of the stub.
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
+ ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()),
5,
1);
}
@@ -1299,7 +1314,8 @@ void TypeRecordingBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
// Patch the caller to an appropriate specialized stub and return the
// operation result to the caller of the stub.
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch)),
+ ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch),
+ masm->isolate()),
5,
1);
}
@@ -1322,7 +1338,8 @@ void TypeRecordingBinaryOpStub::GenerateTypeTransitionWithSavedArgs(
// Patch the caller to an appropriate specialized stub and return the
// operation result to the caller of the stub.
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch)),
+ ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch),
+ masm->isolate()),
5,
1);
}
@@ -1342,6 +1359,9 @@ void TypeRecordingBinaryOpStub::Generate(MacroAssembler* masm) {
case TRBinaryOpIC::HEAP_NUMBER:
GenerateHeapNumberStub(masm);
break;
+ case TRBinaryOpIC::ODDBALL:
+ GenerateOddballStub(masm);
+ break;
case TRBinaryOpIC::STRING:
GenerateStringStub(masm);
break;
@@ -1357,7 +1377,8 @@ void TypeRecordingBinaryOpStub::Generate(MacroAssembler* masm) {
const char* TypeRecordingBinaryOpStub::GetName() {
if (name_ != NULL) return name_;
const int kMaxNameLength = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
+ kMaxNameLength);
if (name_ == NULL) return "OOM";
const char* op_name = Token::Name(op_);
const char* overwrite_name;
@@ -1639,7 +1660,7 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
// number in eax.
__ AllocateHeapNumber(eax, ecx, ebx, slow);
// Store the result in the HeapNumber and return.
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ cvtsi2sd(xmm0, Operand(left));
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
@@ -1684,7 +1705,7 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
break;
}
__ AllocateHeapNumber(ecx, ebx, no_reg, slow);
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
FloatingPointHelper::LoadSSE2Smis(masm, ebx);
switch (op_) {
@@ -1816,7 +1837,7 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
case Token::DIV: {
Label not_floats;
Label not_int32;
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
@@ -1937,7 +1958,7 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
default: UNREACHABLE();
}
// Store the result in the HeapNumber and return.
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ cvtsi2sd(xmm0, Operand(ebx));
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
@@ -2006,9 +2027,41 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
}
+void TypeRecordingBinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
+ Label call_runtime;
+
+ if (op_ == Token::ADD) {
+ // Handle string addition here, because it is the only operation
+ // that does not do a ToNumber conversion on the operands.
+ GenerateAddStrings(masm);
+ }
+
+ // Convert odd ball arguments to numbers.
+ NearLabel check, done;
+ __ cmp(edx, FACTORY->undefined_value());
+ __ j(not_equal, &check);
+ if (Token::IsBitOp(op_)) {
+ __ xor_(edx, Operand(edx));
+ } else {
+ __ mov(edx, Immediate(FACTORY->nan_value()));
+ }
+ __ jmp(&done);
+ __ bind(&check);
+ __ cmp(eax, FACTORY->undefined_value());
+ __ j(not_equal, &done);
+ if (Token::IsBitOp(op_)) {
+ __ xor_(eax, Operand(eax));
+ } else {
+ __ mov(eax, Immediate(FACTORY->nan_value()));
+ }
+ __ bind(&done);
+
+ GenerateHeapNumberStub(masm);
+}
+
+
void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
Label call_runtime;
- ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER);
// Floating point case.
switch (op_) {
@@ -2017,7 +2070,7 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
case Token::MUL:
case Token::DIV: {
Label not_floats;
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
@@ -2120,7 +2173,7 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
default: UNREACHABLE();
}
// Store the result in the HeapNumber and return.
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ cvtsi2sd(xmm0, Operand(ebx));
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
@@ -2191,7 +2244,8 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
Label call_runtime;
- __ IncrementCounter(&Counters::generic_binary_stub_calls, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->generic_binary_stub_calls(), 1);
switch (op_) {
case Token::ADD:
@@ -2221,7 +2275,7 @@ void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
case Token::MUL:
case Token::DIV: {
Label not_floats;
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
@@ -2319,7 +2373,7 @@ void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
default: UNREACHABLE();
}
// Store the result in the HeapNumber and return.
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ cvtsi2sd(xmm0, Operand(ebx));
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
@@ -2507,7 +2561,8 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ bind(&input_not_smi);
// Check if input is a HeapNumber.
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
- __ cmp(Operand(ebx), Immediate(Factory::heap_number_map()));
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(Operand(ebx), Immediate(factory->heap_number_map()));
__ j(not_equal, &runtime_call);
// Input is a HeapNumber. Push it on the FPU stack and load its
// low and high words into ebx, edx.
@@ -2517,7 +2572,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ bind(&loaded);
} else { // UNTAGGED.
- if (CpuFeatures::IsSupported(SSE4_1)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE4_1)) {
CpuFeatures::Scope sse4_scope(SSE4_1);
__ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx.
} else {
@@ -2540,24 +2595,27 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ mov(eax, ecx);
__ sar(eax, 8);
__ xor_(ecx, Operand(eax));
- ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
- __ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1));
+ ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
+ __ and_(Operand(ecx),
+ Immediate(TranscendentalCache::SubCache::kCacheSize - 1));
// ST[0] or xmm1 == double value.
// ebx = low 32 bits of double value.
// edx = high 32 bits of double value.
// ecx = TranscendentalCache::hash(double value).
- __ mov(eax,
- Immediate(ExternalReference::transcendental_cache_array_address()));
- // Eax points to cache array.
- __ mov(eax, Operand(eax, type_ * sizeof(TranscendentalCache::caches_[0])));
+ ExternalReference cache_array =
+ ExternalReference::transcendental_cache_array_address(masm->isolate());
+ __ mov(eax, Immediate(cache_array));
+ int cache_array_index =
+ type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]);
+ __ mov(eax, Operand(eax, cache_array_index));
// Eax points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
__ test(eax, Operand(eax));
__ j(zero, &runtime_call_clear_stack);
#ifdef DEBUG
// Check that the layout of cache elements match expectations.
- { TranscendentalCache::Element test_elem[2];
+ { TranscendentalCache::SubCache::Element test_elem[2];
char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
@@ -2636,7 +2694,9 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ bind(&runtime_call_clear_stack);
__ fstp(0);
__ bind(&runtime_call);
- __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+ ExternalReference runtime =
+ ExternalReference(RuntimeFunction(), masm->isolate());
+ __ TailCallExternalReference(runtime, 1, 1);
} else { // UNTAGGED.
__ bind(&runtime_call_clear_stack);
__ bind(&runtime_call);
@@ -2766,7 +2826,8 @@ void IntegerConvert(MacroAssembler* masm,
Label done, right_exponent, normal_exponent;
Register scratch = ebx;
Register scratch2 = edi;
- if (type_info.IsInteger32() && CpuFeatures::IsEnabled(SSE2)) {
+ if (type_info.IsInteger32() &&
+ masm->isolate()->cpu_features()->IsEnabled(SSE2)) {
CpuFeatures::Scope scope(SSE2);
__ cvttsd2si(ecx, FieldOperand(source, HeapNumber::kValueOffset));
return;
@@ -2969,14 +3030,15 @@ void FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm,
// If the argument is undefined it converts to zero (ECMA-262, section 9.5).
__ bind(&check_undefined_arg1);
- __ cmp(edx, Factory::undefined_value());
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(edx, factory->undefined_value());
__ j(not_equal, conversion_failure);
__ mov(edx, Immediate(0));
__ jmp(&load_arg2);
__ bind(&arg1_is_object);
__ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
- __ cmp(ebx, Factory::heap_number_map());
+ __ cmp(ebx, factory->heap_number_map());
__ j(not_equal, &check_undefined_arg1);
// Get the untagged integer version of the edx heap number in ecx.
@@ -3000,14 +3062,14 @@ void FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm,
// If the argument is undefined it converts to zero (ECMA-262, section 9.5).
__ bind(&check_undefined_arg2);
- __ cmp(eax, Factory::undefined_value());
+ __ cmp(eax, factory->undefined_value());
__ j(not_equal, conversion_failure);
__ mov(ecx, Immediate(0));
__ jmp(&done);
__ bind(&arg2_is_object);
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
- __ cmp(ebx, Factory::heap_number_map());
+ __ cmp(ebx, factory->heap_number_map());
__ j(not_equal, &check_undefined_arg2);
// Get the untagged integer version of the eax heap number in ecx.
@@ -3094,14 +3156,15 @@ void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm,
// Load operand in edx into xmm0, or branch to not_numbers.
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &load_smi_edx, not_taken); // Argument in edx is a smi.
- __ cmp(FieldOperand(edx, HeapObject::kMapOffset), Factory::heap_number_map());
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map());
__ j(not_equal, not_numbers); // Argument in edx is not a number.
__ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
__ bind(&load_eax);
// Load operand in eax into xmm1, or branch to not_numbers.
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &load_smi_eax, not_taken); // Argument in eax is a smi.
- __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::heap_number_map());
+ __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map());
__ j(equal, &load_float_eax);
__ jmp(not_numbers); // Argument in eax is not a number.
__ bind(&load_smi_edx);
@@ -3219,14 +3282,15 @@ void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &test_other, not_taken); // argument in edx is OK
__ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
- __ cmp(scratch, Factory::heap_number_map());
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(scratch, factory->heap_number_map());
__ j(not_equal, non_float); // argument in edx is not a number -> NaN
__ bind(&test_other);
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &done); // argument in eax is OK
__ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
- __ cmp(scratch, Factory::heap_number_map());
+ __ cmp(scratch, factory->heap_number_map());
__ j(not_equal, non_float); // argument in eax is not a number -> NaN
// Fall-through: Both operands are numbers.
@@ -3272,7 +3336,7 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
}
__ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
- __ cmp(edx, Factory::heap_number_map());
+ __ cmp(edx, masm->isolate()->factory()->heap_number_map());
__ j(not_equal, &slow);
if (overwrite_ == UNARY_OVERWRITE) {
__ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
@@ -3304,14 +3368,14 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
// Check if the operand is a heap number.
__ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
- __ cmp(edx, Factory::heap_number_map());
+ __ cmp(edx, masm->isolate()->factory()->heap_number_map());
__ j(not_equal, &slow, not_taken);
// Convert the heap number in eax to an untagged integer in ecx.
IntegerConvert(masm,
eax,
TypeInfo::Unknown(),
- CpuFeatures::IsSupported(SSE3),
+ masm->isolate()->cpu_features()->IsSupported(SSE3),
&slow);
// Do the bitwise operation and check if the result fits in a smi.
@@ -3334,7 +3398,7 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
__ AllocateHeapNumber(ebx, edx, edi, &slow);
__ mov(eax, Operand(ebx));
}
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ cvtsi2sd(xmm0, Operand(ecx));
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
@@ -3406,8 +3470,9 @@ void MathPowStub::Generate(MacroAssembler* masm) {
__ jmp(&powi);
// exponent is smi and base is a heapnumber.
__ bind(&base_nonsmi);
+ Factory* factory = masm->isolate()->factory();
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory->heap_number_map());
__ j(not_equal, &call_runtime);
__ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
@@ -3459,7 +3524,7 @@ void MathPowStub::Generate(MacroAssembler* masm) {
// on doubles.
__ bind(&exponent_nonsmi);
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory->heap_number_map());
__ j(not_equal, &call_runtime);
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
// Test if exponent is nan.
@@ -3476,7 +3541,7 @@ void MathPowStub::Generate(MacroAssembler* masm) {
__ bind(&base_not_smi);
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory->heap_number_map());
__ j(not_equal, &call_runtime);
__ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
__ and_(ecx, HeapNumber::kExponentMask);
@@ -3628,16 +3693,16 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
__ j(zero, &add_arguments_object);
__ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
__ bind(&add_arguments_object);
- __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSize));
+ __ add(Operand(ecx), Immediate(GetArgumentsObjectSize()));
// Do the allocation of both objects in one go.
__ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
// Get the arguments boilerplate from the current (global) context.
- int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
__ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
- __ mov(edi, Operand(edi, offset));
+ __ mov(edi, Operand(edi,
+ Context::SlotOffset(GetArgumentsBoilerplateIndex())));
// Copy the JS object part.
for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
@@ -3645,15 +3710,21 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
__ mov(FieldOperand(eax, i), ebx);
}
- // Setup the callee in-object property.
- STATIC_ASSERT(Heap::arguments_callee_index == 0);
- __ mov(ebx, Operand(esp, 3 * kPointerSize));
- __ mov(FieldOperand(eax, JSObject::kHeaderSize), ebx);
+ if (type_ == NEW_NON_STRICT) {
+ // Setup the callee in-object property.
+ STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
+ __ mov(ebx, Operand(esp, 3 * kPointerSize));
+ __ mov(FieldOperand(eax, JSObject::kHeaderSize +
+ Heap::kArgumentsCalleeIndex * kPointerSize),
+ ebx);
+ }
// Get the length (smi tagged) and set that as an in-object property too.
- STATIC_ASSERT(Heap::arguments_length_index == 1);
+ STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
__ mov(ecx, Operand(esp, 1 * kPointerSize));
- __ mov(FieldOperand(eax, JSObject::kHeaderSize + kPointerSize), ecx);
+ __ mov(FieldOperand(eax, JSObject::kHeaderSize +
+ Heap::kArgumentsLengthIndex * kPointerSize),
+ ecx);
// If there are no actual arguments, we're done.
Label done;
@@ -3665,10 +3736,11 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
// Setup the elements pointer in the allocated arguments object and
// initialize the header in the elements fixed array.
- __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize));
+ __ lea(edi, Operand(eax, GetArgumentsObjectSize()));
__ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
__ mov(FieldOperand(edi, FixedArray::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(masm->isolate()->factory()->fixed_array_map()));
+
__ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
// Untag the length for the loop below.
__ SmiUntag(ecx);
@@ -3721,9 +3793,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Ensure that a RegExp stack is allocated.
ExternalReference address_of_regexp_stack_memory_address =
- ExternalReference::address_of_regexp_stack_memory_address();
+ ExternalReference::address_of_regexp_stack_memory_address(
+ masm->isolate());
ExternalReference address_of_regexp_stack_memory_size =
- ExternalReference::address_of_regexp_stack_memory_size();
+ ExternalReference::address_of_regexp_stack_memory_size(masm->isolate());
__ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
__ test(ebx, Operand(ebx));
__ j(zero, &runtime, not_taken);
@@ -3795,7 +3868,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Check that the JSArray is in fast case.
__ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
__ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset));
- __ cmp(eax, Factory::fixed_array_map());
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(eax, factory->fixed_array_map());
__ j(not_equal, &runtime);
// Check that the last match info has space for the capture registers and the
// additional information.
@@ -3833,7 +3907,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ j(not_zero, &runtime);
// String is a cons string.
__ mov(edx, FieldOperand(eax, ConsString::kSecondOffset));
- __ cmp(Operand(edx), Factory::empty_string());
+ __ cmp(Operand(edx), factory->empty_string());
__ j(not_equal, &runtime);
__ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
@@ -3883,11 +3957,17 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// edx: code
// edi: encoding of subject string (1 if ascii 0 if two_byte);
// All checks done. Now push arguments for native regexp code.
- __ IncrementCounter(&Counters::regexp_entry_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->regexp_entry_native(), 1);
- static const int kRegExpExecuteArguments = 7;
+ // Isolates: note we add an additional parameter here (isolate pointer).
+ static const int kRegExpExecuteArguments = 8;
__ EnterApiExitFrame(kRegExpExecuteArguments);
+ // Argument 8: Pass current isolate address.
+ __ mov(Operand(esp, 7 * kPointerSize),
+ Immediate(ExternalReference::isolate_address()));
+
// Argument 7: Indicate that this is a direct call from JavaScript.
__ mov(Operand(esp, 6 * kPointerSize), Immediate(1));
@@ -3898,7 +3978,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Argument 5: static offsets vector buffer.
__ mov(Operand(esp, 4 * kPointerSize),
- Immediate(ExternalReference::address_of_static_offsets_vector()));
+ Immediate(ExternalReference::address_of_static_offsets_vector(
+ masm->isolate())));
// Argument 4: End of string data
// Argument 3: Start of string data
@@ -3950,9 +4031,11 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system.
// TODO(592): Rerunning the RegExp to get the stack overflow exception.
- ExternalReference pending_exception(Top::k_pending_exception_address);
+ ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ masm->isolate());
__ mov(edx,
- Operand::StaticVariable(ExternalReference::the_hole_value_location()));
+ Operand::StaticVariable(ExternalReference::the_hole_value_location(
+ masm->isolate())));
__ mov(eax, Operand::StaticVariable(pending_exception));
__ cmp(edx, Operand(eax));
__ j(equal, &runtime);
@@ -3963,7 +4046,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Special handling of termination exceptions which are uncatchable
// by javascript code.
- __ cmp(eax, Factory::termination_exception());
+ __ cmp(eax, factory->termination_exception());
Label throw_termination_exception;
__ j(equal, &throw_termination_exception);
@@ -3975,7 +4058,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ bind(&failure);
// For failure to match, return null.
- __ mov(Operand(eax), Factory::null_value());
+ __ mov(Operand(eax), factory->null_value());
__ ret(4 * kPointerSize);
// Load RegExp data.
@@ -4011,7 +4094,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Get the static offsets vector filled by the native regexp code.
ExternalReference address_of_static_offsets_vector =
- ExternalReference::address_of_static_offsets_vector();
+ ExternalReference::address_of_static_offsets_vector(masm->isolate());
__ mov(ecx, Immediate(address_of_static_offsets_vector));
// ebx: last_match_info backing store (FixedArray)
@@ -4076,7 +4159,8 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
// Set elements to point to FixedArray allocated right after the JSArray.
// Interleave operations for better latency.
__ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX));
- __ mov(ecx, Immediate(Factory::empty_fixed_array()));
+ Factory* factory = masm->isolate()->factory();
+ __ mov(ecx, Immediate(factory->empty_fixed_array()));
__ lea(ebx, Operand(eax, JSRegExpResult::kSize));
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset));
__ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx);
@@ -4099,12 +4183,12 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
// Set map.
__ mov(FieldOperand(ebx, HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(factory->fixed_array_map()));
// Set length.
__ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx);
// Fill contents of fixed-array with the-hole.
__ SmiUntag(ecx);
- __ mov(edx, Immediate(Factory::the_hole_value()));
+ __ mov(edx, Immediate(factory->the_hole_value()));
__ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize));
// Fill fixed array elements with hole.
// eax: JSArray.
@@ -4140,7 +4224,8 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
Register scratch = scratch2;
// Load the number string cache.
- ExternalReference roots_address = ExternalReference::roots_address();
+ ExternalReference roots_address =
+ ExternalReference::roots_address(masm->isolate());
__ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex));
__ mov(number_string_cache,
Operand::StaticArray(scratch, times_pointer_size, roots_address));
@@ -4169,7 +4254,7 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
__ jmp(&smi_hash_calculated);
__ bind(&not_smi);
__ cmp(FieldOperand(object, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ masm->isolate()->factory()->heap_number_map());
__ j(not_equal, not_found);
STATIC_ASSERT(8 == kDoubleSize);
__ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset));
@@ -4185,7 +4270,7 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
FixedArray::kHeaderSize));
__ test(probe, Immediate(kSmiTagMask));
__ j(zero, not_found);
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope fscope(SSE2);
__ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
__ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset));
@@ -4219,7 +4304,8 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
index,
times_twice_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
- __ IncrementCounter(&Counters::number_to_string_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->number_to_string_native(), 1);
}
@@ -4285,14 +4371,14 @@ void CompareStub::Generate(MacroAssembler* masm) {
// Check for undefined. undefined OP undefined is false even though
// undefined == undefined.
NearLabel check_for_nan;
- __ cmp(edx, Factory::undefined_value());
+ __ cmp(edx, masm->isolate()->factory()->undefined_value());
__ j(not_equal, &check_for_nan);
__ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
__ ret(0);
__ bind(&check_for_nan);
}
- // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
+ // Test for NaN. Sadly, we can't just compare to factory->nan_value(),
// so we do the second best thing - test it ourselves.
// Note: if cc_ != equal, never_nan_nan_ is not used.
if (never_nan_nan_ && (cc_ == equal)) {
@@ -4301,7 +4387,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
} else {
NearLabel heap_number;
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
- Immediate(Factory::heap_number_map()));
+ Immediate(masm->isolate()->factory()->heap_number_map()));
__ j(equal, &heap_number);
if (cc_ != equal) {
// Call runtime on identical JSObjects. Otherwise return equal.
@@ -4378,7 +4464,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
// Check if the non-smi operand is a heap number.
__ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
- Immediate(Factory::heap_number_map()));
+ Immediate(masm->isolate()->factory()->heap_number_map()));
// If heap number, handle it in the slow case.
__ j(equal, &slow);
// Return non-equal (ebx is not zero)
@@ -4423,7 +4509,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
if (include_number_compare_) {
Label non_number_comparison;
Label unordered;
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
CpuFeatures::Scope use_cmov(CMOV);
@@ -4642,11 +4728,17 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ Set(eax, Immediate(argc_));
__ Set(ebx, Immediate(0));
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
- Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
+ Handle<Code> adaptor =
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
__ jmp(adaptor, RelocInfo::CODE_TARGET);
}
+bool CEntryStub::NeedsImmovableCode() {
+ return false;
+}
+
+
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
__ Throw(eax);
}
@@ -4683,7 +4775,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
}
ExternalReference scope_depth =
- ExternalReference::heap_always_allocate_scope_depth();
+ ExternalReference::heap_always_allocate_scope_depth(masm->isolate());
if (always_allocate_scope) {
__ inc(Operand::StaticVariable(scope_depth));
}
@@ -4691,6 +4783,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
// Call C function.
__ mov(Operand(esp, 0 * kPointerSize), edi); // argc.
__ mov(Operand(esp, 1 * kPointerSize), esi); // argv.
+ __ mov(Operand(esp, 2 * kPointerSize),
+ Immediate(ExternalReference::isolate_address()));
__ call(Operand(ebx));
// Result is in eax or edx:eax - do not destroy these registers!
@@ -4702,7 +4796,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
// call as this may lead to crashes in the IC code later.
if (FLAG_debug_code) {
NearLabel okay;
- __ cmp(eax, Factory::the_hole_value());
+ __ cmp(eax, masm->isolate()->factory()->the_hole_value());
__ j(not_equal, &okay);
__ int3();
__ bind(&okay);
@@ -4716,14 +4810,15 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ test(ecx, Immediate(kFailureTagMask));
__ j(zero, &failure_returned, not_taken);
- ExternalReference pending_exception_address(Top::k_pending_exception_address);
+ ExternalReference pending_exception_address(
+ Isolate::k_pending_exception_address, masm->isolate());
// Check that there is no pending exception, otherwise we
// should have returned some failure value.
if (FLAG_debug_code) {
__ push(edx);
__ mov(edx, Operand::StaticVariable(
- ExternalReference::the_hole_value_location()));
+ ExternalReference::the_hole_value_location(masm->isolate())));
NearLabel okay;
__ cmp(edx, Operand::StaticVariable(pending_exception_address));
// Cannot use check here as it attempts to generate call into runtime.
@@ -4751,14 +4846,15 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ j(equal, throw_out_of_memory_exception);
// Retrieve the pending exception and clear the variable.
+ ExternalReference the_hole_location =
+ ExternalReference::the_hole_value_location(masm->isolate());
__ mov(eax, Operand::StaticVariable(pending_exception_address));
- __ mov(edx,
- Operand::StaticVariable(ExternalReference::the_hole_value_location()));
+ __ mov(edx, Operand::StaticVariable(the_hole_location));
__ mov(Operand::StaticVariable(pending_exception_address), edx);
// Special handling of termination exceptions which are uncatchable
// by javascript code.
- __ cmp(eax, Factory::termination_exception());
+ __ cmp(eax, masm->isolate()->factory()->termination_exception());
__ j(equal, throw_termination_exception);
// Handle normal exception.
@@ -4858,12 +4954,13 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
__ push(ebx);
// Save copies of the top frame descriptor on the stack.
- ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
+ ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, masm->isolate());
__ push(Operand::StaticVariable(c_entry_fp));
#ifdef ENABLE_LOGGING_AND_PROFILING
// If this is the outermost JS call, set js_entry_sp value.
- ExternalReference js_entry_sp(Top::k_js_entry_sp_address);
+ ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address,
+ masm->isolate());
__ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
__ j(not_equal, &not_outermost_js);
__ mov(Operand::StaticVariable(js_entry_sp), ebp);
@@ -4875,7 +4972,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Caught exception: Store result (exception) in the pending
// exception field in the JSEnv and return a failure sentinel.
- ExternalReference pending_exception(Top::k_pending_exception_address);
+ ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ masm->isolate());
__ mov(Operand::StaticVariable(pending_exception), eax);
__ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
__ jmp(&exit);
@@ -4885,8 +4983,9 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
__ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
// Clear any pending exceptions.
- __ mov(edx,
- Operand::StaticVariable(ExternalReference::the_hole_value_location()));
+ ExternalReference the_hole_location =
+ ExternalReference::the_hole_value_location(masm->isolate());
+ __ mov(edx, Operand::StaticVariable(the_hole_location));
__ mov(Operand::StaticVariable(pending_exception), edx);
// Fake a receiver (NULL).
@@ -4897,10 +4996,13 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// cannot store a reference to the trampoline code directly in this
// stub, because the builtin stubs may not have been generated yet.
if (is_construct) {
- ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
+ ExternalReference construct_entry(
+ Builtins::kJSConstructEntryTrampoline,
+ masm->isolate());
__ mov(edx, Immediate(construct_entry));
} else {
- ExternalReference entry(Builtins::JSEntryTrampoline);
+ ExternalReference entry(Builtins::kJSEntryTrampoline,
+ masm->isolate());
__ mov(edx, Immediate(entry));
}
__ mov(edx, Operand(edx, 0)); // deref address
@@ -4908,7 +5010,9 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
__ call(Operand(edx));
// Unlink this frame from the handler chain.
- __ pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
+ __ pop(Operand::StaticVariable(ExternalReference(
+ Isolate::k_handler_address,
+ masm->isolate())));
// Pop next_sp.
__ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
@@ -4923,7 +5027,9 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Restore the top frame descriptor from the stack.
__ bind(&exit);
- __ pop(Operand::StaticVariable(ExternalReference(Top::k_c_entry_fp_address)));
+ __ pop(Operand::StaticVariable(ExternalReference(
+ Isolate::k_c_entry_fp_address,
+ masm->isolate())));
// Restore callee-saved registers (C calling conventions).
__ pop(ebx);
@@ -4972,7 +5078,8 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
static const int8_t kCmpEdiImmediateByte2 = BitCast<int8_t, uint8_t>(0xff);
static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8);
- ExternalReference roots_address = ExternalReference::roots_address();
+ ExternalReference roots_address =
+ ExternalReference::roots_address(masm->isolate());
ASSERT_EQ(object.code(), InstanceofStub::left().code());
ASSERT_EQ(function.code(), InstanceofStub::right().code());
@@ -5048,7 +5155,8 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ bind(&loop);
__ cmp(scratch, Operand(prototype));
__ j(equal, &is_instance);
- __ cmp(Operand(scratch), Immediate(Factory::null_value()));
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(Operand(scratch), Immediate(factory->null_value()));
__ j(equal, &is_not_instance);
__ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
__ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
@@ -5062,7 +5170,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
times_pointer_size, roots_address), eax);
} else {
// Get return address and delta to inlined map check.
- __ mov(eax, Factory::true_value());
+ __ mov(eax, factory->true_value());
__ mov(scratch, Operand(esp, 0 * kPointerSize));
__ sub(scratch, Operand(esp, 1 * kPointerSize));
if (FLAG_debug_code) {
@@ -5084,7 +5192,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
scratch, times_pointer_size, roots_address), eax);
} else {
// Get return address and delta to inlined map check.
- __ mov(eax, Factory::false_value());
+ __ mov(eax, factory->false_value());
__ mov(scratch, Operand(esp, 0 * kPointerSize));
__ sub(scratch, Operand(esp, 1 * kPointerSize));
if (FLAG_debug_code) {
@@ -5108,7 +5216,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ j(not_equal, &slow, not_taken);
// Null is not instance of anything.
- __ cmp(object, Factory::null_value());
+ __ cmp(object, factory->null_value());
__ j(not_equal, &object_not_null);
__ Set(eax, Immediate(Smi::FromInt(1)));
__ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
@@ -5149,10 +5257,10 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
NearLabel true_value, done;
__ test(eax, Operand(eax));
__ j(zero, &true_value);
- __ mov(eax, Factory::false_value());
+ __ mov(eax, factory->false_value());
__ jmp(&done);
__ bind(&true_value);
- __ mov(eax, Factory::true_value());
+ __ mov(eax, factory->true_value());
__ bind(&done);
__ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
}
@@ -5187,7 +5295,8 @@ const char* CompareStub::GetName() {
if (name_ != NULL) return name_;
const int kMaxNameLength = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
+ kMaxNameLength);
if (name_ == NULL) return "OOM";
const char* cc_name;
@@ -5280,7 +5389,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// the case we would rather go to the runtime system now to flatten
// the string.
__ cmp(FieldOperand(object_, ConsString::kSecondOffset),
- Immediate(Factory::empty_string()));
+ Immediate(masm->isolate()->factory()->empty_string()));
__ j(not_equal, &call_runtime_);
// Get the first of the two strings and load its instance type.
__ mov(object_, FieldOperand(object_, ConsString::kFirstOffset));
@@ -5325,7 +5434,10 @@ void StringCharCodeAtGenerator::GenerateSlow(
// Index is not a smi.
__ bind(&index_not_smi_);
// If index is a heap number, try converting it to an integer.
- __ CheckMap(index_, Factory::heap_number_map(), index_not_number_, true);
+ __ CheckMap(index_,
+ masm->isolate()->factory()->heap_number_map(),
+ index_not_number_,
+ true);
call_helper.BeforeCall(masm);
__ push(object_);
__ push(index_);
@@ -5386,7 +5498,8 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
((~String::kMaxAsciiCharCode) << kSmiTagSize)));
__ j(not_zero, &slow_case_, not_taken);
- __ Set(result_, Immediate(Factory::single_character_string_cache()));
+ Factory* factory = masm->isolate()->factory();
+ __ Set(result_, Immediate(factory->single_character_string_cache()));
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiTagSize == 1);
STATIC_ASSERT(kSmiShiftSize == 0);
@@ -5394,7 +5507,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
__ mov(result_, FieldOperand(result_,
code_, times_half_pointer_size,
FixedArray::kHeaderSize));
- __ cmp(result_, Factory::undefined_value());
+ __ cmp(result_, factory->undefined_value());
__ j(equal, &slow_case_, not_taken);
__ bind(&exit_);
}
@@ -5480,7 +5593,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ test(ecx, Operand(ecx));
__ j(not_zero, &second_not_zero_length);
// Second string is empty, result is first string which is already in eax.
- __ IncrementCounter(&Counters::string_add_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
__ bind(&second_not_zero_length);
__ mov(ebx, FieldOperand(eax, String::kLengthOffset));
@@ -5489,7 +5603,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ j(not_zero, &both_not_zero_length);
// First string is empty, result is second string which is in edx.
__ mov(eax, edx);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
// Both strings are non-empty.
@@ -5504,8 +5618,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength);
// Handle exceptionally long strings in the runtime system.
__ j(overflow, &string_add_runtime);
- // Use the runtime system when adding two one character strings, as it
- // contains optimizations for this specific case using the symbol table.
+ // Use the symbol table when adding two one character strings, as it
+ // helps later optimizations to return a symbol here.
__ cmp(Operand(ebx), Immediate(Smi::FromInt(2)));
__ j(not_equal, &longer_than_two);
@@ -5523,7 +5637,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, ebx, ecx, eax, edx, edi,
&make_two_character_string_no_reload, &make_two_character_string);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
// Allocate a two character string.
@@ -5535,7 +5649,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
__ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
__ bind(&make_two_character_string_no_reload);
- __ IncrementCounter(&Counters::string_add_make_two_char, 1);
+ __ IncrementCounter(counters->string_add_make_two_char(), 1);
__ AllocateAsciiString(eax, // Result.
2, // Length.
edi, // Scratch 1.
@@ -5546,7 +5660,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ or_(ebx, Operand(ecx));
// Set the characters in the new string.
__ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
__ bind(&longer_than_two);
@@ -5577,7 +5691,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax);
__ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx);
__ mov(eax, ecx);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
__ bind(&non_ascii);
// At least one of the strings is two-byte. Check whether it happens
@@ -5654,7 +5768,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// edx: first char of second argument
// edi: length of second argument
StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
// Handle creating a flat two byte result.
@@ -5695,7 +5809,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// edx: first char of second argument
// edi: length of second argument
StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
// Just jump to runtime to add the two strings.
@@ -5880,7 +5994,8 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
// Load the symbol table.
Register symbol_table = c2;
- ExternalReference roots_address = ExternalReference::roots_address();
+ ExternalReference roots_address =
+ ExternalReference::roots_address(masm->isolate());
__ mov(scratch, Immediate(Heap::kSymbolTableRootIndex));
__ mov(symbol_table,
Operand::StaticArray(scratch, times_pointer_size, roots_address));
@@ -5920,8 +6035,11 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
SymbolTable::kElementsStartOffset));
// If entry is undefined no string with this hash can be found.
- __ cmp(candidate, Factory::undefined_value());
+ Factory* factory = masm->isolate()->factory();
+ __ cmp(candidate, factory->undefined_value());
__ j(equal, not_found);
+ __ cmp(candidate, factory->null_value());
+ __ j(equal, &next_probe[i]);
// If length is not 2 the string is not a candidate.
__ cmp(FieldOperand(candidate, String::kLengthOffset),
@@ -6117,7 +6235,8 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// esi: character of sub string start
StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true);
__ mov(esi, edx); // Restore esi.
- __ IncrementCounter(&Counters::sub_string_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->sub_string_native(), 1);
__ ret(3 * kPointerSize);
__ bind(&non_ascii_flat);
@@ -6158,7 +6277,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ mov(esi, edx); // Restore esi.
__ bind(&return_eax);
- __ IncrementCounter(&Counters::sub_string_native, 1);
+ __ IncrementCounter(counters->sub_string_native(), 1);
__ ret(3 * kPointerSize);
// Just jump to runtime to create the sub string.
@@ -6177,7 +6296,8 @@ void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
Label result_greater;
Label compare_lengths;
- __ IncrementCounter(&Counters::string_compare_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->string_compare_native(), 1);
// Find minimum length.
NearLabel left_shorter;
@@ -6268,7 +6388,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
STATIC_ASSERT(EQUAL == 0);
STATIC_ASSERT(kSmiTag == 0);
__ Set(eax, Immediate(Smi::FromInt(EQUAL)));
- __ IncrementCounter(&Counters::string_compare_native, 1);
+ __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1);
__ ret(2 * kPointerSize);
__ bind(&not_same);
@@ -6290,59 +6410,6 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
}
-void StringCharAtStub::Generate(MacroAssembler* masm) {
- // Expects two arguments (object, index) on the stack:
-
- // Stack frame on entry.
- // esp[0]: return address
- // esp[4]: index
- // esp[8]: object
-
- Register object = ebx;
- Register index = eax;
- Register scratch1 = ecx;
- Register scratch2 = edx;
- Register result = eax;
-
- __ pop(scratch1); // Return address.
- __ pop(index);
- __ pop(object);
- __ push(scratch1);
-
- Label need_conversion;
- Label index_out_of_range;
- Label done;
- StringCharAtGenerator generator(object,
- index,
- scratch1,
- scratch2,
- result,
- &need_conversion,
- &need_conversion,
- &index_out_of_range,
- STRING_INDEX_IS_NUMBER);
- generator.GenerateFast(masm);
- __ jmp(&done);
-
- __ bind(&index_out_of_range);
- // When the index is out of range, the spec requires us to return
- // the empty string.
- __ Set(result, Immediate(Factory::empty_string()));
- __ jmp(&done);
-
- __ bind(&need_conversion);
- // Move smi zero into the result register, which will trigger
- // conversion.
- __ Set(result, Immediate(Smi::FromInt(0)));
- __ jmp(&done);
-
- StubRuntimeCallHelper call_helper;
- generator.GenerateSlow(masm, call_helper);
-
- __ bind(&done);
- __ ret(0);
-}
-
void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
ASSERT(state_ == CompareIC::SMIS);
NearLabel miss;
@@ -6388,7 +6455,8 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
// Inlining the double comparison and falling back to the general compare
// stub if NaN is involved or SS2 or CMOV is unsupported.
- if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) {
+ CpuFeatures* cpu_features = masm->isolate()->cpu_features();
+ if (cpu_features->IsSupported(SSE2) && cpu_features->IsSupported(CMOV)) {
CpuFeatures::Scope scope1(SSE2);
CpuFeatures::Scope scope2(CMOV);
@@ -6453,7 +6521,8 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
__ push(ecx);
// Call the runtime system in a fresh internal frame.
- ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss));
+ ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
+ masm->isolate());
__ EnterInternalFrame();
__ push(edx);
__ push(eax);
@@ -6475,148 +6544,6 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
}
-// Loads a indexed element from a pixel array.
-void GenerateFastPixelArrayLoad(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register elements,
- Register untagged_key,
- Register result,
- Label* not_pixel_array,
- Label* key_not_smi,
- Label* out_of_range) {
- // Register use:
- // receiver - holds the receiver and is unchanged.
- // key - holds the key and is unchanged (must be a smi).
- // elements - is set to the the receiver's element if
- // the receiver doesn't have a pixel array or the
- // key is not a smi, otherwise it's the elements'
- // external pointer.
- // untagged_key - is set to the untagged key
-
- // Some callers already have verified that the key is a smi. key_not_smi is
- // set to NULL as a sentinel for that case. Otherwise, add an explicit check
- // to ensure the key is a smi must be added.
- if (key_not_smi != NULL) {
- __ JumpIfNotSmi(key, key_not_smi);
- } else {
- if (FLAG_debug_code) {
- __ AbortIfNotSmi(key);
- }
- }
- __ mov(untagged_key, key);
- __ SmiUntag(untagged_key);
-
- __ mov(elements, FieldOperand(receiver, JSObject::kElementsOffset));
- // By passing NULL as not_pixel_array, callers signal that they have already
- // verified that the receiver has pixel array elements.
- if (not_pixel_array != NULL) {
- __ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
- } else {
- if (FLAG_debug_code) {
- // Map check should have already made sure that elements is a pixel array.
- __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
- Immediate(Factory::pixel_array_map()));
- __ Assert(equal, "Elements isn't a pixel array");
- }
- }
-
- // Key must be in range.
- __ cmp(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
- __ j(above_equal, out_of_range); // unsigned check handles negative keys.
-
- // Perform the indexed load and tag the result as a smi.
- __ mov(elements, FieldOperand(elements, PixelArray::kExternalPointerOffset));
- __ movzx_b(result, Operand(elements, untagged_key, times_1, 0));
- __ SmiTag(result);
- __ ret(0);
-}
-
-
-// Stores an indexed element into a pixel array, clamping the stored value.
-void GenerateFastPixelArrayStore(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register value,
- Register elements,
- Register scratch1,
- bool load_elements_from_receiver,
- Label* key_not_smi,
- Label* value_not_smi,
- Label* not_pixel_array,
- Label* out_of_range) {
- // Register use:
- // receiver - holds the receiver and is unchanged unless the
- // store succeeds.
- // key - holds the key (must be a smi) and is unchanged.
- // value - holds the value (must be a smi) and is unchanged.
- // elements - holds the element object of the receiver on entry if
- // load_elements_from_receiver is false, otherwise used
- // internally to store the pixel arrays elements and
- // external array pointer.
- //
- // receiver, key and value remain unmodified until it's guaranteed that the
- // store will succeed.
- Register external_pointer = elements;
- Register untagged_key = scratch1;
- Register untagged_value = receiver; // Only set once success guaranteed.
-
- // Fetch the receiver's elements if the caller hasn't already done so.
- if (load_elements_from_receiver) {
- __ mov(elements, FieldOperand(receiver, JSObject::kElementsOffset));
- }
-
- // By passing NULL as not_pixel_array, callers signal that they have already
- // verified that the receiver has pixel array elements.
- if (not_pixel_array != NULL) {
- __ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
- } else {
- if (FLAG_debug_code) {
- // Map check should have already made sure that elements is a pixel array.
- __ cmp(FieldOperand(elements, HeapObject::kMapOffset),
- Immediate(Factory::pixel_array_map()));
- __ Assert(equal, "Elements isn't a pixel array");
- }
- }
-
- // Some callers already have verified that the key is a smi. key_not_smi is
- // set to NULL as a sentinel for that case. Otherwise, add an explicit check
- // to ensure the key is a smi must be added.
- if (key_not_smi != NULL) {
- __ JumpIfNotSmi(key, key_not_smi);
- } else {
- if (FLAG_debug_code) {
- __ AbortIfNotSmi(key);
- }
- }
-
- // Key must be a smi and it must be in range.
- __ mov(untagged_key, key);
- __ SmiUntag(untagged_key);
- __ cmp(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
- __ j(above_equal, out_of_range); // unsigned check handles negative keys.
-
- // Value must be a smi.
- __ JumpIfNotSmi(value, value_not_smi);
- __ mov(untagged_value, value);
- __ SmiUntag(untagged_value);
-
- { // Clamp the value to [0..255].
- NearLabel done;
- __ test(untagged_value, Immediate(0xFFFFFF00));
- __ j(zero, &done);
- __ setcc(negative, untagged_value); // 1 if negative, 0 if positive.
- __ dec_b(untagged_value); // 0 if negative, 255 if positive.
- __ bind(&done);
- }
-
- __ mov(external_pointer,
- FieldOperand(elements, PixelArray::kExternalPointerOffset));
- __ mov_b(Operand(external_pointer, untagged_key, times_1, 0), untagged_value);
- __ ret(0); // Return value in eax.
-}
-
-
#undef __
} } // namespace v8::internal
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h
index 4a1119ab..31fa6451 100644
--- a/src/ia32/code-stubs-ia32.h
+++ b/src/ia32/code-stubs-ia32.h
@@ -96,7 +96,7 @@ class GenericBinaryOpStub: public CodeStub {
if (static_operands_type_.IsSmi()) {
mode_ = NO_OVERWRITE;
}
- use_sse3_ = CpuFeatures::IsSupported(SSE3);
+ use_sse3_ = Isolate::Current()->cpu_features()->IsSupported(SSE3);
ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
}
@@ -235,7 +235,7 @@ class TypeRecordingBinaryOpStub: public CodeStub {
operands_type_(TRBinaryOpIC::UNINITIALIZED),
result_type_(TRBinaryOpIC::UNINITIALIZED),
name_(NULL) {
- use_sse3_ = CpuFeatures::IsSupported(SSE3);
+ use_sse3_ = Isolate::Current()->cpu_features()->IsSupported(SSE3);
ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
}
@@ -306,6 +306,7 @@ class TypeRecordingBinaryOpStub: public CodeStub {
void GenerateSmiStub(MacroAssembler* masm);
void GenerateInt32Stub(MacroAssembler* masm);
void GenerateHeapNumberStub(MacroAssembler* masm);
+ void GenerateOddballStub(MacroAssembler* masm);
void GenerateStringStub(MacroAssembler* masm);
void GenerateGenericStub(MacroAssembler* masm);
void GenerateAddStrings(MacroAssembler* masm);
@@ -489,48 +490,6 @@ class NumberToStringStub: public CodeStub {
#endif
};
-
-// Generate code to load an element from a pixel array. The receiver is assumed
-// to not be a smi and to have elements, the caller must guarantee this
-// precondition. If key is not a smi, then the generated code branches to
-// key_not_smi. Callers can specify NULL for key_not_smi to signal that a smi
-// check has already been performed on key so that the smi check is not
-// generated. If key is not a valid index within the bounds of the pixel array,
-// the generated code jumps to out_of_range. receiver, key and elements are
-// unchanged throughout the generated code sequence.
-void GenerateFastPixelArrayLoad(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register elements,
- Register untagged_key,
- Register result,
- Label* not_pixel_array,
- Label* key_not_smi,
- Label* out_of_range);
-
-// Generate code to store an element into a pixel array, clamping values between
-// [0..255]. The receiver is assumed to not be a smi and to have elements, the
-// caller must guarantee this precondition. If key is not a smi, then the
-// generated code branches to key_not_smi. Callers can specify NULL for
-// key_not_smi to signal that a smi check has already been performed on key so
-// that the smi check is not generated. If the value is not a smi, the generated
-// code will branch to value_not_smi. If the receiver doesn't have pixel array
-// elements, the generated code will branch to not_pixel_array, unless
-// not_pixel_array is NULL, in which case the caller must ensure that the
-// receiver has pixel array elements. If key is not a valid index within the
-// bounds of the pixel array, the generated code jumps to out_of_range.
-void GenerateFastPixelArrayStore(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register value,
- Register elements,
- Register scratch1,
- bool load_elements_from_receiver,
- Label* key_not_smi,
- Label* value_not_smi,
- Label* not_pixel_array,
- Label* out_of_range);
-
} } // namespace v8::internal
#endif // V8_IA32_CODE_STUBS_IA32_H_
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 3a2753d2..cf990a00 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -154,7 +154,8 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm)
safe_int32_mode_enabled_(true),
function_return_is_shadowed_(false),
in_spilled_code_(false),
- jit_cookie_((FLAG_mask_constants_with_cookie) ? V8::RandomPrivate() : 0) {
+ jit_cookie_((FLAG_mask_constants_with_cookie) ?
+ V8::RandomPrivate(Isolate::Current()) : 0) {
}
@@ -182,7 +183,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
ASSERT_EQ(0, loop_nesting_);
loop_nesting_ = info->is_in_loop() ? 1 : 0;
- JumpTarget::set_compiling_deferred_code(false);
+ masm()->isolate()->set_jump_target_compiling_deferred_code(false);
{
CodeGenState state(this);
@@ -284,7 +285,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Initialize ThisFunction reference if present.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- frame_->Push(Factory::the_hole_value());
+ frame_->Push(FACTORY->the_hole_value());
StoreToSlot(scope()->function()->AsSlot(), NOT_CONST_INIT);
}
@@ -320,7 +321,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
if (!scope()->HasIllegalRedeclaration()) {
Comment cmnt(masm_, "[ function body");
#ifdef DEBUG
- bool is_builtin = Bootstrapper::IsActive();
+ bool is_builtin = info->isolate()->bootstrapper()->IsActive();
bool should_trace =
is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
if (should_trace) {
@@ -337,7 +338,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
ASSERT(!function_return_is_shadowed_);
CodeForReturnPosition(info->function());
frame_->PrepareForReturn();
- Result undefined(Factory::undefined_value());
+ Result undefined(FACTORY->undefined_value());
if (function_return_.is_bound()) {
function_return_.Jump(&undefined);
} else {
@@ -369,9 +370,9 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Process any deferred code using the register allocator.
if (!HasStackOverflow()) {
- JumpTarget::set_compiling_deferred_code(true);
+ info->isolate()->set_jump_target_compiling_deferred_code(true);
ProcessDeferred();
- JumpTarget::set_compiling_deferred_code(false);
+ info->isolate()->set_jump_target_compiling_deferred_code(false);
}
// There is no need to delete the register allocator, it is a
@@ -555,7 +556,7 @@ void CodeGenerator::ConvertInt32ResultToNumber(Result* value) {
__ sar(val, 1);
// If there was an overflow, bits 30 and 31 of the original number disagree.
__ xor_(val, 0x80000000u);
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope fscope(SSE2);
__ cvtsi2sd(xmm0, Operand(val));
} else {
@@ -573,7 +574,7 @@ void CodeGenerator::ConvertInt32ResultToNumber(Result* value) {
no_reg, &allocation_failed);
VirtualFrame* clone = new VirtualFrame(frame_);
scratch.Unuse();
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope fscope(SSE2);
__ movdbl(FieldOperand(val, HeapNumber::kValueOffset), xmm0);
} else {
@@ -586,7 +587,7 @@ void CodeGenerator::ConvertInt32ResultToNumber(Result* value) {
RegisterFile empty_regs;
SetFrame(clone, &empty_regs);
__ bind(&allocation_failed);
- if (!CpuFeatures::IsSupported(SSE2)) {
+ if (!masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
// Pop the value from the floating point stack.
__ fstp(0);
}
@@ -613,7 +614,7 @@ void CodeGenerator::Load(Expression* expr) {
safe_int32_mode_enabled() &&
expr->side_effect_free() &&
expr->num_bit_ops() > 2 &&
- CpuFeatures::IsSupported(SSE2)) {
+ masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
BreakTarget unsafe_bailout;
JumpTarget done;
unsafe_bailout.set_expected_height(frame_->height());
@@ -634,12 +635,12 @@ void CodeGenerator::Load(Expression* expr) {
if (dest.false_was_fall_through()) {
// The false target was just bound.
JumpTarget loaded;
- frame_->Push(Factory::false_value());
+ frame_->Push(FACTORY->false_value());
// There may be dangling jumps to the true target.
if (true_target.is_linked()) {
loaded.Jump();
true_target.Bind();
- frame_->Push(Factory::true_value());
+ frame_->Push(FACTORY->true_value());
loaded.Bind();
}
@@ -647,11 +648,11 @@ void CodeGenerator::Load(Expression* expr) {
// There is true, and possibly false, control flow (with true as
// the fall through).
JumpTarget loaded;
- frame_->Push(Factory::true_value());
+ frame_->Push(FACTORY->true_value());
if (false_target.is_linked()) {
loaded.Jump();
false_target.Bind();
- frame_->Push(Factory::false_value());
+ frame_->Push(FACTORY->false_value());
loaded.Bind();
}
@@ -666,14 +667,14 @@ void CodeGenerator::Load(Expression* expr) {
loaded.Jump(); // Don't lose the current TOS.
if (true_target.is_linked()) {
true_target.Bind();
- frame_->Push(Factory::true_value());
+ frame_->Push(FACTORY->true_value());
if (false_target.is_linked()) {
loaded.Jump();
}
}
if (false_target.is_linked()) {
false_target.Bind();
- frame_->Push(Factory::false_value());
+ frame_->Push(FACTORY->false_value());
}
loaded.Bind();
}
@@ -729,11 +730,14 @@ void CodeGenerator::LoadTypeofExpression(Expression* expr) {
ArgumentsAllocationMode CodeGenerator::ArgumentsMode() {
if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION;
- ASSERT(scope()->arguments_shadow() != NULL);
+
+ // In strict mode there is no need for shadow arguments.
+ ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode());
+
// We don't want to do lazy arguments allocation for functions that
// have heap-allocated contexts, because it interfers with the
// uninitialized const tracking in the context objects.
- return (scope()->num_heap_slots() > 0)
+ return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode())
? EAGER_ARGUMENTS_ALLOCATION
: LAZY_ARGUMENTS_ALLOCATION;
}
@@ -748,9 +752,11 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) {
// When using lazy arguments allocation, we store the arguments marker value
// as a sentinel indicating that the arguments object hasn't been
// allocated yet.
- frame_->Push(Factory::arguments_marker());
+ frame_->Push(FACTORY->arguments_marker());
} else {
- ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+ ArgumentsAccessStub stub(is_strict_mode()
+ ? ArgumentsAccessStub::NEW_STRICT
+ : ArgumentsAccessStub::NEW_NON_STRICT);
frame_->PushFunction();
frame_->PushReceiverSlotAddress();
frame_->Push(Smi::FromInt(scope()->num_parameters()));
@@ -760,8 +766,11 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) {
Variable* arguments = scope()->arguments();
Variable* shadow = scope()->arguments_shadow();
+
ASSERT(arguments != NULL && arguments->AsSlot() != NULL);
- ASSERT(shadow != NULL && shadow->AsSlot() != NULL);
+ ASSERT((shadow != NULL && shadow->AsSlot() != NULL) ||
+ scope()->is_strict_mode());
+
JumpTarget done;
bool skip_arguments = false;
if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) {
@@ -775,7 +784,7 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) {
// been assigned a proper value.
skip_arguments = !probe.handle()->IsArgumentsMarker();
} else {
- __ cmp(Operand(probe.reg()), Immediate(Factory::arguments_marker()));
+ __ cmp(Operand(probe.reg()), Immediate(FACTORY->arguments_marker()));
probe.Unuse();
done.Branch(not_equal);
}
@@ -784,7 +793,9 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) {
StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT);
if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind();
}
- StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT);
+ if (shadow != NULL) {
+ StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT);
+ }
return frame_->Pop();
}
@@ -904,15 +915,15 @@ void CodeGenerator::ToBoolean(ControlDestination* dest) {
} else {
// Fast case checks.
// 'false' => false.
- __ cmp(value.reg(), Factory::false_value());
+ __ cmp(value.reg(), FACTORY->false_value());
dest->false_target()->Branch(equal);
// 'true' => true.
- __ cmp(value.reg(), Factory::true_value());
+ __ cmp(value.reg(), FACTORY->true_value());
dest->true_target()->Branch(equal);
// 'undefined' => false.
- __ cmp(value.reg(), Factory::undefined_value());
+ __ cmp(value.reg(), FACTORY->undefined_value());
dest->false_target()->Branch(equal);
// Smi => false iff zero.
@@ -983,7 +994,8 @@ class DeferredInlineBinaryOperation: public DeferredCode {
Label* DeferredInlineBinaryOperation::NonSmiInputLabel() {
- if (Token::IsBitOp(op_) && CpuFeatures::IsSupported(SSE2)) {
+ if (Token::IsBitOp(op_) &&
+ masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
return &non_smi_input_;
} else {
return entry_label();
@@ -1006,7 +1018,7 @@ void DeferredInlineBinaryOperation::JumpToConstantRhs(Condition cond,
void DeferredInlineBinaryOperation::Generate() {
// Registers are not saved implicitly for this stub, so we should not
// tread on the registers that were not passed to us.
- if (CpuFeatures::IsSupported(SSE2) &&
+ if (masm()->isolate()->cpu_features()->IsSupported(SSE2) &&
((op_ == Token::ADD) ||
(op_ == Token::SUB) ||
(op_ == Token::MUL) ||
@@ -1019,7 +1031,7 @@ void DeferredInlineBinaryOperation::Generate() {
__ j(zero, &left_smi);
if (!left_info_.IsNumber()) {
__ cmp(FieldOperand(left_, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
__ j(not_equal, &call_runtime);
}
__ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset));
@@ -1048,7 +1060,7 @@ void DeferredInlineBinaryOperation::Generate() {
__ j(zero, &right_smi);
if (!right_info_.IsNumber()) {
__ cmp(FieldOperand(right_, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
__ j(not_equal, &call_runtime);
}
__ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset));
@@ -1142,7 +1154,7 @@ void DeferredInlineBinaryOperation::GenerateNonSmiInput() {
// The left_ and right_ registers have not been initialized yet.
__ mov(right_, Immediate(smi_value_));
__ mov(left_, Operand(dst_));
- if (!CpuFeatures::IsSupported(SSE2)) {
+ if (!masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
__ jmp(entry_label());
return;
} else {
@@ -1255,7 +1267,8 @@ void DeferredInlineBinaryOperation::GenerateAnswerOutOfRange() {
// This trashes right_.
__ AllocateHeapNumber(left_, right_, no_reg, &after_alloc_failure2);
__ bind(&allocation_ok);
- if (CpuFeatures::IsSupported(SSE2) && op_ != Token::SHR) {
+ if (masm()->isolate()->cpu_features()->IsSupported(SSE2) &&
+ op_ != Token::SHR) {
CpuFeatures::Scope use_sse2(SSE2);
ASSERT(Token::IsBitOp(op_));
// Signed conversion.
@@ -1497,7 +1510,7 @@ Result CodeGenerator::GenerateGenericBinaryOpStubCall(GenericBinaryOpStub* stub,
bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) {
- Object* answer_object = Heap::undefined_value();
+ Object* answer_object = HEAP->undefined_value();
switch (op) {
case Token::ADD:
if (Smi::IsValid(left + right)) {
@@ -1569,7 +1582,7 @@ bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) {
UNREACHABLE();
break;
}
- if (answer_object == Heap::undefined_value()) {
+ if (answer_object->IsUndefined()) {
return false;
}
frame_->Push(Handle<Object>(answer_object));
@@ -3018,13 +3031,14 @@ void CodeGenerator::ConstantSmiComparison(Condition cc,
// Jump or fall through to here if we are comparing a non-smi to a
// constant smi. If the non-smi is a heap number and this is not
// a loop condition, inline the floating point code.
- if (!is_loop_condition && CpuFeatures::IsSupported(SSE2)) {
+ if (!is_loop_condition &&
+ masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
// Right side is a constant smi and left side has been checked
// not to be a smi.
CpuFeatures::Scope use_sse2(SSE2);
JumpTarget not_number;
__ cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
- Immediate(Factory::heap_number_map()));
+ Immediate(FACTORY->heap_number_map()));
not_number.Branch(not_equal, left_side);
__ movdbl(xmm1,
FieldOperand(left_reg, HeapNumber::kValueOffset));
@@ -3090,7 +3104,7 @@ static void CheckComparisonOperand(MacroAssembler* masm_,
__ test(operand->reg(), Immediate(kSmiTagMask));
__ j(zero, &done);
__ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset),
- Immediate(Factory::heap_number_map()));
+ Immediate(FACTORY->heap_number_map()));
not_numbers->Branch(not_equal, left_side, right_side, not_taken);
__ bind(&done);
}
@@ -3157,7 +3171,7 @@ static void LoadComparisonOperandSSE2(MacroAssembler* masm_,
__ j(zero, &smi);
if (!operand->type_info().IsNumber()) {
__ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset),
- Immediate(Factory::heap_number_map()));
+ Immediate(FACTORY->heap_number_map()));
not_numbers->Branch(not_equal, left_side, right_side, taken);
}
__ movdbl(xmm_reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset));
@@ -3182,7 +3196,7 @@ void CodeGenerator::GenerateInlineNumberComparison(Result* left_side,
ASSERT(right_side->is_register());
JumpTarget not_numbers;
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
// Load left and right operand into registers xmm0 and xmm1 and compare.
@@ -3264,7 +3278,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
// give us a megamorphic load site. Not super, but it works.
Load(applicand);
frame()->Dup();
- Handle<String> name = Factory::LookupAsciiSymbol("apply");
+ Handle<String> name = FACTORY->LookupAsciiSymbol("apply");
frame()->Push(name);
Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET);
__ nop();
@@ -3296,7 +3310,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
if (probe.is_constant()) {
try_lazy = probe.handle()->IsArgumentsMarker();
} else {
- __ cmp(Operand(probe.reg()), Immediate(Factory::arguments_marker()));
+ __ cmp(Operand(probe.reg()), Immediate(FACTORY->arguments_marker()));
probe.Unuse();
__ j(not_equal, &slow);
}
@@ -3332,7 +3346,8 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
__ j(not_equal, &build_args);
__ mov(ecx, FieldOperand(eax, JSFunction::kCodeEntryOffset));
__ sub(Operand(ecx), Immediate(Code::kHeaderSize - kHeapObjectTag));
- Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply));
+ Handle<Code> apply_code(masm()->isolate()->builtins()->builtin(
+ Builtins::kFunctionApply));
__ cmp(Operand(ecx), Immediate(apply_code));
__ j(not_equal, &build_args);
@@ -3458,7 +3473,7 @@ void DeferredStackCheck::Generate() {
void CodeGenerator::CheckStack() {
DeferredStackCheck* deferred = new DeferredStackCheck;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(masm()->isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
deferred->Branch(below);
deferred->BindExit();
@@ -3559,7 +3574,7 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
// 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value.
if (node->mode() == Variable::CONST) {
- frame_->EmitPush(Immediate(Factory::the_hole_value()));
+ frame_->EmitPush(Immediate(FACTORY->the_hole_value()));
} else if (node->fun() != NULL) {
Load(node->fun());
} else {
@@ -3575,7 +3590,7 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
// If we have a function or a constant, we need to initialize the variable.
Expression* val = NULL;
if (node->mode() == Variable::CONST) {
- val = new Literal(Factory::the_hole_value());
+ val = new Literal(FACTORY->the_hole_value());
} else {
val = node->fun(); // NULL if we don't have a function
}
@@ -4356,9 +4371,9 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
frame_->EmitPop(eax);
// eax: value to be iterated over
- __ cmp(eax, Factory::undefined_value());
+ __ cmp(eax, FACTORY->undefined_value());
exit.Branch(equal);
- __ cmp(eax, Factory::null_value());
+ __ cmp(eax, FACTORY->null_value());
exit.Branch(equal);
// Stack layout in body:
@@ -4397,14 +4412,14 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
loop.Bind();
// Check that there are no elements.
__ mov(edx, FieldOperand(ecx, JSObject::kElementsOffset));
- __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
+ __ cmp(Operand(edx), Immediate(FACTORY->empty_fixed_array()));
call_runtime.Branch(not_equal);
// Check that instance descriptors are not empty so that we can
// check for an enum cache. Leave the map in ebx for the subsequent
// prototype load.
__ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
__ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
- __ cmp(Operand(edx), Immediate(Factory::empty_descriptor_array()));
+ __ cmp(Operand(edx), Immediate(FACTORY->empty_descriptor_array()));
call_runtime.Branch(equal);
// Check that there in an enum cache in the non-empty instance
// descriptors. This is the case if the next enumeration index
@@ -4416,12 +4431,12 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
__ cmp(ecx, Operand(eax));
check_prototype.Branch(equal);
__ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
- __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
+ __ cmp(Operand(edx), Immediate(FACTORY->empty_fixed_array()));
call_runtime.Branch(not_equal);
check_prototype.Bind();
// Load the prototype from the map and loop if non-null.
__ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
- __ cmp(Operand(ecx), Immediate(Factory::null_value()));
+ __ cmp(Operand(ecx), Immediate(FACTORY->null_value()));
loop.Branch(not_equal);
// The enum cache is valid. Load the map of the object being
// iterated over and use the cache for the iteration.
@@ -4440,7 +4455,7 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
// Runtime::kGetPropertyNamesFast)
__ mov(edx, Operand(eax));
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
- __ cmp(ecx, Factory::meta_map());
+ __ cmp(ecx, FACTORY->meta_map());
fixed_array.Branch(not_equal);
use_cache.Bind();
@@ -4632,7 +4647,8 @@ void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
function_return_is_shadowed_ = function_return_was_shadowed;
// Get an external reference to the handler address.
- ExternalReference handler_address(Top::k_handler_address);
+ ExternalReference handler_address(Isolate::k_handler_address,
+ masm()->isolate());
// Make sure that there's nothing left on the stack above the
// handler structure.
@@ -4758,7 +4774,8 @@ void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
function_return_is_shadowed_ = function_return_was_shadowed;
// Get an external reference to the handler address.
- ExternalReference handler_address(Top::k_handler_address);
+ ExternalReference handler_address(Isolate::k_handler_address,
+ masm()->isolate());
// If we can fall off the end of the try block, unlink from the try
// chain and set the state on the frame to FALLING.
@@ -4770,7 +4787,7 @@ void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
// Fake a top of stack value (unneeded when FALLING) and set the
// state in ecx, then jump around the unlink blocks if any.
- frame_->EmitPush(Immediate(Factory::undefined_value()));
+ frame_->EmitPush(Immediate(FACTORY->undefined_value()));
__ Set(ecx, Immediate(Smi::FromInt(FALLING)));
if (nof_unlinks > 0) {
finally_block.Jump();
@@ -4813,7 +4830,7 @@ void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
frame_->EmitPush(eax);
} else {
// Fake TOS for targets that shadowed breaks and continues.
- frame_->EmitPush(Immediate(Factory::undefined_value()));
+ frame_->EmitPush(Immediate(FACTORY->undefined_value()));
}
__ Set(ecx, Immediate(Smi::FromInt(JUMPING + i)));
if (--nof_unlinks > 0) {
@@ -4908,10 +4925,11 @@ Result CodeGenerator::InstantiateFunction(
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
- if (scope()->is_function_scope() &&
- function_info->num_literals() == 0 &&
- !pretenure) {
- FastNewClosureStub stub;
+ if (!pretenure &&
+ scope()->is_function_scope() &&
+ function_info->num_literals() == 0) {
+ FastNewClosureStub stub(
+ function_info->strict_mode() ? kStrictMode : kNonStrictMode);
frame()->EmitPush(Immediate(function_info));
return frame()->CallStub(&stub, 1);
} else {
@@ -4920,8 +4938,8 @@ Result CodeGenerator::InstantiateFunction(
frame()->EmitPush(esi);
frame()->EmitPush(Immediate(function_info));
frame()->EmitPush(Immediate(pretenure
- ? Factory::true_value()
- : Factory::false_value()));
+ ? FACTORY->true_value()
+ : FACTORY->false_value()));
return frame()->CallRuntime(Runtime::kNewClosure, 3);
}
}
@@ -5029,9 +5047,9 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
Comment cmnt(masm_, "[ Load const");
Label exit;
__ mov(ecx, SlotOperand(slot, ecx));
- __ cmp(ecx, Factory::the_hole_value());
+ __ cmp(ecx, FACTORY->the_hole_value());
__ j(not_equal, &exit);
- __ mov(ecx, Factory::undefined_value());
+ __ mov(ecx, FACTORY->undefined_value());
__ bind(&exit);
frame()->EmitPush(ecx);
@@ -5081,7 +5099,7 @@ void CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot,
// indicates that we haven't loaded the arguments object yet, we
// need to do it now.
JumpTarget exit;
- __ cmp(Operand(result.reg()), Immediate(Factory::arguments_marker()));
+ __ cmp(Operand(result.reg()), Immediate(FACTORY->arguments_marker()));
frame()->Push(&result);
exit.Branch(not_equal);
@@ -5135,7 +5153,7 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
__ bind(&next);
// Terminate at global context.
__ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset),
- Immediate(Factory::global_context_map()));
+ Immediate(FACTORY->global_context_map()));
__ j(equal, &fast);
// Check that extension is NULL.
__ cmp(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0));
@@ -5195,9 +5213,9 @@ void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot,
__ mov(result->reg(),
ContextSlotOperandCheckExtensions(potential_slot, *result, slow));
if (potential_slot->var()->mode() == Variable::CONST) {
- __ cmp(result->reg(), Factory::the_hole_value());
+ __ cmp(result->reg(), FACTORY->the_hole_value());
done->Branch(not_equal, result);
- __ mov(result->reg(), Factory::undefined_value());
+ __ mov(result->reg(), FACTORY->undefined_value());
}
done->Jump(result);
} else if (rewrite != NULL) {
@@ -5284,7 +5302,7 @@ void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ Init const");
__ mov(ecx, SlotOperand(slot, ecx));
- __ cmp(ecx, Factory::the_hole_value());
+ __ cmp(ecx, FACTORY->the_hole_value());
exit.Branch(not_equal);
}
@@ -5455,7 +5473,7 @@ class DeferredAllocateInNewSpace: public DeferredCode {
Register target,
int registers_to_save = 0)
: size_(size), target_(target), registers_to_save_(registers_to_save) {
- ASSERT(size >= kPointerSize && size <= Heap::MaxObjectSizeInNewSpace());
+ ASSERT(size >= kPointerSize && size <= HEAP->MaxObjectSizeInNewSpace());
ASSERT_EQ(0, registers_to_save & target.bit());
set_comment("[ DeferredAllocateInNewSpace");
}
@@ -5516,7 +5534,7 @@ void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
// jump to the deferred code passing the literals array.
DeferredRegExpLiteral* deferred =
new DeferredRegExpLiteral(boilerplate.reg(), literals.reg(), node);
- __ cmp(boilerplate.reg(), Factory::undefined_value());
+ __ cmp(boilerplate.reg(), FACTORY->undefined_value());
deferred->Branch(equal);
deferred->BindExit();
@@ -5674,11 +5692,12 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
frame_->Push(node->constant_elements());
int length = node->values()->length();
Result clone;
- if (node->constant_elements()->map() == Heap::fixed_cow_array_map()) {
+ if (node->constant_elements()->map() == HEAP->fixed_cow_array_map()) {
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
clone = frame_->CallStub(&stub, 3);
- __ IncrementCounter(&Counters::cow_arrays_created_stub, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->cow_arrays_created_stub(), 1);
} else if (node->depth() > 1) {
clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
@@ -6081,7 +6100,7 @@ void CodeGenerator::VisitCall(Call* node) {
Load(function);
// Allocate a frame slot for the receiver.
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
// Load the arguments.
int arg_count = args->length();
@@ -6113,7 +6132,7 @@ void CodeGenerator::VisitCall(Call* node) {
if (arg_count > 0) {
frame_->PushElementAt(arg_count);
} else {
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
}
frame_->PushParameterAt(-1);
@@ -6135,7 +6154,7 @@ void CodeGenerator::VisitCall(Call* node) {
if (arg_count > 0) {
frame_->PushElementAt(arg_count);
} else {
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
}
frame_->PushParameterAt(-1);
@@ -6429,7 +6448,7 @@ void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) {
}
#endif
// Finally, we're expected to leave a value on the top of the stack.
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
}
@@ -6472,13 +6491,13 @@ class DeferredStringCharCodeAt : public DeferredCode {
__ bind(&need_conversion_);
// Move the undefined value into the result register, which will
// trigger conversion.
- __ Set(result_, Immediate(Factory::undefined_value()));
+ __ Set(result_, Immediate(FACTORY->undefined_value()));
__ jmp(exit_label());
__ bind(&index_out_of_range_);
// When the index is out of range, the spec requires us to return
// NaN.
- __ Set(result_, Immediate(Factory::nan_value()));
+ __ Set(result_, Immediate(FACTORY->nan_value()));
__ jmp(exit_label());
}
@@ -6601,7 +6620,7 @@ class DeferredStringCharAt : public DeferredCode {
__ bind(&index_out_of_range_);
// When the index is out of range, the spec requires us to return
// the empty string.
- __ Set(result_, Immediate(Factory::empty_string()));
+ __ Set(result_, Immediate(FACTORY->empty_string()));
__ jmp(exit_label());
}
@@ -6719,7 +6738,7 @@ void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
__ sar(array_length, 1);
__ j(not_zero, &non_trivial_array);
- __ mov(result_operand, Factory::empty_string());
+ __ mov(result_operand, FACTORY->empty_string());
__ jmp(&done);
// Save the array length.
@@ -6930,7 +6949,7 @@ void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ bind(&bailout);
- __ mov(result_operand, Factory::undefined_value());
+ __ mov(result_operand, FACTORY->undefined_value());
__ bind(&done);
__ mov(eax, result_operand);
// Drop temp values from the stack, and restore context register.
@@ -6971,7 +6990,7 @@ void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
__ test(obj.reg(), Immediate(kSmiTagMask));
destination()->false_target()->Branch(zero);
- __ cmp(obj.reg(), Factory::null_value());
+ __ cmp(obj.reg(), FACTORY->null_value());
destination()->true_target()->Branch(equal);
Result map = allocator()->Allocate();
@@ -7042,7 +7061,7 @@ class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
// Check for fast case object. Generate false result for slow case object.
__ mov(scratch1_, FieldOperand(object_, JSObject::kPropertiesOffset));
__ mov(scratch1_, FieldOperand(scratch1_, HeapObject::kMapOffset));
- __ cmp(scratch1_, Factory::hash_table_map());
+ __ cmp(scratch1_, FACTORY->hash_table_map());
__ j(equal, &false_result);
// Look for valueOf symbol in the descriptor array, and indicate false if
@@ -7069,7 +7088,7 @@ class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
__ jmp(&entry);
__ bind(&loop);
__ mov(scratch2_, FieldOperand(map_result_, 0));
- __ cmp(scratch2_, Factory::value_of_symbol());
+ __ cmp(scratch2_, FACTORY->value_of_symbol());
__ j(equal, &false_result);
__ add(Operand(map_result_), Immediate(kPointerSize));
__ bind(&entry);
@@ -7284,17 +7303,17 @@ void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
// Functions have class 'Function'.
function.Bind();
- frame_->Push(Factory::function_class_symbol());
+ frame_->Push(FACTORY->function_class_symbol());
leave.Jump();
// Objects with a non-function constructor have class 'Object'.
non_function_constructor.Bind();
- frame_->Push(Factory::Object_symbol());
+ frame_->Push(FACTORY->Object_symbol());
leave.Jump();
// Non-JS objects have class null.
null.Bind();
- frame_->Push(Factory::null_value());
+ frame_->Push(FACTORY->null_value());
// All done.
leave.Bind();
@@ -7430,13 +7449,14 @@ void CodeGenerator::GenerateRandomHeapNumber(
__ bind(&heapnumber_allocated);
__ PrepareCallCFunction(0, ebx);
- __ CallCFunction(ExternalReference::random_uint32_function(), 0);
+ __ CallCFunction(ExternalReference::random_uint32_function(masm()->isolate()),
+ 0);
// Convert 32 random bits in eax to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
// This is implemented on both SSE2 and FPU.
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope fscope(SSE2);
__ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
__ movd(xmm1, Operand(ebx));
@@ -7653,10 +7673,10 @@ void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) {
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
Handle<FixedArray> jsfunction_result_caches(
- Top::global_context()->jsfunction_result_caches());
+ masm()->isolate()->global_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort("Attempt to use undefined cache.");
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
return;
}
@@ -7773,7 +7793,7 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
// Check the object's elements are in fast case and writable.
__ mov(tmp1.reg(), FieldOperand(object.reg(), JSObject::kElementsOffset));
__ cmp(FieldOperand(tmp1.reg(), HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(FACTORY->fixed_array_map()));
deferred->Branch(not_equal);
// Smi-tagging is equivalent to multiplying by 2.
@@ -7814,7 +7834,7 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
__ bind(&done);
deferred->BindExit();
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
}
@@ -7842,7 +7862,7 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
Load(args->at(0));
Load(args->at(1));
- if (!CpuFeatures::IsSupported(SSE2)) {
+ if (!masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
Result res = frame_->CallRuntime(Runtime::kMath_pow, 2);
frame_->Push(&res);
} else {
@@ -7883,7 +7903,7 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
// exponent is smi and base is a heapnumber.
__ bind(&base_nonsmi);
__ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
call_runtime.Branch(not_equal);
__ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset));
@@ -7934,7 +7954,7 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
// on doubles.
__ bind(&exponent_nonsmi);
__ cmp(FieldOperand(exponent.reg(), HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
call_runtime.Branch(not_equal);
__ movdbl(xmm1, FieldOperand(exponent.reg(), HeapNumber::kValueOffset));
// Test if exponent is nan.
@@ -7950,7 +7970,7 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
__ jmp(&handle_special_cases);
__ bind(&base_not_smi);
__ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
call_runtime.Branch(not_equal);
__ mov(answer.reg(), FieldOperand(base.reg(), HeapNumber::kExponentOffset));
__ and_(answer.reg(), HeapNumber::kExponentMask);
@@ -8059,7 +8079,7 @@ void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
Load(args->at(0));
- if (!CpuFeatures::IsSupported(SSE2)) {
+ if (!masm()->isolate()->cpu_features()->IsSupported(SSE2)) {
Result result = frame()->CallRuntime(Runtime::kMath_sqrt, 1);
frame()->Push(&result);
} else {
@@ -8081,7 +8101,7 @@ void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
__ jmp(&load_done);
__ bind(&non_smi);
__ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
__ j(not_equal, &runtime);
__ movdbl(xmm0, FieldOperand(result.reg(), HeapNumber::kValueOffset));
@@ -8187,7 +8207,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments();
Comment cmnt(masm_, "[ CallRuntime");
- Runtime::Function* function = node->function();
+ const Runtime::Function* function = node->function();
if (function == NULL) {
// Push the builtins object found in the current global object.
@@ -8270,12 +8290,12 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
} else {
// Default: Result of deleting non-global, not dynamically
// introduced variables is false.
- frame_->Push(Factory::false_value());
+ frame_->Push(FACTORY->false_value());
}
} else {
// Default: Result of deleting expressions is true.
Load(node->expression()); // may have side-effects
- frame_->SetElementAt(0, Factory::true_value());
+ frame_->SetElementAt(0, FACTORY->true_value());
}
} else if (op == Token::TYPEOF) {
@@ -8296,10 +8316,10 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
expression->AsLiteral()->IsNull())) {
// Omit evaluating the value of the primitive literal.
// It will be discarded anyway, and can have no side effect.
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
} else {
Load(node->expression());
- frame_->SetElementAt(0, Factory::undefined_value());
+ frame_->SetElementAt(0, FACTORY->undefined_value());
}
} else {
@@ -9101,16 +9121,16 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
Result answer = frame_->Pop();
answer.ToRegister();
- if (check->Equals(Heap::number_symbol())) {
+ if (check->Equals(HEAP->number_symbol())) {
__ test(answer.reg(), Immediate(kSmiTagMask));
destination()->true_target()->Branch(zero);
frame_->Spill(answer.reg());
__ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
- __ cmp(answer.reg(), Factory::heap_number_map());
+ __ cmp(answer.reg(), FACTORY->heap_number_map());
answer.Unuse();
destination()->Split(equal);
- } else if (check->Equals(Heap::string_symbol())) {
+ } else if (check->Equals(HEAP->string_symbol())) {
__ test(answer.reg(), Immediate(kSmiTagMask));
destination()->false_target()->Branch(zero);
@@ -9126,15 +9146,15 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
answer.Unuse();
destination()->Split(below);
- } else if (check->Equals(Heap::boolean_symbol())) {
- __ cmp(answer.reg(), Factory::true_value());
+ } else if (check->Equals(HEAP->boolean_symbol())) {
+ __ cmp(answer.reg(), FACTORY->true_value());
destination()->true_target()->Branch(equal);
- __ cmp(answer.reg(), Factory::false_value());
+ __ cmp(answer.reg(), FACTORY->false_value());
answer.Unuse();
destination()->Split(equal);
- } else if (check->Equals(Heap::undefined_symbol())) {
- __ cmp(answer.reg(), Factory::undefined_value());
+ } else if (check->Equals(HEAP->undefined_symbol())) {
+ __ cmp(answer.reg(), FACTORY->undefined_value());
destination()->true_target()->Branch(equal);
__ test(answer.reg(), Immediate(kSmiTagMask));
@@ -9148,7 +9168,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
answer.Unuse();
destination()->Split(not_zero);
- } else if (check->Equals(Heap::function_symbol())) {
+ } else if (check->Equals(HEAP->function_symbol())) {
__ test(answer.reg(), Immediate(kSmiTagMask));
destination()->false_target()->Branch(zero);
frame_->Spill(answer.reg());
@@ -9158,10 +9178,10 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
__ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE);
answer.Unuse();
destination()->Split(equal);
- } else if (check->Equals(Heap::object_symbol())) {
+ } else if (check->Equals(HEAP->object_symbol())) {
__ test(answer.reg(), Immediate(kSmiTagMask));
destination()->false_target()->Branch(zero);
- __ cmp(answer.reg(), Factory::null_value());
+ __ cmp(answer.reg(), FACTORY->null_value());
destination()->true_target()->Branch(equal);
Result map = allocator()->Allocate();
@@ -9204,7 +9224,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
Result scratch = allocator()->Allocate();
ASSERT(scratch.is_valid());
__ mov(scratch.reg(), FieldOperand(lhs.reg(), HeapObject::kMapOffset));
- __ cmp(scratch.reg(), Factory::heap_number_map());
+ __ cmp(scratch.reg(), FACTORY->heap_number_map());
JumpTarget not_a_number;
not_a_number.Branch(not_equal, &lhs);
__ mov(scratch.reg(),
@@ -9291,7 +9311,7 @@ void CodeGenerator::VisitCompareToNull(CompareToNull* node) {
Load(node->expression());
Result operand = frame_->Pop();
operand.ToRegister();
- __ cmp(operand.reg(), Factory::null_value());
+ __ cmp(operand.reg(), FACTORY->null_value());
if (node->is_strict()) {
operand.Unuse();
destination()->Split(equal);
@@ -9299,7 +9319,7 @@ void CodeGenerator::VisitCompareToNull(CompareToNull* node) {
// The 'null' value is only equal to 'undefined' if using non-strict
// comparisons.
destination()->true_target()->Branch(equal);
- __ cmp(operand.reg(), Factory::undefined_value());
+ __ cmp(operand.reg(), FACTORY->undefined_value());
destination()->true_target()->Branch(equal);
__ test(operand.reg(), Immediate(kSmiTagMask));
destination()->false_target()->Branch(equal);
@@ -9372,7 +9392,8 @@ void DeferredReferenceGetNamedValue::Generate() {
__ mov(eax, receiver_);
}
__ Set(ecx, Immediate(name_));
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic(masm()->isolate()->builtins()->builtin(
+ Builtins::kLoadIC_Initialize));
RelocInfo::Mode mode = is_contextual_
? RelocInfo::CODE_TARGET_CONTEXT
: RelocInfo::CODE_TARGET;
@@ -9389,15 +9410,16 @@ void DeferredReferenceGetNamedValue::Generate() {
int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site());
// Here we use masm_-> instead of the __ macro because this is the
// instruction that gets patched and coverage code gets in the way.
+ Counters* counters = masm()->isolate()->counters();
if (is_contextual_) {
masm_->mov(is_dont_delete_ ? edx : ecx, -delta_to_patch_site);
- __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
+ __ IncrementCounter(counters->named_load_global_inline_miss(), 1);
if (is_dont_delete_) {
- __ IncrementCounter(&Counters::dont_delete_hint_miss, 1);
+ __ IncrementCounter(counters->dont_delete_hint_miss(), 1);
}
} else {
masm_->test(eax, Immediate(-delta_to_patch_site));
- __ IncrementCounter(&Counters::named_load_inline_miss, 1);
+ __ IncrementCounter(counters->named_load_inline_miss(), 1);
}
if (!dst_.is(eax)) __ mov(dst_, eax);
@@ -9451,7 +9473,8 @@ void DeferredReferenceGetKeyedValue::Generate() {
// it in the IC initialization code and patch the cmp instruction.
// This means that we cannot allow test instructions after calls to
// KeyedLoadIC stubs in other places.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic(masm()->isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// The delta from the start of the map-compare instruction to the
// test instruction. We use masm_-> directly here instead of the __
@@ -9462,7 +9485,8 @@ void DeferredReferenceGetKeyedValue::Generate() {
// Here we use masm_-> instead of the __ macro because this is the
// instruction that gets patched and coverage code gets in the way.
masm_->test(eax, Immediate(-delta_to_patch_site));
- __ IncrementCounter(&Counters::keyed_load_inline_miss, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_inline_miss(), 1);
if (!dst_.is(eax)) __ mov(dst_, eax);
}
@@ -9498,7 +9522,8 @@ class DeferredReferenceSetKeyedValue: public DeferredCode {
void DeferredReferenceSetKeyedValue::Generate() {
- __ IncrementCounter(&Counters::keyed_store_inline_miss, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->keyed_store_inline_miss(), 1);
// Move value_ to eax, key_ to ecx, and receiver_ to edx.
Register old_value = value_;
@@ -9552,9 +9577,9 @@ void DeferredReferenceSetKeyedValue::Generate() {
}
// Call the IC stub.
- Handle<Code> ic(Builtins::builtin(
- (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic(masm()->isolate()->builtins()->builtin(
+ (strict_mode_ == kStrictMode) ? Builtins::kKeyedStoreIC_Initialize_Strict
+ : Builtins::kKeyedStoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// The delta from the start of the map-compare instruction to the
// test instruction. We use masm_-> directly here instead of the
@@ -9575,9 +9600,13 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
int original_height = frame()->height();
#endif
+ Isolate* isolate = masm()->isolate();
+ Factory* factory = isolate->factory();
+ Counters* counters = isolate->counters();
+
bool contextual_load_in_builtin =
is_contextual &&
- (Bootstrapper::IsActive() ||
+ (isolate->bootstrapper()->IsActive() ||
(!info_->closure().is_null() && info_->closure()->IsBuiltin()));
Result result;
@@ -9623,7 +9652,7 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
// use the double underscore macro that may insert instructions).
// Initially use an invalid map to force a failure.
masm()->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
- Immediate(Factory::null_value()));
+ Immediate(factory->null_value()));
// This branch is always a forwards branch so it's always a fixed size
// which allows the assert below to succeed and patching to work.
deferred->Branch(not_equal);
@@ -9635,14 +9664,16 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
if (is_contextual) {
// Load the (initialy invalid) cell and get its value.
- masm()->mov(result.reg(), Factory::null_value());
+ masm()->mov(result.reg(), factory->null_value());
if (FLAG_debug_code) {
__ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset),
- Factory::global_property_cell_map());
+ factory->global_property_cell_map());
__ Assert(equal, "Uninitialized inlined contextual load");
}
__ mov(result.reg(),
FieldOperand(result.reg(), JSGlobalPropertyCell::kValueOffset));
+ __ cmp(result.reg(), factory->the_hole_value());
+ deferred->Branch(equal);
bool is_dont_delete = false;
if (!info_->closure().is_null()) {
// When doing lazy compilation we can check if the global cell
@@ -9661,15 +9692,15 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
}
deferred->set_is_dont_delete(is_dont_delete);
if (!is_dont_delete) {
- __ cmp(result.reg(), Factory::the_hole_value());
+ __ cmp(result.reg(), factory->the_hole_value());
deferred->Branch(equal);
} else if (FLAG_debug_code) {
- __ cmp(result.reg(), Factory::the_hole_value());
+ __ cmp(result.reg(), factory->the_hole_value());
__ Check(not_equal, "DontDelete cells can't contain the hole");
}
- __ IncrementCounter(&Counters::named_load_global_inline, 1);
+ __ IncrementCounter(counters->named_load_global_inline(), 1);
if (is_dont_delete) {
- __ IncrementCounter(&Counters::dont_delete_hint_hit, 1);
+ __ IncrementCounter(counters->dont_delete_hint_hit(), 1);
}
} else {
// The initial (invalid) offset has to be large enough to force a 32-bit
@@ -9677,7 +9708,7 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
// kMaxInt (minus kHeapObjectTag).
int offset = kMaxInt;
masm()->mov(result.reg(), FieldOperand(receiver.reg(), offset));
- __ IncrementCounter(&Counters::named_load_inline, 1);
+ __ IncrementCounter(counters->named_load_inline(), 1);
}
deferred->BindExit();
@@ -9723,7 +9754,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
// Initially use an invalid map to force a failure.
__ bind(&patch_site);
masm()->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
- Immediate(Factory::null_value()));
+ Immediate(FACTORY->null_value()));
// This branch is always a forwards branch so it's always a fixed size
// which allows the assert below to succeed and patching to work.
slow.Branch(not_equal, &value, &receiver);
@@ -9833,7 +9864,7 @@ Result CodeGenerator::EmitKeyedLoad() {
// Use masm-> here instead of the double underscore macro since extra
// coverage code can interfere with the patching.
masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
- Immediate(Factory::null_value()));
+ Immediate(FACTORY->null_value()));
deferred->Branch(not_equal);
// Check that the key is a smi.
@@ -9863,9 +9894,9 @@ Result CodeGenerator::EmitKeyedLoad() {
times_2,
FixedArray::kHeaderSize));
result = elements;
- __ cmp(Operand(result.reg()), Immediate(Factory::the_hole_value()));
+ __ cmp(Operand(result.reg()), Immediate(FACTORY->the_hole_value()));
deferred->Branch(equal);
- __ IncrementCounter(&Counters::keyed_load_inline, 1);
+ __ IncrementCounter(masm_->isolate()->counters()->keyed_load_inline(), 1);
deferred->BindExit();
} else {
@@ -9935,12 +9966,6 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
__ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, tmp.reg());
deferred->Branch(not_equal);
- // Check that the key is within bounds. Both the key and the length of
- // the JSArray are smis. Use unsigned comparison to handle negative keys.
- __ cmp(key.reg(),
- FieldOperand(receiver.reg(), JSArray::kLengthOffset));
- deferred->Branch(above_equal);
-
// Get the elements array from the receiver and check that it is not a
// dictionary.
__ mov(tmp.reg(),
@@ -9963,12 +9988,20 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
// which will allow the debugger to break for fast case stores.
__ bind(deferred->patch_site());
__ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(FACTORY->fixed_array_map()));
deferred->Branch(not_equal);
+ // Check that the key is within bounds. Both the key and the length of
+ // the JSArray are smis (because the fixed array check above ensures the
+ // elements are in fast case). Use unsigned comparison to handle negative
+ // keys.
+ __ cmp(key.reg(),
+ FieldOperand(receiver.reg(), JSArray::kLengthOffset));
+ deferred->Branch(above_equal);
+
// Store the value.
__ mov(FixedArrayElementOperand(tmp.reg(), key.reg()), result.reg());
- __ IncrementCounter(&Counters::keyed_store_inline, 1);
+ __ IncrementCounter(masm_->isolate()->counters()->keyed_store_inline(), 1);
deferred->BindExit();
} else {
@@ -10171,7 +10204,7 @@ MemCopyFunction CreateMemCopyFunction() {
__ int3();
__ bind(&ok);
}
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (masm.isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope enable(SSE2);
__ push(edi);
__ push(esi);
@@ -10199,7 +10232,7 @@ MemCopyFunction CreateMemCopyFunction() {
__ test(Operand(src), Immediate(0x0F));
__ j(not_zero, &unaligned_source);
{
- __ IncrementCounter(&Counters::memcopy_aligned, 1);
+ __ IncrementCounter(masm.isolate()->counters()->memcopy_aligned(), 1);
// Copy loop for aligned source and destination.
__ mov(edx, count);
Register loop_count = ecx;
@@ -10247,7 +10280,7 @@ MemCopyFunction CreateMemCopyFunction() {
// Copy loop for unaligned source and aligned destination.
// If source is not aligned, we can't read it as efficiently.
__ bind(&unaligned_source);
- __ IncrementCounter(&Counters::memcopy_unaligned, 1);
+ __ IncrementCounter(masm.isolate()->counters()->memcopy_unaligned(), 1);
__ mov(edx, ecx);
Register loop_count = ecx;
Register count = edx;
@@ -10291,7 +10324,7 @@ MemCopyFunction CreateMemCopyFunction() {
}
} else {
- __ IncrementCounter(&Counters::memcopy_noxmm, 1);
+ __ IncrementCounter(masm.isolate()->counters()->memcopy_noxmm(), 1);
// SSE2 not supported. Unlikely to happen in practice.
__ push(edi);
__ push(esi);
diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h
index 27e33962..acd651b4 100644
--- a/src/ia32/codegen-ia32.h
+++ b/src/ia32/codegen-ia32.h
@@ -365,6 +365,7 @@ class CodeGenerator: public AstVisitor {
// Accessors
inline bool is_eval();
inline Scope* scope();
+ inline bool is_strict_mode();
inline StrictModeFlag strict_mode_flag();
// Generating deferred code.
@@ -779,6 +780,7 @@ class CodeGenerator: public AstVisitor {
int jit_cookie_;
friend class VirtualFrame;
+ friend class Isolate;
friend class JumpTarget;
friend class Reference;
friend class Result;
@@ -788,6 +790,7 @@ class CodeGenerator: public AstVisitor {
friend class LCodeGen;
friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc
+ friend class InlineRuntimeFunctionsTable;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
diff --git a/src/ia32/cpu-ia32.cc b/src/ia32/cpu-ia32.cc
index d64257f3..286ed7b8 100644
--- a/src/ia32/cpu-ia32.cc
+++ b/src/ia32/cpu-ia32.cc
@@ -42,9 +42,10 @@ namespace v8 {
namespace internal {
void CPU::Setup() {
- CpuFeatures::Clear();
- CpuFeatures::Probe(true);
- if (!CpuFeatures::IsSupported(SSE2) || Serializer::enabled()) {
+ CpuFeatures* cpu_features = Isolate::Current()->cpu_features();
+ cpu_features->Clear();
+ cpu_features->Probe(true);
+ if (!cpu_features->IsSupported(SSE2) || Serializer::enabled()) {
V8::DisableCrankshaft();
}
}
diff --git a/src/ia32/debug-ia32.cc b/src/ia32/debug-ia32.cc
index 678cc931..33c52515 100644
--- a/src/ia32/debug-ia32.cc
+++ b/src/ia32/debug-ia32.cc
@@ -49,7 +49,8 @@ bool BreakLocationIterator::IsDebugBreakAtReturn() {
void BreakLocationIterator::SetDebugBreakAtReturn() {
ASSERT(Assembler::kJSReturnSequenceLength >=
Assembler::kCallInstructionLength);
- rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(),
+ Isolate* isolate = Isolate::Current();
+ rinfo()->PatchCodeWithCall(isolate->debug()->debug_break_return()->entry(),
Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
}
@@ -78,8 +79,9 @@ bool BreakLocationIterator::IsDebugBreakAtSlot() {
void BreakLocationIterator::SetDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
+ Isolate* isolate = Isolate::Current();
rinfo()->PatchCodeWithCall(
- Debug::debug_break_slot()->entry(),
+ isolate->debug()->debug_break_slot()->entry(),
Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
}
@@ -126,7 +128,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ Set(eax, Immediate(0)); // No arguments.
- __ mov(ebx, Immediate(ExternalReference::debug_break()));
+ __ mov(ebx, Immediate(ExternalReference::debug_break(masm->isolate())));
CEntryStub ceb(1);
__ CallStub(&ceb);
@@ -161,7 +163,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
// jumping to the target address intended by the caller and that was
// overwritten by the address of DebugBreakXXX.
ExternalReference after_break_target =
- ExternalReference(Debug_Address::AfterBreakTarget());
+ ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate());
__ jmp(Operand::StaticVariable(after_break_target));
}
@@ -277,7 +279,8 @@ void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
ExternalReference restarter_frame_function_slot =
- ExternalReference(Debug_Address::RestarterFrameFunctionPointer());
+ ExternalReference(Debug_Address::RestarterFrameFunctionPointer(),
+ masm->isolate());
__ mov(Operand::StaticVariable(restarter_frame_function_slot), Immediate(0));
// We do not know our frame height, but set esp based on ebp.
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index 5f4d9444..c6342d7b 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -55,11 +55,89 @@ static void ZapCodeRange(Address start, Address end) {
}
-void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
- AssertNoAllocation no_allocation;
+void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
+ Isolate* isolate = code->GetIsolate();
+ HandleScope scope(isolate);
+
+ // Compute the size of relocation information needed for the code
+ // patching in Deoptimizer::DeoptimizeFunction.
+ int min_reloc_size = 0;
+ Address prev_reloc_address = code->instruction_start();
+ Address code_start_address = code->instruction_start();
+ SafepointTable table(*code);
+ for (unsigned i = 0; i < table.length(); ++i) {
+ Address curr_reloc_address = code_start_address + table.GetPcOffset(i);
+ ASSERT_GE(curr_reloc_address, prev_reloc_address);
+ SafepointEntry safepoint_entry = table.GetEntry(i);
+ int deoptimization_index = safepoint_entry.deoptimization_index();
+ if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
+ // The gap code is needed to get to the state expected at the
+ // bailout and we need to skip the call opcode to get to the
+ // address that needs reloc.
+ curr_reloc_address += safepoint_entry.gap_code_size() + 1;
+ int pc_delta = curr_reloc_address - prev_reloc_address;
+ // We use RUNTIME_ENTRY reloc info which has a size of 2 bytes
+ // if encodable with small pc delta encoding and up to 6 bytes
+ // otherwise.
+ if (pc_delta <= RelocInfo::kMaxSmallPCDelta) {
+ min_reloc_size += 2;
+ } else {
+ min_reloc_size += 6;
+ }
+ prev_reloc_address = curr_reloc_address;
+ }
+ }
+
+ // If the relocation information is not big enough we create a new
+ // relocation info object that is padded with comments to make it
+ // big enough for lazy doptimization.
+ int reloc_length = code->relocation_info()->length();
+ if (min_reloc_size > reloc_length) {
+ int comment_reloc_size = RelocInfo::kMinRelocCommentSize;
+ // Padding needed.
+ int min_padding = min_reloc_size - reloc_length;
+ // Number of comments needed to take up at least that much space.
+ int additional_comments =
+ (min_padding + comment_reloc_size - 1) / comment_reloc_size;
+ // Actual padding size.
+ int padding = additional_comments * comment_reloc_size;
+ // Allocate new relocation info and copy old relocation to the end
+ // of the new relocation info array because relocation info is
+ // written and read backwards.
+ Factory* factory = isolate->factory();
+ Handle<ByteArray> new_reloc =
+ factory->NewByteArray(reloc_length + padding, TENURED);
+ memcpy(new_reloc->GetDataStartAddress() + padding,
+ code->relocation_info()->GetDataStartAddress(),
+ reloc_length);
+ // Create a relocation writer to write the comments in the padding
+ // space. Use position 0 for everything to ensure short encoding.
+ RelocInfoWriter reloc_info_writer(
+ new_reloc->GetDataStartAddress() + padding, 0);
+ intptr_t comment_string
+ = reinterpret_cast<intptr_t>(RelocInfo::kFillerCommentString);
+ RelocInfo rinfo(0, RelocInfo::COMMENT, comment_string);
+ for (int i = 0; i < additional_comments; ++i) {
+#ifdef DEBUG
+ byte* pos_before = reloc_info_writer.pos();
+#endif
+ reloc_info_writer.Write(&rinfo);
+ ASSERT(RelocInfo::kMinRelocCommentSize ==
+ pos_before - reloc_info_writer.pos());
+ }
+ // Replace relocation information on the code object.
+ code->set_relocation_info(*new_reloc);
+ }
+}
+
+void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
if (!function->IsOptimized()) return;
+ Isolate* isolate = function->GetIsolate();
+ HandleScope scope(isolate);
+ AssertNoAllocation no_allocation;
+
// Get the optimized code.
Code* code = function->code();
Address code_start_address = code->instruction_start();
@@ -118,12 +196,14 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
// a non-live object in the extra space at the end of the former reloc info.
Address junk_address = reloc_info->address() + reloc_info->Size();
ASSERT(junk_address <= reloc_end_address);
- Heap::CreateFillerObjectAt(junk_address, reloc_end_address - junk_address);
+ isolate->heap()->CreateFillerObjectAt(junk_address,
+ reloc_end_address - junk_address);
// Add the deoptimizing code to the list.
DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
- node->set_next(deoptimizing_code_list_);
- deoptimizing_code_list_ = node;
+ DeoptimizerData* data = isolate->deoptimizer_data();
+ node->set_next(data->deoptimizing_code_list_);
+ data->deoptimizing_code_list_ = node;
// Set the code for the function to non-optimized version.
function->ReplaceCode(function->shared()->code());
@@ -132,6 +212,11 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
PrintF("[forced deoptimization: ");
function->PrintName();
PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
+#ifdef DEBUG
+ if (FLAG_print_code) {
+ code->PrintLn();
+ }
+#endif
}
}
@@ -284,13 +369,31 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
// There are no translation commands for the caller's pc and fp, the
// context, and the function. Set them up explicitly.
- for (int i = 0; ok && i < 4; i++) {
+ for (int i = StandardFrameConstants::kCallerPCOffset;
+ ok && i >= StandardFrameConstants::kMarkerOffset;
+ i -= kPointerSize) {
uint32_t input_value = input_->GetFrameSlot(input_offset);
if (FLAG_trace_osr) {
- PrintF(" [esp + %d] <- 0x%08x ; [esp + %d] (fixed part)\n",
+ const char* name = "UNKNOWN";
+ switch (i) {
+ case StandardFrameConstants::kCallerPCOffset:
+ name = "caller's pc";
+ break;
+ case StandardFrameConstants::kCallerFPOffset:
+ name = "fp";
+ break;
+ case StandardFrameConstants::kContextOffset:
+ name = "context";
+ break;
+ case StandardFrameConstants::kMarkerOffset:
+ name = "function";
+ break;
+ }
+ PrintF(" [esp + %d] <- 0x%08x ; [esp + %d] (fixed part - %s)\n",
output_offset,
input_value,
- input_offset);
+ input_offset,
+ name);
}
output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
input_offset -= kPointerSize;
@@ -317,7 +420,8 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
optimized_code_->entry() + pc_offset);
output_[0]->SetPc(pc);
}
- Code* continuation = Builtins::builtin(Builtins::NotifyOSR);
+ Code* continuation =
+ function->GetIsolate()->builtins()->builtin(Builtins::kNotifyOSR);
output_[0]->SetContinuation(
reinterpret_cast<uint32_t>(continuation->entry()));
@@ -484,9 +588,10 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
// Set the continuation for the topmost frame.
if (is_topmost) {
+ Builtins* builtins = isolate_->builtins();
Code* continuation = (bailout_type_ == EAGER)
- ? Builtins::builtin(Builtins::NotifyDeoptimized)
- : Builtins::builtin(Builtins::NotifyLazyDeoptimized);
+ ? builtins->builtin(Builtins::kNotifyDeoptimized)
+ : builtins->builtin(Builtins::kNotifyLazyDeoptimized);
output_frame->SetContinuation(
reinterpret_cast<uint32_t>(continuation->entry()));
}
@@ -501,6 +606,8 @@ void Deoptimizer::EntryGenerator::Generate() {
GeneratePrologue();
CpuFeatures::Scope scope(SSE2);
+ Isolate* isolate = masm()->isolate();
+
// Save all general purpose registers before messing with them.
const int kNumberOfRegisters = Register::kNumRegisters;
@@ -541,7 +648,7 @@ void Deoptimizer::EntryGenerator::Generate() {
__ mov(Operand(esp, 2 * kPointerSize), ebx); // Bailout id.
__ mov(Operand(esp, 3 * kPointerSize), ecx); // Code address or 0.
__ mov(Operand(esp, 4 * kPointerSize), edx); // Fp-to-sp delta.
- __ CallCFunction(ExternalReference::new_deoptimizer_function(), 5);
+ __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 5);
// Preserve deoptimizer object in register eax and get the input
// frame descriptor pointer.
@@ -589,7 +696,8 @@ void Deoptimizer::EntryGenerator::Generate() {
__ push(eax);
__ PrepareCallCFunction(1, ebx);
__ mov(Operand(esp, 0 * kPointerSize), eax);
- __ CallCFunction(ExternalReference::compute_output_frames_function(), 1);
+ __ CallCFunction(
+ ExternalReference::compute_output_frames_function(isolate), 1);
__ pop(eax);
// Replace the current frame with the output frames.
diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
index e0cbe35c..d1c869a2 100644
--- a/src/ia32/disasm-ia32.cc
+++ b/src/ia32/disasm-ia32.cc
@@ -331,6 +331,7 @@ class DisassemblerIA32 {
int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
int PrintRightOperand(byte* modrmp);
int PrintRightByteOperand(byte* modrmp);
+ int PrintRightXMMOperand(byte* modrmp);
int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
int PrintImmediateOp(byte* data);
int F7Instruction(byte* data);
@@ -367,9 +368,11 @@ void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
int DisassemblerIA32::PrintRightOperandHelper(
byte* modrmp,
- RegisterNameMapping register_name) {
+ RegisterNameMapping direct_register_name) {
int mod, regop, rm;
get_modrm(*modrmp, &mod, &regop, &rm);
+ RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
+ &DisassemblerIA32::NameOfCPURegister;
switch (mod) {
case 0:
if (rm == ebp) {
@@ -454,6 +457,12 @@ int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
}
+int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
+ return PrintRightOperandHelper(modrmp,
+ &DisassemblerIA32::NameOfXMMRegister);
+}
+
+
// Returns number of bytes used including the current *data.
// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
int DisassemblerIA32::PrintOperands(const char* mnem,
@@ -937,7 +946,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
get_modrm(*data, &mod, &regop, &rm);
if (regop == eax) {
AppendToBuffer("test_b ");
- data += PrintRightOperand(data);
+ data += PrintRightByteOperand(data);
int32_t imm = *data;
AppendToBuffer(",0x%x", imm);
data++;
@@ -1035,11 +1044,19 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
case 0xC6: // imm8
{ bool is_byte = *data == 0xC6;
data++;
- AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
- data += PrintRightOperand(data);
- int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
- AppendToBuffer(",0x%x", imm);
- data += is_byte ? 1 : 4;
+ if (is_byte) {
+ AppendToBuffer("%s ", "mov_b");
+ data += PrintRightByteOperand(data);
+ int32_t imm = *data;
+ AppendToBuffer(",0x%x", imm);
+ data++;
+ } else {
+ AppendToBuffer("%s ", "mov");
+ data += PrintRightOperand(data);
+ int32_t imm = *reinterpret_cast<int32_t*>(data);
+ AppendToBuffer(",0x%x", imm);
+ data += 4;
+ }
}
break;
@@ -1054,7 +1071,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
default: UnimplementedInstruction();
}
AppendToBuffer("%s ", mnem);
- data += PrintRightOperand(data);
+ data += PrintRightByteOperand(data);
int32_t imm = *data;
AppendToBuffer(",0x%x", imm);
data++;
@@ -1067,9 +1084,15 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
int mod, regop, rm;
data++;
get_modrm(*data, &mod, &regop, &rm);
- AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
- data += PrintRightOperand(data);
- AppendToBuffer(",%s", NameOfCPURegister(regop));
+ if (is_byte) {
+ AppendToBuffer("%s ", "mov_b");
+ data += PrintRightByteOperand(data);
+ AppendToBuffer(",%s", NameOfByteCPURegister(regop));
+ } else {
+ AppendToBuffer("%s ", "mov");
+ data += PrintRightOperand(data);
+ AppendToBuffer(",%s", NameOfCPURegister(regop));
+ }
}
break;
@@ -1181,7 +1204,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
- data += PrintRightOperand(data);
+ data += PrintRightXMMOperand(data);
} else if (*data == 0x70) {
data++;
int mod, regop, rm;
@@ -1224,7 +1247,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
data++;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
- data += PrintRightOperand(data);
+ data += PrintRightXMMOperand(data);
AppendToBuffer(",%s", NameOfXMMRegister(regop));
} else if (*data == 0x7E) {
data++;
@@ -1242,12 +1265,16 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
NameOfXMMRegister(rm));
data++;
} else if (*data == 0xE7) {
- AppendToBuffer("movntdq ");
data++;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
- data += PrintRightOperand(data);
- AppendToBuffer(",%s", NameOfXMMRegister(regop));
+ if (mod == 3) {
+ AppendToBuffer("movntdq ");
+ data += PrintRightOperand(data);
+ AppendToBuffer(",%s", NameOfXMMRegister(regop));
+ } else {
+ UnimplementedInstruction();
+ }
} else if (*data == 0xEF) {
data++;
int mod, regop, rm;
@@ -1338,14 +1365,20 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
- data += PrintRightOperand(data);
+ data += PrintRightXMMOperand(data);
AppendToBuffer(",%s", NameOfXMMRegister(regop));
} else if (b2 == 0x10) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
- data += PrintRightOperand(data);
+ data += PrintRightXMMOperand(data);
+ } else if (b2 == 0x5A) {
+ data += 3;
+ int mod, regop, rm;
+ get_modrm(*data, &mod, &regop, &rm);
+ AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
+ data += PrintRightXMMOperand(data);
} else {
const char* mnem = "?";
switch (b2) {
@@ -1361,27 +1394,11 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
if (b2 == 0x2A) {
- if (mod != 0x3) {
- AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
- data += PrintRightOperand(data);
- } else {
- AppendToBuffer("%s %s,%s",
- mnem,
- NameOfXMMRegister(regop),
- NameOfCPURegister(rm));
- data++;
- }
+ AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
+ data += PrintRightOperand(data);
} else if (b2 == 0x2C) {
- if (mod != 0x3) {
- AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
- data += PrintRightOperand(data);
- } else {
- AppendToBuffer("%s %s,%s",
- mnem,
- NameOfCPURegister(regop),
- NameOfXMMRegister(rm));
- data++;
- }
+ AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
+ data += PrintRightXMMOperand(data);
} else if (b2 == 0xC2) {
// Intel manual 2A, Table 3-18.
const char* const pseudo_op[] = {
@@ -1400,16 +1417,8 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
NameOfXMMRegister(rm));
data += 2;
} else {
- if (mod != 0x3) {
- AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
- data += PrintRightOperand(data);
- } else {
- AppendToBuffer("%s %s,%s",
- mnem,
- NameOfXMMRegister(regop),
- NameOfXMMRegister(rm));
- data++;
- }
+ AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
+ data += PrintRightXMMOperand(data);
}
}
} else {
@@ -1419,29 +1428,44 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
case 0xF3:
if (*(data+1) == 0x0F) {
- if (*(data+2) == 0x2C) {
+ byte b2 = *(data+2);
+ if (b2 == 0x11) {
+ AppendToBuffer("movss ");
data += 3;
- data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
- } else if (*(data+2) == 0x5A) {
+ int mod, regop, rm;
+ get_modrm(*data, &mod, &regop, &rm);
+ data += PrintRightXMMOperand(data);
+ AppendToBuffer(",%s", NameOfXMMRegister(regop));
+ } else if (b2 == 0x10) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
- AppendToBuffer("cvtss2sd %s,%s",
- NameOfXMMRegister(regop),
- NameOfXMMRegister(rm));
- data++;
- } else if (*(data+2) == 0x6F) {
+ AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
+ data += PrintRightXMMOperand(data);
+ } else if (b2 == 0x2C) {
+ data += 3;
+ int mod, regop, rm;
+ get_modrm(*data, &mod, &regop, &rm);
+ AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
+ data += PrintRightXMMOperand(data);
+ } else if (b2 == 0x5A) {
+ data += 3;
+ int mod, regop, rm;
+ get_modrm(*data, &mod, &regop, &rm);
+ AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
+ data += PrintRightXMMOperand(data);
+ } else if (b2 == 0x6F) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
- data += PrintRightOperand(data);
- } else if (*(data+2) == 0x7F) {
+ data += PrintRightXMMOperand(data);
+ } else if (b2 == 0x7F) {
AppendToBuffer("movdqu ");
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
- data += PrintRightOperand(data);
+ data += PrintRightXMMOperand(data);
AppendToBuffer(",%s", NameOfXMMRegister(regop));
} else {
UnimplementedInstruction();
@@ -1514,9 +1538,8 @@ static const char* xmm_regs[8] = {
const char* NameConverter::NameOfAddress(byte* addr) const {
- static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
- v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
- return tmp_buffer.start();
+ v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
+ return tmp_buffer_.start();
}
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 9a7d41ad..16c39c5e 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -129,9 +129,9 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = scope()->num_stack_slots();
if (locals_count == 1) {
- __ push(Immediate(Factory::undefined_value()));
+ __ push(Immediate(isolate()->factory()->undefined_value()));
} else if (locals_count > 1) {
- __ mov(eax, Immediate(Factory::undefined_value()));
+ __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
for (int i = 0; i < locals_count; i++) {
__ push(eax);
}
@@ -197,12 +197,17 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous
// stack frame was an arguments adapter frame.
- ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+ ArgumentsAccessStub stub(
+ is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
+ : ArgumentsAccessStub::NEW_NON_STRICT);
__ CallStub(&stub);
- __ mov(ecx, eax); // Duplicate result.
+
+ Variable* arguments_shadow = scope()->arguments_shadow();
+ if (arguments_shadow != NULL) {
+ __ mov(ecx, eax); // Duplicate result.
+ Move(arguments_shadow->AsSlot(), ecx, ebx, edx);
+ }
Move(arguments->AsSlot(), eax, ebx, edx);
- Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
- Move(dot_arguments_slot, ecx, ebx, edx);
}
if (FLAG_trace) {
@@ -229,7 +234,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
PrepareForBailout(info->function(), NO_REGISTERS);
NearLabel ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &ok, taken);
StackCheckStub stub;
@@ -247,7 +252,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Always emit a 'return undefined' in case control fell off the end of
// the body.
{ Comment cmnt(masm_, "[ return <undefined>;");
- __ mov(eax, Factory::undefined_value());
+ __ mov(eax, isolate()->factory()->undefined_value());
EmitReturnSequence();
}
}
@@ -261,7 +266,8 @@ void FullCodeGenerator::ClearAccumulator() {
void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
Comment cmnt(masm_, "[ Stack check");
NearLabel ok;
- ExternalReference stack_limit = ExternalReference::address_of_stack_limit();
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &ok, taken);
StackCheckStub stub;
@@ -462,10 +468,10 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(
Label* materialize_false) const {
NearLabel done;
__ bind(materialize_true);
- __ mov(result_register(), Factory::true_value());
+ __ mov(result_register(), isolate()->factory()->true_value());
__ jmp(&done);
__ bind(materialize_false);
- __ mov(result_register(), Factory::false_value());
+ __ mov(result_register(), isolate()->factory()->false_value());
__ bind(&done);
}
@@ -475,10 +481,10 @@ void FullCodeGenerator::StackValueContext::Plug(
Label* materialize_false) const {
NearLabel done;
__ bind(materialize_true);
- __ push(Immediate(Factory::true_value()));
+ __ push(Immediate(isolate()->factory()->true_value()));
__ jmp(&done);
__ bind(materialize_false);
- __ push(Immediate(Factory::false_value()));
+ __ push(Immediate(isolate()->factory()->false_value()));
__ bind(&done);
}
@@ -495,15 +501,17 @@ void FullCodeGenerator::EffectContext::Plug(bool flag) const {
void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
- Handle<Object> value =
- flag ? Factory::true_value() : Factory::false_value();
+ Handle<Object> value = flag
+ ? isolate()->factory()->true_value()
+ : isolate()->factory()->false_value();
__ mov(result_register(), value);
}
void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
- Handle<Object> value =
- flag ? Factory::true_value() : Factory::false_value();
+ Handle<Object> value = flag
+ ? isolate()->factory()->true_value()
+ : isolate()->factory()->false_value();
__ push(Immediate(value));
}
@@ -525,11 +533,11 @@ void FullCodeGenerator::DoTest(Label* if_true,
Label* if_false,
Label* fall_through) {
// Emit the inlined tests assumed by the stub.
- __ cmp(result_register(), Factory::undefined_value());
+ __ cmp(result_register(), isolate()->factory()->undefined_value());
__ j(equal, if_false);
- __ cmp(result_register(), Factory::true_value());
+ __ cmp(result_register(), isolate()->factory()->true_value());
__ j(equal, if_true);
- __ cmp(result_register(), Factory::false_value());
+ __ cmp(result_register(), isolate()->factory()->false_value());
__ j(equal, if_false);
STATIC_ASSERT(kSmiTag == 0);
__ test(result_register(), Operand(result_register()));
@@ -624,7 +632,7 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
}
if (should_normalize) {
- __ cmp(eax, Factory::true_value());
+ __ cmp(eax, isolate()->factory()->true_value());
Split(equal, if_true, if_false, NULL);
__ bind(&skip);
}
@@ -645,7 +653,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
case Slot::LOCAL:
if (mode == Variable::CONST) {
__ mov(Operand(ebp, SlotOffset(slot)),
- Immediate(Factory::the_hole_value()));
+ Immediate(isolate()->factory()->the_hole_value()));
} else if (function != NULL) {
VisitForAccumulatorValue(function);
__ mov(Operand(ebp, SlotOffset(slot)), result_register());
@@ -667,7 +675,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
}
if (mode == Variable::CONST) {
__ mov(ContextOperand(esi, slot->index()),
- Immediate(Factory::the_hole_value()));
+ Immediate(isolate()->factory()->the_hole_value()));
// No write barrier since the hole value is in old space.
} else if (function != NULL) {
VisitForAccumulatorValue(function);
@@ -690,7 +698,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value.
if (mode == Variable::CONST) {
- __ push(Immediate(Factory::the_hole_value()));
+ __ push(Immediate(isolate()->factory()->the_hole_value()));
} else if (function != NULL) {
VisitForStackValue(function);
} else {
@@ -718,15 +726,15 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ pop(edx);
} else {
__ mov(edx, eax);
- __ mov(eax, Factory::the_hole_value());
+ __ mov(eax, isolate()->factory()->the_hole_value());
}
ASSERT(prop->key()->AsLiteral() != NULL &&
prop->key()->AsLiteral()->handle()->IsSmi());
__ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
- Handle<Code> ic(Builtins::builtin(is_strict()
- ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
}
}
@@ -822,6 +830,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
Comment cmnt(masm_, "[ Case body");
CaseClause* clause = clauses->at(i);
__ bind(clause->body_target()->entry_label());
+ PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
VisitStatements(clause->statements());
}
@@ -842,9 +851,9 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// ignore null and undefined in contrast to the specification; see
// ECMA-262 section 12.6.4.
VisitForAccumulatorValue(stmt->enumerable());
- __ cmp(eax, Factory::undefined_value());
+ __ cmp(eax, isolate()->factory()->undefined_value());
__ j(equal, &exit);
- __ cmp(eax, Factory::null_value());
+ __ cmp(eax, isolate()->factory()->null_value());
__ j(equal, &exit);
// Convert the object to a JS object.
@@ -870,7 +879,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Check that there are no elements. Register ecx contains the
// current JS object we've reached through the prototype chain.
__ cmp(FieldOperand(ecx, JSObject::kElementsOffset),
- Factory::empty_fixed_array());
+ isolate()->factory()->empty_fixed_array());
__ j(not_equal, &call_runtime);
// Check that instance descriptors are not empty so that we can
@@ -878,7 +887,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// prototype load.
__ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
__ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
- __ cmp(edx, Factory::empty_descriptor_array());
+ __ cmp(edx, isolate()->factory()->empty_descriptor_array());
__ j(equal, &call_runtime);
// Check that there is an enum cache in the non-empty instance
@@ -893,13 +902,13 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ cmp(ecx, Operand(eax));
__ j(equal, &check_prototype);
__ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
- __ cmp(edx, Factory::empty_fixed_array());
+ __ cmp(edx, isolate()->factory()->empty_fixed_array());
__ j(not_equal, &call_runtime);
// Load the prototype from the map and loop if non-null.
__ bind(&check_prototype);
__ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
- __ cmp(ecx, Factory::null_value());
+ __ cmp(ecx, isolate()->factory()->null_value());
__ j(not_equal, &next);
// The enum cache is valid. Load the map of the object being
@@ -917,7 +926,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// modification check. Otherwise, we got a fixed array, and we have
// to do a slow check.
NearLabel fixed_array;
- __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map());
+ __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
+ isolate()->factory()->meta_map());
__ j(not_equal, &fixed_array);
// We got a map in register eax. Get the enumeration cache from it.
@@ -1013,18 +1023,18 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
// doesn't just get a copy of the existing unoptimized code.
if (!FLAG_always_opt &&
!FLAG_prepare_always_opt &&
+ !pretenure &&
scope()->is_function_scope() &&
- info->num_literals() == 0 &&
- !pretenure) {
- FastNewClosureStub stub;
+ info->num_literals() == 0) {
+ FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
__ push(Immediate(info));
__ CallStub(&stub);
} else {
__ push(esi);
__ push(Immediate(info));
__ push(Immediate(pretenure
- ? Factory::true_value()
- : Factory::false_value()));
+ ? isolate()->factory()->true_value()
+ : isolate()->factory()->false_value()));
__ CallRuntime(Runtime::kNewClosure, 3);
}
context()->Plug(eax);
@@ -1076,7 +1086,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
__ bind(&next);
// Terminate at global context.
__ cmp(FieldOperand(temp, HeapObject::kMapOffset),
- Immediate(Factory::global_context_map()));
+ Immediate(isolate()->factory()->global_context_map()));
__ j(equal, &fast);
// Check that extension is NULL.
__ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
@@ -1092,7 +1102,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
// load IC call.
__ mov(eax, GlobalObjectOperand());
__ mov(ecx, slot->var()->name());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
@@ -1153,9 +1163,9 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
__ mov(eax,
ContextSlotOperandCheckExtensions(potential_slot, slow));
if (potential_slot->var()->mode() == Variable::CONST) {
- __ cmp(eax, Factory::the_hole_value());
+ __ cmp(eax, isolate()->factory()->the_hole_value());
__ j(not_equal, done);
- __ mov(eax, Factory::undefined_value());
+ __ mov(eax, isolate()->factory()->undefined_value());
}
__ jmp(done);
} else if (rewrite != NULL) {
@@ -1175,7 +1185,8 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
slow));
__ mov(eax, Immediate(key_literal->handle()));
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic =
+ isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
__ jmp(done);
}
@@ -1198,7 +1209,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
// object on the stack.
__ mov(eax, GlobalObjectOperand());
__ mov(ecx, var->name());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(eax);
@@ -1228,9 +1239,9 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
NearLabel done;
MemOperand slot_operand = EmitSlotSearch(slot, eax);
__ mov(eax, slot_operand);
- __ cmp(eax, Factory::the_hole_value());
+ __ cmp(eax, isolate()->factory()->the_hole_value());
__ j(not_equal, &done);
- __ mov(eax, Factory::undefined_value());
+ __ mov(eax, isolate()->factory()->undefined_value());
__ bind(&done);
context()->Plug(eax);
} else {
@@ -1261,7 +1272,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
__ mov(eax, Immediate(key_literal->handle()));
// Do a keyed property load.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Drop key and object left on the stack by IC.
@@ -1283,7 +1294,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ mov(ebx, FieldOperand(ecx, literal_offset));
- __ cmp(ebx, Factory::undefined_value());
+ __ cmp(ebx, isolate()->factory()->undefined_value());
__ j(not_equal, &materialized);
// Create regexp literal using runtime function
@@ -1330,7 +1341,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(expr->literal_index())));
__ push(Immediate(expr->constant_properties()));
- __ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
+ int flags = expr->fast_elements()
+ ? ObjectLiteral::kFastElements
+ : ObjectLiteral::kNoFlags;
+ flags |= expr->has_function()
+ ? ObjectLiteral::kHasFunction
+ : ObjectLiteral::kNoFlags;
+ __ push(Immediate(Smi::FromInt(flags)));
if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateObjectLiteral, 4);
} else {
@@ -1366,9 +1383,9 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
VisitForAccumulatorValue(value);
__ mov(ecx, Immediate(key->handle()));
__ mov(edx, Operand(esp, 0));
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(key->id(), NO_REGISTERS);
} else {
@@ -1402,6 +1419,12 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
}
+ if (expr->has_function()) {
+ ASSERT(result_saved);
+ __ push(Operand(esp, 0));
+ __ CallRuntime(Runtime::kToFastProperties, 1);
+ }
+
if (result_saved) {
context()->PlugTOS();
} else {
@@ -1420,12 +1443,13 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
__ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(expr->literal_index())));
__ push(Immediate(expr->constant_elements()));
- if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
+ if (expr->constant_elements()->map() ==
+ isolate()->heap()->fixed_cow_array_map()) {
ASSERT(expr->depth() == 1);
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
__ CallStub(&stub);
- __ IncrementCounter(&Counters::cow_arrays_created_stub, 1);
+ __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
} else if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
@@ -1610,14 +1634,14 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral();
__ mov(ecx, Immediate(key->handle()));
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
}
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
}
@@ -1758,9 +1782,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
__ mov(edx, eax);
__ pop(eax); // Restore value.
__ mov(ecx, prop->key()->AsLiteral()->handle());
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
break;
}
@@ -1781,9 +1805,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
__ pop(edx);
}
__ pop(eax); // Restore value.
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
break;
}
@@ -1807,9 +1831,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// ecx, and the global object on the stack.
__ mov(ecx, var->name());
__ mov(edx, GlobalObjectOperand());
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
@@ -1826,14 +1850,14 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
break;
case Slot::LOCAL:
__ mov(edx, Operand(ebp, SlotOffset(slot)));
- __ cmp(edx, Factory::the_hole_value());
+ __ cmp(edx, isolate()->factory()->the_hole_value());
__ j(not_equal, &skip);
__ mov(Operand(ebp, SlotOffset(slot)), eax);
break;
case Slot::CONTEXT: {
__ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX));
__ mov(edx, ContextOperand(ecx, slot->index()));
- __ cmp(edx, Factory::the_hole_value());
+ __ cmp(edx, isolate()->factory()->the_hole_value());
__ j(not_equal, &skip);
__ mov(ContextOperand(ecx, slot->index()), eax);
int offset = Context::SlotOffset(slot->index());
@@ -1910,9 +1934,9 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
} else {
__ pop(edx);
}
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// If the assignment ends an initialization block, revert to fast case.
@@ -1950,9 +1974,9 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
}
// Record source code position before IC call.
SetSourcePosition(expr->position());
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// If the assignment ends an initialization block, revert to fast case.
@@ -2002,7 +2026,8 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Record source position of the IC call.
SetSourcePosition(expr->position());
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
+ arg_count, in_loop);
EmitCallIC(ic, mode);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2034,7 +2059,8 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
// Record source position of the IC call.
SetSourcePosition(expr->position());
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
+ arg_count, in_loop);
__ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, mode);
RecordJSReturnSite(expr);
@@ -2071,7 +2097,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
if (arg_count > 0) {
__ push(Operand(esp, arg_count * kPointerSize));
} else {
- __ push(Immediate(Factory::undefined_value()));
+ __ push(Immediate(isolate()->factory()->undefined_value()));
}
// Push the receiver of the enclosing function.
@@ -2107,7 +2133,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
{ PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(fun);
// Reserved receiver slot.
- __ push(Immediate(Factory::undefined_value()));
+ __ push(Immediate(isolate()->factory()->undefined_value()));
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
@@ -2226,7 +2252,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Record source code position for IC call.
SetSourcePosition(prop->position());
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Push result (function).
__ push(eax);
@@ -2247,7 +2273,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// also use the full code generator.
FunctionLiteral* lit = fun->AsFunctionLiteral();
if (lit != NULL &&
- lit->name()->Equals(Heap::empty_string()) &&
+ lit->name()->Equals(isolate()->heap()->empty_string()) &&
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
@@ -2294,7 +2320,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ Set(eax, Immediate(arg_count));
__ mov(edi, Operand(esp, arg_count * kPointerSize));
- Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> construct_builtin =
+ isolate()->builtins()->JSConstructCall();
__ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
context()->Plug(eax);
}
@@ -2354,7 +2381,7 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, if_false);
- __ cmp(eax, Factory::null_value());
+ __ cmp(eax, isolate()->factory()->null_value());
__ j(equal, if_true);
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
// Undetectable objects behave like undefined when tested with typeof.
@@ -2633,17 +2660,17 @@ void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
// Functions have class 'Function'.
__ bind(&function);
- __ mov(eax, Factory::function_class_symbol());
+ __ mov(eax, isolate()->factory()->function_class_symbol());
__ jmp(&done);
// Objects with a non-function constructor have class 'Object'.
__ bind(&non_function_constructor);
- __ mov(eax, Factory::Object_symbol());
+ __ mov(eax, isolate()->factory()->Object_symbol());
__ jmp(&done);
// Non-JS objects have class null.
__ bind(&null);
- __ mov(eax, Factory::null_value());
+ __ mov(eax, isolate()->factory()->null_value());
// All done.
__ bind(&done);
@@ -2669,7 +2696,7 @@ void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
}
#endif
// Finally, we're expected to leave a value on the top of the stack.
- __ mov(eax, Factory::undefined_value());
+ __ mov(eax, isolate()->factory()->undefined_value());
context()->Plug(eax);
}
@@ -2691,13 +2718,14 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
__ bind(&heapnumber_allocated);
__ PrepareCallCFunction(0, ebx);
- __ CallCFunction(ExternalReference::random_uint32_function(), 0);
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()),
+ 0);
// Convert 32 random bits in eax to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
// This is implemented on both SSE2 and FPU.
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (isolate()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope fscope(SSE2);
__ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
__ movd(xmm1, Operand(ebx));
@@ -2772,8 +2800,12 @@ void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
- MathPowStub stub;
- __ CallStub(&stub);
+ if (isolate()->cpu_features()->IsSupported(SSE2)) {
+ MathPowStub stub;
+ __ CallStub(&stub);
+ } else {
+ __ CallRuntime(Runtime::kMath_pow, 2);
+ }
context()->Plug(eax);
}
@@ -2866,13 +2898,13 @@ void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
__ bind(&index_out_of_range);
// When the index is out of range, the spec requires us to return
// NaN.
- __ Set(result, Immediate(Factory::nan_value()));
+ __ Set(result, Immediate(isolate()->factory()->nan_value()));
__ jmp(&done);
__ bind(&need_conversion);
// Move the undefined value into the result register, which will
// trigger conversion.
- __ Set(result, Immediate(Factory::undefined_value()));
+ __ Set(result, Immediate(isolate()->factory()->undefined_value()));
__ jmp(&done);
NopRuntimeCallHelper call_helper;
@@ -2915,7 +2947,7 @@ void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
__ bind(&index_out_of_range);
// When the index is out of range, the spec requires us to return
// the empty string.
- __ Set(result, Immediate(Factory::empty_string()));
+ __ Set(result, Immediate(isolate()->factory()->empty_string()));
__ jmp(&done);
__ bind(&need_conversion);
@@ -3045,8 +3077,8 @@ void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
// Fetch the map and check if array is in fast case.
// Check that object doesn't require security checks and
// has no indexed interceptor.
- __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp);
- __ j(below, &slow_case);
+ __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
+ __ j(not_equal, &slow_case);
__ test_b(FieldOperand(temp, Map::kBitFieldOffset),
KeyedLoadIC::kSlowCaseBitFieldMask);
__ j(not_zero, &slow_case);
@@ -3054,7 +3086,7 @@ void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
// Check the object's elements are in fast case and writable.
__ mov(elements, FieldOperand(object, JSObject::kElementsOffset));
__ cmp(FieldOperand(elements, HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(isolate()->factory()->fixed_array_map()));
__ j(not_equal, &slow_case);
// Check that both indices are smis.
@@ -3092,7 +3124,7 @@ void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
__ bind(&new_space);
// We are done. Drop elements from the stack, and return undefined.
__ add(Operand(esp), Immediate(3 * kPointerSize));
- __ mov(eax, Factory::undefined_value());
+ __ mov(eax, isolate()->factory()->undefined_value());
__ jmp(&done);
__ bind(&slow_case);
@@ -3110,10 +3142,10 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
Handle<FixedArray> jsfunction_result_caches(
- Top::global_context()->jsfunction_result_caches());
+ isolate()->global_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort("Attempt to use undefined cache.");
- __ mov(eax, Factory::undefined_value());
+ __ mov(eax, isolate()->factory()->undefined_value());
context()->Plug(eax);
return;
}
@@ -3170,7 +3202,8 @@ void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
__ and_(Operand(tmp), right);
__ test(Operand(tmp), Immediate(kSmiTagMask));
__ j(zero, &fail);
- __ CmpObjectType(left, JS_REGEXP_TYPE, tmp);
+ __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
+ __ CmpInstanceType(tmp, JS_REGEXP_TYPE);
__ j(not_equal, &fail);
__ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
__ j(not_equal, &fail);
@@ -3178,10 +3211,10 @@ void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
__ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
__ j(equal, &ok);
__ bind(&fail);
- __ mov(eax, Immediate(Factory::false_value()));
+ __ mov(eax, Immediate(isolate()->factory()->false_value()));
__ jmp(&done);
__ bind(&ok);
- __ mov(eax, Immediate(Factory::true_value()));
+ __ mov(eax, Immediate(isolate()->factory()->true_value()));
__ bind(&done);
context()->Plug(eax);
@@ -3274,7 +3307,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
__ SmiUntag(array_length);
__ j(not_zero, &non_trivial_array);
- __ mov(result_operand, Factory::empty_string());
+ __ mov(result_operand, isolate()->factory()->empty_string());
__ jmp(&done);
// Save the array length.
@@ -3485,7 +3518,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
__ bind(&bailout);
- __ mov(result_operand, Factory::undefined_value());
+ __ mov(result_operand, isolate()->factory()->undefined_value());
__ bind(&done);
__ mov(eax, result_operand);
// Drop temp values from the stack, and restore context register.
@@ -3523,7 +3556,8 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
// Call the JS runtime function via a call IC.
__ Set(ecx, Immediate(expr->name()));
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
+ arg_count, in_loop);
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@@ -3589,7 +3623,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
case Token::VOID: {
Comment cmnt(masm_, "[ UnaryOperation (VOID)");
VisitForEffect(expr->expression());
- context()->Plug(Factory::undefined_value());
+ context()->Plug(isolate()->factory()->undefined_value());
break;
}
@@ -3837,9 +3871,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
case NAMED_PROPERTY: {
__ mov(ecx, prop->key()->AsLiteral()->handle());
__ pop(edx);
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -3854,9 +3888,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
case KEYED_PROPERTY: {
__ pop(ecx);
__ pop(edx);
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -3882,7 +3916,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Comment cmnt(masm_, "Global variable");
__ mov(eax, GlobalObjectOperand());
__ mov(ecx, Immediate(proxy->name()));
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference
// error.
EmitCallIC(ic, RelocInfo::CODE_TARGET);
@@ -3935,12 +3969,12 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
}
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- if (check->Equals(Heap::number_symbol())) {
+ if (check->Equals(isolate()->heap()->number_symbol())) {
__ JumpIfSmi(eax, if_true);
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ isolate()->factory()->heap_number_map());
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::string_symbol())) {
+ } else if (check->Equals(isolate()->heap()->string_symbol())) {
__ JumpIfSmi(eax, if_false);
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
__ j(above_equal, if_false);
@@ -3948,13 +3982,13 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
__ test_b(FieldOperand(edx, Map::kBitFieldOffset),
1 << Map::kIsUndetectable);
Split(zero, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::boolean_symbol())) {
- __ cmp(eax, Factory::true_value());
+ } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
+ __ cmp(eax, isolate()->factory()->true_value());
__ j(equal, if_true);
- __ cmp(eax, Factory::false_value());
+ __ cmp(eax, isolate()->factory()->false_value());
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::undefined_symbol())) {
- __ cmp(eax, Factory::undefined_value());
+ } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
+ __ cmp(eax, isolate()->factory()->undefined_value());
__ j(equal, if_true);
__ JumpIfSmi(eax, if_false);
// Check for undetectable objects => true.
@@ -3962,13 +3996,13 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
__ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
__ test(ecx, Immediate(1 << Map::kIsUndetectable));
Split(not_zero, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::function_symbol())) {
+ } else if (check->Equals(isolate()->heap()->function_symbol())) {
__ JumpIfSmi(eax, if_false);
__ CmpObjectType(eax, FIRST_FUNCTION_CLASS_TYPE, edx);
Split(above_equal, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::object_symbol())) {
+ } else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(eax, if_false);
- __ cmp(eax, Factory::null_value());
+ __ cmp(eax, isolate()->factory()->null_value());
__ j(equal, if_true);
__ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, edx);
__ j(below, if_false);
@@ -4016,7 +4050,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
VisitForStackValue(expr->right());
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
- __ cmp(eax, Factory::true_value());
+ __ cmp(eax, isolate()->factory()->true_value());
Split(equal, if_true, if_false, fall_through);
break;
@@ -4109,12 +4143,12 @@ void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
VisitForAccumulatorValue(expr->expression());
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- __ cmp(eax, Factory::null_value());
+ __ cmp(eax, isolate()->factory()->null_value());
if (expr->is_strict()) {
Split(equal, if_true, if_false, fall_through);
} else {
__ j(equal, if_true);
- __ cmp(eax, Factory::undefined_value());
+ __ cmp(eax, isolate()->factory()->undefined_value());
__ j(equal, if_true);
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, if_false);
@@ -4149,16 +4183,16 @@ void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
mode == RelocInfo::CODE_TARGET_CONTEXT);
switch (ic->kind()) {
case Code::LOAD_IC:
- __ IncrementCounter(&Counters::named_load_full, 1);
+ __ IncrementCounter(isolate()->counters()->named_load_full(), 1);
break;
case Code::KEYED_LOAD_IC:
- __ IncrementCounter(&Counters::keyed_load_full, 1);
+ __ IncrementCounter(isolate()->counters()->keyed_load_full(), 1);
break;
case Code::STORE_IC:
- __ IncrementCounter(&Counters::named_store_full, 1);
+ __ IncrementCounter(isolate()->counters()->named_store_full(), 1);
break;
case Code::KEYED_STORE_IC:
- __ IncrementCounter(&Counters::keyed_store_full, 1);
+ __ IncrementCounter(isolate()->counters()->keyed_store_full(), 1);
default:
break;
}
@@ -4190,18 +4224,19 @@ void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
+ Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
- __ IncrementCounter(&Counters::named_load_full, 1);
+ __ IncrementCounter(counters->named_load_full(), 1);
break;
case Code::KEYED_LOAD_IC:
- __ IncrementCounter(&Counters::keyed_load_full, 1);
+ __ IncrementCounter(counters->keyed_load_full(), 1);
break;
case Code::STORE_IC:
- __ IncrementCounter(&Counters::named_store_full, 1);
+ __ IncrementCounter(counters->named_store_full(), 1);
break;
case Code::KEYED_STORE_IC:
- __ IncrementCounter(&Counters::keyed_store_full, 1);
+ __ IncrementCounter(counters->keyed_store_full(), 1);
default:
break;
}
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 6b9e7496..48ffc735 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -93,7 +93,7 @@ static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
__ j(not_zero, miss, not_taken);
__ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
- __ CheckMap(r0, Factory::hash_table_map(), miss, true);
+ __ CheckMap(r0, FACTORY->hash_table_map(), miss, true);
}
@@ -475,7 +475,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm,
__ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
if (not_fast_array != NULL) {
// Check that the object is in fast mode and writable.
- __ CheckMap(scratch, Factory::fixed_array_map(), not_fast_array, true);
+ __ CheckMap(scratch, FACTORY->fixed_array_map(), not_fast_array, true);
} else {
__ AssertFastElements(scratch);
}
@@ -485,7 +485,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm,
// Fast case: Do the load.
ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
__ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
- __ cmp(Operand(scratch), Immediate(Factory::the_hole_value()));
+ __ cmp(Operand(scratch), Immediate(FACTORY->the_hole_value()));
// In case the loaded value is the_hole we have to consult GetProperty
// to ensure the prototype chain is searched.
__ j(equal, out_of_range);
@@ -530,7 +530,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// -- esp[0] : return address
// -----------------------------------
Label slow, check_string, index_smi, index_string, property_array_property;
- Label check_pixel_array, probe_dictionary, check_number_dictionary;
+ Label probe_dictionary, check_number_dictionary;
// Check that the key is a smi.
__ test(eax, Immediate(kSmiTagMask));
@@ -546,7 +546,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// now in ecx.
__ test_b(FieldOperand(ecx, Map::kBitField2Offset),
1 << Map::kHasFastElements);
- __ j(zero, &check_pixel_array, not_taken);
+ __ j(zero, &check_number_dictionary, not_taken);
GenerateFastArrayLoad(masm,
edx,
@@ -555,27 +555,22 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
eax,
NULL,
&slow);
- __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
+ Isolate* isolate = masm->isolate();
+ Counters* counters = isolate->counters();
+ __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
__ ret(0);
- __ bind(&check_pixel_array);
- GenerateFastPixelArrayLoad(masm,
- edx,
- eax,
- ecx,
- ebx,
- eax,
- &check_number_dictionary,
- NULL,
- &slow);
-
__ bind(&check_number_dictionary);
+ __ mov(ebx, eax);
+ __ SmiUntag(ebx);
+ __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
+
// Check whether the elements is a number dictionary.
// edx: receiver
// ebx: untagged index
// eax: key
// ecx: elements
- __ CheckMap(ecx, Factory::hash_table_map(), &slow, true);
+ __ CheckMap(ecx, isolate->factory()->hash_table_map(), &slow, true);
Label slow_pop_receiver;
// Push receiver on the stack to free up a register for the dictionary
// probing.
@@ -600,7 +595,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Slow case: jump to runtime.
// edx: receiver
// eax: key
- __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
+ __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
GenerateRuntimeGetProperty(masm);
__ bind(&check_string);
@@ -613,7 +608,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// cache. Otherwise probe the dictionary.
__ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
__ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
- Immediate(Factory::hash_table_map()));
+ Immediate(isolate->factory()->hash_table_map()));
__ j(equal, &probe_dictionary);
// Load the map of the receiver, compute the keyed lookup cache hash
@@ -628,8 +623,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Load the key (consisting of map and symbol) from the cache and
// check for match.
- ExternalReference cache_keys
- = ExternalReference::keyed_lookup_cache_keys();
+ ExternalReference cache_keys =
+ ExternalReference::keyed_lookup_cache_keys(masm->isolate());
__ mov(edi, ecx);
__ shl(edi, kPointerSizeLog2 + 1);
__ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
@@ -643,8 +638,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// ebx : receiver's map
// eax : key
// ecx : lookup cache index
- ExternalReference cache_field_offsets
- = ExternalReference::keyed_lookup_cache_field_offsets();
+ ExternalReference cache_field_offsets =
+ ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
__ mov(edi,
Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
__ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
@@ -655,7 +650,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
__ add(ecx, Operand(edi));
__ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
- __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
+ __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
__ ret(0);
// Load property array property.
@@ -663,7 +658,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
__ mov(eax, FieldOperand(eax, edi, times_pointer_size,
FixedArray::kHeaderSize));
- __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
+ __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
__ ret(0);
// Do a quick inline probe of the receiver's dictionary, if it
@@ -675,7 +670,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
- __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
+ __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
__ ret(0);
__ bind(&index_string);
@@ -752,8 +747,9 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
__ push(ecx); // return address
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(
- IC_Utility(kKeyedLoadPropertyWithInterceptor));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
+ masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
__ bind(&slow);
@@ -769,7 +765,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
- Label slow, fast, array, extra, check_pixel_array;
+ Label slow, fast, array, extra;
// Check that the object isn't a smi.
__ test(edx, Immediate(kSmiTagMask));
@@ -796,7 +792,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// ecx: key (a smi)
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
// Check that the object is in fast mode and writable.
- __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
+ __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true);
__ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
__ j(below, &fast, taken);
@@ -804,24 +800,6 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
__ bind(&slow);
GenerateRuntimeSetProperty(masm, strict_mode);
- // Check whether the elements is a pixel array.
- __ bind(&check_pixel_array);
- // eax: value
- // ecx: key (a smi)
- // edx: receiver
- // edi: elements array
- GenerateFastPixelArrayStore(masm,
- edx,
- ecx,
- eax,
- edi,
- ebx,
- false,
- NULL,
- &slow,
- &slow,
- &slow);
-
// Extra capacity case: Check if there is extra capacity to
// perform the store and update the length. Used for adding one
// element to the array by writing to array[array.length].
@@ -847,7 +825,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// edx: receiver, a JSArray
// ecx: key, a smi.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
- __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
+ __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true);
// Check the key against the length in the array, compute the
// address to store into and fall through to fast case.
@@ -886,7 +864,8 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
Code::kNoExtraICState,
NORMAL,
argc);
- StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
+ Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
+ eax);
// If the stub cache probing failed, the receiver might be a value.
// For value objects, we use the map of the prototype objects for
@@ -913,9 +892,9 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Check for boolean.
__ bind(&non_string);
- __ cmp(edx, Factory::true_value());
+ __ cmp(edx, FACTORY->true_value());
__ j(equal, &boolean, not_taken);
- __ cmp(edx, Factory::false_value());
+ __ cmp(edx, FACTORY->false_value());
__ j(not_equal, &miss, taken);
__ bind(&boolean);
StubCompiler::GenerateLoadGlobalFunctionPrototype(
@@ -923,7 +902,8 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Probe the stub cache for the value object.
__ bind(&probe);
- StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
+ Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
+ no_reg);
__ bind(&miss);
}
@@ -989,10 +969,11 @@ static void GenerateCallMiss(MacroAssembler* masm,
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
+ Counters* counters = masm->isolate()->counters();
if (id == IC::kCallIC_Miss) {
- __ IncrementCounter(&Counters::call_miss, 1);
+ __ IncrementCounter(counters->call_miss(), 1);
} else {
- __ IncrementCounter(&Counters::keyed_call_miss, 1);
+ __ IncrementCounter(counters->keyed_call_miss(), 1);
}
// Get the receiver of the function from the stack; 1 ~ return address.
@@ -1008,7 +989,7 @@ static void GenerateCallMiss(MacroAssembler* masm,
// Call the entry.
CEntryStub stub(1);
__ mov(eax, Immediate(2));
- __ mov(ebx, Immediate(ExternalReference(IC_Utility(id))));
+ __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
__ CallStub(&stub);
// Move result to edi and exit the internal frame.
@@ -1114,7 +1095,9 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
GenerateFastArrayLoad(
masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
- __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1);
+ Isolate* isolate = masm->isolate();
+ Counters* counters = isolate->counters();
+ __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
__ bind(&do_call);
// receiver in edx is not used after this point.
@@ -1126,14 +1109,14 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// eax: elements
// ecx: smi key
// Check whether the elements is a number dictionary.
- __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true);
+ __ CheckMap(eax, isolate->factory()->hash_table_map(), &slow_load, true);
__ mov(ebx, ecx);
__ SmiUntag(ebx);
// ebx: untagged index
// Receiver in edx will be clobbered, need to reload it on miss.
GenerateNumberDictionaryLoad(
masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
- __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1);
+ __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
__ jmp(&do_call);
__ bind(&slow_reload_receiver);
@@ -1142,7 +1125,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
__ bind(&slow_load);
// This branch is taken when calling KeyedCallIC_Miss is neither required
// nor beneficial.
- __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1);
+ __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
__ EnterInternalFrame();
__ push(ecx); // save the key
__ push(edx); // pass the receiver
@@ -1164,14 +1147,17 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
__ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
- __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true);
+ __ CheckMap(ebx,
+ isolate->factory()->hash_table_map(),
+ &lookup_monomorphic_cache,
+ true);
GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
- __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
+ __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
__ jmp(&do_call);
__ bind(&lookup_monomorphic_cache);
- __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1);
+ __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
// Fall through on miss.
@@ -1182,7 +1168,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// - the value loaded is not a function,
// - there is hope that the runtime will create a monomorphic call stub
// that will get fetched next time.
- __ IncrementCounter(&Counters::keyed_call_generic_slow, 1);
+ __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
GenerateMiss(masm, argc);
__ bind(&index_string);
@@ -1237,7 +1223,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
NOT_IN_LOOP,
MONOMORPHIC);
- StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
+ Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, eax, ecx, ebx,
+ edx);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -1272,7 +1259,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
// -- esp[0] : return address
// -----------------------------------
- __ IncrementCounter(&Counters::load_miss, 1);
+ __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
__ pop(ebx);
__ push(eax); // receiver
@@ -1280,7 +1267,8 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
__ push(ebx); // return address
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
@@ -1400,7 +1388,7 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
// (-1) or we should be clearing the inlined version.
ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 ||
*reinterpret_cast<int*>(offset_address) == -1 ||
- (offset == 0 && map == Heap::null_value()));
+ (offset == 0 && map == HEAP->null_value()));
*reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
// Patch the offset in the write-barrier code. The offset is the
@@ -1410,7 +1398,7 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
// (-1) or we should be clearing the inlined version.
ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt ||
*reinterpret_cast<int*>(offset_address) == -1 ||
- (offset == 0 && map == Heap::null_value()));
+ (offset == 0 && map == HEAP->null_value()));
*reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
return true;
@@ -1458,7 +1446,7 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// -- esp[0] : return address
// -----------------------------------
- __ IncrementCounter(&Counters::keyed_load_miss, 1);
+ __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
__ pop(ebx);
__ push(edx); // receiver
@@ -1466,7 +1454,8 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
__ push(ebx); // return address
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
@@ -1501,7 +1490,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
NOT_IN_LOOP,
MONOMORPHIC,
strict_mode);
- StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
+ Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
+ no_reg);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -1523,7 +1513,8 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
__ push(ebx);
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
@@ -1543,9 +1534,8 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
// -----------------------------------
//
// This accepts as a receiver anything JSObject::SetElementsLength accepts
- // (currently anything except for external and pixel arrays which means
- // anything with elements of FixedArray type.), but currently is restricted
- // to JSArray.
+ // (currently anything except for external arrays which means anything with
+ // elements of FixedArray type.), but currently is restricted to JSArray.
// Value must be a number, but only smis are accepted as the most common case.
Label miss;
@@ -1579,7 +1569,8 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
__ push(value);
__ push(scratch); // return address
- ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
__ bind(&miss);
@@ -1606,14 +1597,15 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
__ push(edx);
GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
__ Drop(1);
- __ IncrementCounter(&Counters::store_normal_hit, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->store_normal_hit(), 1);
__ ret(0);
__ bind(&restore_miss);
__ pop(edx);
__ bind(&miss);
- __ IncrementCounter(&Counters::store_normal_miss, 1);
+ __ IncrementCounter(counters->store_normal_miss(), 1);
GenerateMiss(masm);
}
@@ -1676,7 +1668,8 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
__ push(ebx);
// Do tail-call to runtime routine.
- ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 9dcca9ee..1691098f 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -31,6 +31,7 @@
#include "ia32/lithium-codegen-ia32.h"
#include "code-stubs.h"
+#include "deoptimizer.h"
#include "stub-cache.h"
namespace v8 {
@@ -43,20 +44,13 @@ class SafepointGenerator : public PostCallGenerator {
public:
SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers,
- int deoptimization_index,
- bool ensure_reloc_space = false)
+ int deoptimization_index)
: codegen_(codegen),
pointers_(pointers),
- deoptimization_index_(deoptimization_index),
- ensure_reloc_space_(ensure_reloc_space) { }
+ deoptimization_index_(deoptimization_index) {}
virtual ~SafepointGenerator() { }
virtual void Generate() {
- // Ensure that we have enough space in the reloc info to patch
- // this with calls when doing deoptimization.
- if (ensure_reloc_space_) {
- codegen_->EnsureRelocSpaceForDeoptimization();
- }
codegen_->RecordSafepoint(pointers_, deoptimization_index_);
}
@@ -64,7 +58,6 @@ class SafepointGenerator : public PostCallGenerator {
LCodeGen* codegen_;
LPointerMap* pointers_;
int deoptimization_index_;
- bool ensure_reloc_space_;
};
@@ -78,7 +71,6 @@ bool LCodeGen::GenerateCode() {
return GeneratePrologue() &&
GenerateBody() &&
GenerateDeferredCode() &&
- GenerateRelocPadding() &&
GenerateSafepointTable();
}
@@ -88,6 +80,7 @@ void LCodeGen::FinishCode(Handle<Code> code) {
code->set_stack_slots(StackSlotCount());
code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
PopulateDeoptimizationData(code);
+ Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
}
@@ -123,16 +116,6 @@ void LCodeGen::Comment(const char* format, ...) {
}
-bool LCodeGen::GenerateRelocPadding() {
- int reloc_size = masm()->relocation_writer_size();
- while (reloc_size < deoptimization_reloc_size.min_size) {
- __ RecordComment(RelocInfo::kFillerCommentString, true);
- reloc_size += RelocInfo::kMinRelocCommentSize;
- }
- return !is_aborted();
-}
-
-
bool LCodeGen::GeneratePrologue() {
ASSERT(is_generating());
@@ -385,22 +368,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
}
-void LCodeGen::EnsureRelocSpaceForDeoptimization() {
- // Since we patch the reloc info with RUNTIME_ENTRY calls every patch
- // site will take up 2 bytes + any pc-jumps.
- // We are conservative and always reserver 6 bytes in case where a
- // simple pc-jump is not enough.
- uint32_t pc_delta =
- masm()->pc_offset() - deoptimization_reloc_size.last_pc_offset;
- if (is_uintn(pc_delta, 6)) {
- deoptimization_reloc_size.min_size += 2;
- } else {
- deoptimization_reloc_size.min_size += 6;
- }
- deoptimization_reloc_size.last_pc_offset = masm()->pc_offset();
-}
-
-
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged) {
@@ -454,7 +421,6 @@ void LCodeGen::CallCode(Handle<Code> code,
}
__ call(code, mode);
- EnsureRelocSpaceForDeoptimization();
RegisterLazyDeoptimization(instr);
// Signal that we don't inline smi code before these stubs in the
@@ -466,7 +432,7 @@ void LCodeGen::CallCode(Handle<Code> code,
}
-void LCodeGen::CallRuntime(Runtime::Function* fun,
+void LCodeGen::CallRuntime(const Runtime::Function* fun,
int argc,
LInstruction* instr,
bool adjusted) {
@@ -479,6 +445,7 @@ void LCodeGen::CallRuntime(Runtime::Function* fun,
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
__ CallRuntime(fun, argc);
+
RegisterLazyDeoptimization(instr);
}
@@ -586,14 +553,14 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
if (length == 0) return;
ASSERT(FLAG_deopt);
Handle<DeoptimizationInputData> data =
- Factory::NewDeoptimizationInputData(length, TENURED);
+ factory()->NewDeoptimizationInputData(length, TENURED);
Handle<ByteArray> translations = translations_.CreateByteArray();
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
Handle<FixedArray> literals =
- Factory::NewFixedArray(deoptimization_literals_.length(), TENURED);
+ factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
for (int i = 0; i < deoptimization_literals_.length(); i++) {
literals->set(i, *deoptimization_literals_[i]);
}
@@ -743,16 +710,6 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
break;
}
- case CodeStub::StringCharAt: {
- StringCharAtStub stub;
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- break;
- }
- case CodeStub::MathPow: {
- MathPowStub stub;
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- break;
- }
case CodeStub::NumberToString: {
NumberToStringStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
@@ -786,41 +743,64 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
void LCodeGen::DoModI(LModI* instr) {
- LOperand* right = instr->InputAt(1);
- ASSERT(ToRegister(instr->result()).is(edx));
- ASSERT(ToRegister(instr->InputAt(0)).is(eax));
- ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
- ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
+ if (instr->hydrogen()->HasPowerOf2Divisor()) {
+ Register dividend = ToRegister(instr->InputAt(0));
- Register right_reg = ToRegister(right);
+ int32_t divisor =
+ HConstant::cast(instr->hydrogen()->right())->Integer32Value();
- // Check for x % 0.
- if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ test(right_reg, ToOperand(right));
- DeoptimizeIf(zero, instr->environment());
- }
+ if (divisor < 0) divisor = -divisor;
- // Sign extend to edx.
- __ cdq();
+ NearLabel positive_dividend, done;
+ __ test(dividend, Operand(dividend));
+ __ j(not_sign, &positive_dividend);
+ __ neg(dividend);
+ __ and_(dividend, divisor - 1);
+ __ neg(dividend);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ __ j(not_zero, &done);
+ DeoptimizeIf(no_condition, instr->environment());
+ }
+ __ bind(&positive_dividend);
+ __ and_(dividend, divisor - 1);
+ __ bind(&done);
+ } else {
+ LOperand* right = instr->InputAt(1);
+ ASSERT(ToRegister(instr->InputAt(0)).is(eax));
+ ASSERT(ToRegister(instr->result()).is(edx));
- // Check for (0 % -x) that will produce negative zero.
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- NearLabel positive_left;
- NearLabel done;
- __ test(eax, Operand(eax));
- __ j(not_sign, &positive_left);
- __ idiv(right_reg);
+ Register right_reg = ToRegister(right);
+ ASSERT(!right_reg.is(eax));
+ ASSERT(!right_reg.is(edx));
- // Test the remainder for 0, because then the result would be -0.
- __ test(edx, Operand(edx));
- __ j(not_zero, &done);
+ // Check for x % 0.
+ if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
+ __ test(right_reg, ToOperand(right));
+ DeoptimizeIf(zero, instr->environment());
+ }
- DeoptimizeIf(no_condition, instr->environment());
- __ bind(&positive_left);
- __ idiv(right_reg);
- __ bind(&done);
- } else {
- __ idiv(right_reg);
+ // Sign extend to edx.
+ __ cdq();
+
+ // Check for (0 % -x) that will produce negative zero.
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ NearLabel positive_left;
+ NearLabel done;
+ __ test(eax, Operand(eax));
+ __ j(not_sign, &positive_left);
+ __ idiv(right_reg);
+
+ // Test the remainder for 0, because then the result would be -0.
+ __ test(edx, Operand(edx));
+ __ j(not_zero, &done);
+
+ DeoptimizeIf(no_condition, instr->environment());
+ __ bind(&positive_left);
+ __ idiv(right_reg);
+ __ bind(&done);
+ } else {
+ __ idiv(right_reg);
+ }
}
}
@@ -880,7 +860,49 @@ void LCodeGen::DoMulI(LMulI* instr) {
}
if (right->IsConstantOperand()) {
- __ imul(left, left, ToInteger32(LConstantOperand::cast(right)));
+ // Try strength reductions on the multiplication.
+ // All replacement instructions are at most as long as the imul
+ // and have better latency.
+ int constant = ToInteger32(LConstantOperand::cast(right));
+ if (constant == -1) {
+ __ neg(left);
+ } else if (constant == 0) {
+ __ xor_(left, Operand(left));
+ } else if (constant == 2) {
+ __ add(left, Operand(left));
+ } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
+ // If we know that the multiplication can't overflow, it's safe to
+ // use instructions that don't set the overflow flag for the
+ // multiplication.
+ switch (constant) {
+ case 1:
+ // Do nothing.
+ break;
+ case 3:
+ __ lea(left, Operand(left, left, times_2, 0));
+ break;
+ case 4:
+ __ shl(left, 2);
+ break;
+ case 5:
+ __ lea(left, Operand(left, left, times_4, 0));
+ break;
+ case 8:
+ __ shl(left, 3);
+ break;
+ case 9:
+ __ lea(left, Operand(left, left, times_8, 0));
+ break;
+ case 16:
+ __ shl(left, 4);
+ break;
+ default:
+ __ imul(left, left, constant);
+ break;
+ }
+ } else {
+ __ imul(left, left, constant);
+ }
} else {
__ imul(left, ToOperand(right));
}
@@ -1040,7 +1062,7 @@ void LCodeGen::DoConstantD(LConstantD* instr) {
uint64_t int_val = BitCast<uint64_t, double>(v);
int32_t lower = static_cast<int32_t>(int_val);
int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
- if (CpuFeatures::IsSupported(SSE4_1)) {
+ if (isolate()->cpu_features()->IsSupported(SSE4_1)) {
CpuFeatures::Scope scope(SSE4_1);
if (lower != 0) {
__ Set(temp, Immediate(lower));
@@ -1086,10 +1108,10 @@ void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
}
-void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
+void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
- __ mov(result, FieldOperand(array, PixelArray::kLengthOffset));
+ __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
}
@@ -1171,7 +1193,9 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
__ PrepareCallCFunction(4, eax);
__ movdbl(Operand(esp, 0 * kDoubleSize), left);
__ movdbl(Operand(esp, 1 * kDoubleSize), right);
- __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4);
+ __ CallCFunction(
+ ExternalReference::double_fp_operation(Token::MOD, isolate()),
+ 4);
// Return value is in st(0) on ia32.
// Store it into the (fixed) result register.
@@ -1243,17 +1267,17 @@ void LCodeGen::DoBranch(LBranch* instr) {
ASSERT(r.IsTagged());
Register reg = ToRegister(instr->InputAt(0));
if (instr->hydrogen()->type().IsBoolean()) {
- __ cmp(reg, Factory::true_value());
+ __ cmp(reg, factory()->true_value());
EmitBranch(true_block, false_block, equal);
} else {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
- __ cmp(reg, Factory::undefined_value());
+ __ cmp(reg, factory()->undefined_value());
__ j(equal, false_label);
- __ cmp(reg, Factory::true_value());
+ __ cmp(reg, factory()->true_value());
__ j(equal, true_label);
- __ cmp(reg, Factory::false_value());
+ __ cmp(reg, factory()->false_value());
__ j(equal, false_label);
__ test(reg, Operand(reg));
__ j(equal, false_label);
@@ -1263,7 +1287,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
// Test for double values. Zero is false.
NearLabel call_stub;
__ cmp(FieldOperand(reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
__ j(not_equal, &call_stub);
__ fldz();
__ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
@@ -1293,7 +1317,7 @@ void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
// Perform stack overflow check if this goto needs it before jumping.
if (deferred_stack_check != NULL) {
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, chunk_->GetAssemblyLabel(block));
__ jmp(deferred_stack_check->entry());
@@ -1386,11 +1410,11 @@ void LCodeGen::DoCmpID(LCmpID* instr) {
NearLabel done;
Condition cc = TokenToCondition(instr->op(), instr->is_double());
- __ mov(ToRegister(result), Factory::true_value());
+ __ mov(ToRegister(result), factory()->true_value());
__ j(cc, &done);
__ bind(&unordered);
- __ mov(ToRegister(result), Factory::false_value());
+ __ mov(ToRegister(result), factory()->false_value());
__ bind(&done);
}
@@ -1421,10 +1445,10 @@ void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
Register result = ToRegister(instr->result());
__ cmp(left, Operand(right));
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
NearLabel done;
__ j(equal, &done);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
@@ -1447,17 +1471,17 @@ void LCodeGen::DoIsNull(LIsNull* instr) {
// TODO(fsc): If the expression is known to be a smi, then it's
// definitely not null. Materialize false.
- __ cmp(reg, Factory::null_value());
+ __ cmp(reg, factory()->null_value());
if (instr->is_strict()) {
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
NearLabel done;
__ j(equal, &done);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
} else {
NearLabel true_value, false_value, done;
__ j(equal, &true_value);
- __ cmp(reg, Factory::undefined_value());
+ __ cmp(reg, factory()->undefined_value());
__ j(equal, &true_value);
__ test(reg, Immediate(kSmiTagMask));
__ j(zero, &false_value);
@@ -1469,10 +1493,10 @@ void LCodeGen::DoIsNull(LIsNull* instr) {
__ test(scratch, Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, &true_value);
__ bind(&false_value);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ jmp(&done);
__ bind(&true_value);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ bind(&done);
}
}
@@ -1487,14 +1511,14 @@ void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
- __ cmp(reg, Factory::null_value());
+ __ cmp(reg, factory()->null_value());
if (instr->is_strict()) {
EmitBranch(true_block, false_block, equal);
} else {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
__ j(equal, true_label);
- __ cmp(reg, Factory::undefined_value());
+ __ cmp(reg, factory()->undefined_value());
__ j(equal, true_label);
__ test(reg, Immediate(kSmiTagMask));
__ j(zero, false_label);
@@ -1521,7 +1545,7 @@ Condition LCodeGen::EmitIsObject(Register input,
__ test(input, Immediate(kSmiTagMask));
__ j(equal, is_not_object);
- __ cmp(input, Factory::null_value());
+ __ cmp(input, isolate()->factory()->null_value());
__ j(equal, is_object);
__ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
@@ -1548,11 +1572,11 @@ void LCodeGen::DoIsObject(LIsObject* instr) {
__ j(true_cond, &is_true);
__ bind(&is_false);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ jmp(&done);
__ bind(&is_true);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ bind(&done);
}
@@ -1580,10 +1604,10 @@ void LCodeGen::DoIsSmi(LIsSmi* instr) {
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
__ test(input, Immediate(kSmiTagMask));
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
NearLabel done;
__ j(zero, &done);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
@@ -1629,10 +1653,10 @@ void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
__ j(zero, &is_false);
__ CmpObjectType(input, TestType(instr->hydrogen()), result);
__ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ jmp(&done);
__ bind(&is_false);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
@@ -1672,12 +1696,12 @@ void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
Register result = ToRegister(instr->result());
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ test(FieldOperand(input, String::kHashFieldOffset),
Immediate(String::kContainsCachedArrayIndexMask));
NearLabel done;
__ j(zero, &done);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
@@ -1766,11 +1790,11 @@ void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
__ j(not_equal, &is_false);
__ bind(&is_true);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ jmp(&done);
__ bind(&is_false);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ bind(&done);
}
@@ -1818,10 +1842,10 @@ void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
NearLabel true_value, done;
__ test(eax, Operand(eax));
__ j(zero, &true_value);
- __ mov(ToRegister(instr->result()), Factory::false_value());
+ __ mov(ToRegister(instr->result()), factory()->false_value());
__ jmp(&done);
__ bind(&true_value);
- __ mov(ToRegister(instr->result()), Factory::true_value());
+ __ mov(ToRegister(instr->result()), factory()->true_value());
__ bind(&done);
}
@@ -1873,16 +1897,16 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
Register map = ToRegister(instr->TempAt(0));
__ mov(map, FieldOperand(object, HeapObject::kMapOffset));
__ bind(deferred->map_check()); // Label for calculating code patching.
- __ cmp(map, Factory::the_hole_value()); // Patched to cached map.
+ __ cmp(map, factory()->the_hole_value()); // Patched to cached map.
__ j(not_equal, &cache_miss, not_taken);
- __ mov(eax, Factory::the_hole_value()); // Patched to either true or false.
+ __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
__ jmp(&done);
// The inlined call site cache did not match. Check for null and string
// before calling the deferred code.
__ bind(&cache_miss);
// Null is not an instance of anything.
- __ cmp(object, Factory::null_value());
+ __ cmp(object, factory()->null_value());
__ j(equal, &false_result);
// String values are not instances of anything.
@@ -1893,7 +1917,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
__ jmp(deferred->entry());
__ bind(&false_result);
- __ mov(ToRegister(instr->result()), Factory::false_value());
+ __ mov(ToRegister(instr->result()), factory()->false_value());
// Here result has either true or false. Deferred code also produces true or
// false object.
@@ -1965,10 +1989,10 @@ void LCodeGen::DoCmpT(LCmpT* instr) {
NearLabel true_value, done;
__ test(eax, Operand(eax));
__ j(condition, &true_value);
- __ mov(ToRegister(instr->result()), Factory::false_value());
+ __ mov(ToRegister(instr->result()), factory()->false_value());
__ jmp(&done);
__ bind(&true_value);
- __ mov(ToRegister(instr->result()), Factory::true_value());
+ __ mov(ToRegister(instr->result()), factory()->true_value());
__ bind(&done);
}
@@ -2012,7 +2036,7 @@ void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
Register result = ToRegister(instr->result());
__ mov(result, Operand::Cell(instr->hydrogen()->cell()));
if (instr->hydrogen()->check_hole_value()) {
- __ cmp(result, Factory::the_hole_value());
+ __ cmp(result, factory()->the_hole_value());
DeoptimizeIf(equal, instr->environment());
}
}
@@ -2027,7 +2051,7 @@ void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
// to update the property details in the property dictionary to mark
// it as no longer deleted. We deoptimize in that case.
if (instr->hydrogen()->check_hole_value()) {
- __ cmp(cell_operand, Factory::the_hole_value());
+ __ cmp(cell_operand, factory()->the_hole_value());
DeoptimizeIf(equal, instr->environment());
}
@@ -2056,7 +2080,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
- Register object = ToRegister(instr->InputAt(0));
+ Register object = ToRegister(instr->object());
Register result = ToRegister(instr->result());
if (instr->hydrogen()->is_in_object()) {
__ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
@@ -2067,13 +2091,76 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
}
+void LCodeGen::EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name) {
+ LookupResult lookup;
+ type->LookupInDescriptors(NULL, *name, &lookup);
+ ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
+ int index = lookup.GetLocalFieldIndexFromMap(*type);
+ int offset = index * kPointerSize;
+ if (index < 0) {
+ // Negative property indices are in-object properties, indexed
+ // from the end of the fixed part of the object.
+ __ mov(result, FieldOperand(object, offset + type->instance_size()));
+ } else {
+ // Non-negative property indices are in the properties array.
+ __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
+ __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
+ }
+}
+
+
+void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
+ Register object = ToRegister(instr->object());
+ Register result = ToRegister(instr->result());
+
+ int map_count = instr->hydrogen()->types()->length();
+ Handle<String> name = instr->hydrogen()->name();
+ if (map_count == 0) {
+ ASSERT(instr->hydrogen()->need_generic());
+ __ mov(ecx, name);
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
+ } else {
+ NearLabel done;
+ for (int i = 0; i < map_count - 1; ++i) {
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ NearLabel next;
+ __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ __ j(not_equal, &next);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&next);
+ }
+ Handle<Map> map = instr->hydrogen()->types()->last();
+ __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ if (instr->hydrogen()->need_generic()) {
+ NearLabel generic;
+ __ j(not_equal, &generic);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&generic);
+ __ mov(ecx, name);
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
+ } else {
+ DeoptimizeIf(not_equal, instr->environment());
+ EmitLoadField(result, object, map, name);
+ }
+ __ bind(&done);
+ }
+}
+
+
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(eax));
ASSERT(ToRegister(instr->result()).is(eax));
__ mov(ecx, instr->name());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2098,7 +2185,7 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
// Check that the function has a prototype or an initial map.
- __ cmp(Operand(result), Immediate(Factory::the_hole_value()));
+ __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
DeoptimizeIf(equal, instr->environment());
// If the function does not have an initial map, we're done.
@@ -2127,24 +2214,30 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
if (FLAG_debug_code) {
NearLabel done;
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(factory()->fixed_array_map()));
__ j(equal, &done);
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::pixel_array_map()));
+ Immediate(factory()->fixed_cow_array_map()));
__ j(equal, &done);
- __ cmp(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::fixed_cow_array_map()));
- __ Check(equal, "Check for fast elements or pixel array failed.");
+ Register temp((result.is(eax)) ? ebx : eax);
+ __ push(temp);
+ __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
+ __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
+ __ sub(Operand(temp), Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
+ __ cmp(Operand(temp), Immediate(kExternalArrayTypeCount));
+ __ pop(temp);
+ __ Check(below, "Check for fast elements or pixel array failed.");
__ bind(&done);
}
}
-void LCodeGen::DoLoadPixelArrayExternalPointer(
- LLoadPixelArrayExternalPointer* instr) {
+void LCodeGen::DoLoadExternalArrayPointer(
+ LLoadExternalArrayPointer* instr) {
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0));
- __ mov(result, FieldOperand(input, PixelArray::kExternalPointerOffset));
+ __ mov(result, FieldOperand(input,
+ ExternalArray::kExternalPointerOffset));
}
@@ -2176,19 +2269,52 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
FixedArray::kHeaderSize));
// Check for the hole value.
- __ cmp(result, Factory::the_hole_value());
+ __ cmp(result, factory()->the_hole_value());
DeoptimizeIf(equal, instr->environment());
}
-void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
+void LCodeGen::DoLoadKeyedSpecializedArrayElement(
+ LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
- Register result = ToRegister(instr->result());
- ASSERT(result.is(external_pointer));
-
- // Load the result.
- __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
+ ExternalArrayType array_type = instr->array_type();
+ if (array_type == kExternalFloatArray) {
+ XMMRegister result(ToDoubleRegister(instr->result()));
+ __ movss(result, Operand(external_pointer, key, times_4, 0));
+ __ cvtss2sd(result, result);
+ } else {
+ Register result(ToRegister(instr->result()));
+ switch (array_type) {
+ case kExternalByteArray:
+ __ movsx_b(result, Operand(external_pointer, key, times_1, 0));
+ break;
+ case kExternalUnsignedByteArray:
+ case kExternalPixelArray:
+ __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
+ break;
+ case kExternalShortArray:
+ __ movsx_w(result, Operand(external_pointer, key, times_2, 0));
+ break;
+ case kExternalUnsignedShortArray:
+ __ movzx_w(result, Operand(external_pointer, key, times_2, 0));
+ break;
+ case kExternalIntArray:
+ __ mov(result, Operand(external_pointer, key, times_4, 0));
+ break;
+ case kExternalUnsignedIntArray:
+ __ mov(result, Operand(external_pointer, key, times_4, 0));
+ __ test(Operand(result), Immediate(0x80000000));
+ // TODO(danno): we could be more clever here, perhaps having a special
+ // version of the stub that detects if the overflow case actually
+ // happens, and generate code that returns a double rather than int.
+ DeoptimizeIf(not_zero, instr->environment());
+ break;
+ case kExternalFloatArray:
+ UNREACHABLE();
+ break;
+ }
+ }
}
@@ -2197,7 +2323,7 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(edx));
ASSERT(ToRegister(instr->key()).is(eax));
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2262,9 +2388,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
// If the receiver is null or undefined, we have to pass the global object
// as a receiver.
NearLabel global_object, receiver_ok;
- __ cmp(receiver, Factory::null_value());
+ __ cmp(receiver, factory()->null_value());
__ j(equal, &global_object);
- __ cmp(receiver, Factory::undefined_value());
+ __ cmp(receiver, factory()->undefined_value());
__ j(equal, &global_object);
// The receiver should be a JS object.
@@ -2311,8 +2437,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
RegisterEnvironmentForDeoptimization(env);
SafepointGenerator safepoint_generator(this,
pointers,
- env->deoptimization_index(),
- true);
+ env->deoptimization_index());
v8::internal::ParameterCount actual(eax);
__ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
}
@@ -2384,7 +2509,6 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
__ CallSelf();
} else {
__ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
- EnsureRelocSpaceForDeoptimization();
}
// Setup deoptimization.
@@ -2402,7 +2526,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
Register input_reg = ToRegister(instr->InputAt(0));
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
DeoptimizeIf(not_equal, instr->environment());
Label done;
@@ -2583,13 +2707,15 @@ void LCodeGen::DoPower(LPower* instr) {
LOperand* right = instr->InputAt(1);
DoubleRegister result_reg = ToDoubleRegister(instr->result());
Representation exponent_type = instr->hydrogen()->right()->representation();
+
if (exponent_type.IsDouble()) {
// It is safe to use ebx directly since the instruction is marked
// as a call.
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
- __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+ __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
+ 4);
} else if (exponent_type.IsInteger32()) {
// It is safe to use ebx directly since the instruction is marked
// as a call.
@@ -2597,7 +2723,8 @@ void LCodeGen::DoPower(LPower* instr) {
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
- __ CallCFunction(ExternalReference::power_double_int_function(), 4);
+ __ CallCFunction(ExternalReference::power_double_int_function(isolate()),
+ 4);
} else {
ASSERT(exponent_type.IsTagged());
CpuFeatures::Scope scope(SSE2);
@@ -2622,7 +2749,8 @@ void LCodeGen::DoPower(LPower* instr) {
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
- __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+ __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
+ 4);
}
// Return value is in st(0) on ia32.
@@ -2697,7 +2825,8 @@ void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->
+ ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2707,7 +2836,8 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->
+ ComputeCallInitialize(arity, NOT_IN_LOOP);
__ mov(ecx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2729,7 +2859,8 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->
+ ComputeCallInitialize(arity, NOT_IN_LOOP);
__ mov(ecx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
}
@@ -2747,7 +2878,7 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
ASSERT(ToRegister(instr->constructor()).is(edi));
ASSERT(ToRegister(instr->result()).is(eax));
- Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
__ Set(eax, Immediate(instr->arity()));
CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
}
@@ -2794,9 +2925,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
ASSERT(ToRegister(instr->value()).is(eax));
__ mov(ecx, instr->name());
- Handle<Code> ic(Builtins::builtin(
- info_->is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = info_->is_strict()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2807,22 +2938,52 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
}
-void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
+void LCodeGen::DoStoreKeyedSpecializedArrayElement(
+ LStoreKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
- Register value = ToRegister(instr->value());
- ASSERT(ToRegister(instr->TempAt(0)).is(eax));
-
- __ mov(eax, value);
- { // Clamp the value to [0..255].
- NearLabel done;
- __ test(eax, Immediate(0xFFFFFF00));
- __ j(zero, &done);
- __ setcc(negative, eax); // 1 if negative, 0 if positive.
- __ dec_b(eax); // 0 if negative, 255 if positive.
- __ bind(&done);
+ ExternalArrayType array_type = instr->array_type();
+ if (array_type == kExternalFloatArray) {
+ __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
+ __ movss(Operand(external_pointer, key, times_4, 0), xmm0);
+ } else {
+ Register value = ToRegister(instr->value());
+ switch (array_type) {
+ case kExternalPixelArray: {
+ // Clamp the value to [0..255].
+ Register temp = ToRegister(instr->TempAt(0));
+ // The dec_b below requires that the clamped value is in a byte
+ // register. eax is an arbitrary choice to satisfy this requirement, we
+ // hinted the register allocator to give us eax when building the
+ // instruction.
+ ASSERT(temp.is(eax));
+ __ mov(temp, ToRegister(instr->value()));
+ NearLabel done;
+ __ test(temp, Immediate(0xFFFFFF00));
+ __ j(zero, &done);
+ __ setcc(negative, temp); // 1 if negative, 0 if positive.
+ __ dec_b(temp); // 0 if negative, 255 if positive.
+ __ bind(&done);
+ __ mov_b(Operand(external_pointer, key, times_1, 0), temp);
+ break;
+ }
+ case kExternalByteArray:
+ case kExternalUnsignedByteArray:
+ __ mov_b(Operand(external_pointer, key, times_1, 0), value);
+ break;
+ case kExternalShortArray:
+ case kExternalUnsignedShortArray:
+ __ mov_w(Operand(external_pointer, key, times_2, 0), value);
+ break;
+ case kExternalIntArray:
+ case kExternalUnsignedIntArray:
+ __ mov(Operand(external_pointer, key, times_4, 0), value);
+ break;
+ case kExternalFloatArray:
+ UNREACHABLE();
+ break;
+ }
}
- __ mov_b(Operand(external_pointer, key, times_1, 0), eax);
}
@@ -2864,9 +3025,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->key()).is(ecx));
ASSERT(ToRegister(instr->value()).is(eax));
- Handle<Code> ic(Builtins::builtin(
- info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = info_->is_strict()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2926,7 +3087,7 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// the case we would rather go to the runtime system now to flatten
// the string.
__ cmp(FieldOperand(string, ConsString::kSecondOffset),
- Immediate(Factory::empty_string()));
+ Immediate(factory()->empty_string()));
__ j(not_equal, deferred->entry());
// Get the first of the two strings and load its instance type.
__ mov(string, FieldOperand(string, ConsString::kFirstOffset));
@@ -3011,6 +3172,56 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
}
+void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
+ class DeferredStringCharFromCode: public LDeferredCode {
+ public:
+ DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
+ private:
+ LStringCharFromCode* instr_;
+ };
+
+ DeferredStringCharFromCode* deferred =
+ new DeferredStringCharFromCode(this, instr);
+
+ ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+ ASSERT(!char_code.is(result));
+
+ __ cmp(char_code, String::kMaxAsciiCharCode);
+ __ j(above, deferred->entry());
+ __ Set(result, Immediate(factory()->single_character_string_cache()));
+ __ mov(result, FieldOperand(result,
+ char_code, times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ cmp(result, factory()->undefined_value());
+ __ j(equal, deferred->entry());
+ __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+
+ // TODO(3095996): Get rid of this. For now, we need to make the
+ // result register contain a valid pointer because it is already
+ // contained in the register pointer map.
+ __ Set(result, Immediate(0));
+
+ __ PushSafepointRegisters();
+ __ SmiTag(char_code);
+ __ push(char_code);
+ __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
+ __ StoreToSafepointRegisterSlot(result, eax);
+ __ PopSafepointRegisters();
+}
+
+
void LCodeGen::DoStringLength(LStringLength* instr) {
Register string = ToRegister(instr->string());
Register result = ToRegister(instr->result());
@@ -3163,17 +3374,15 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
// Heap number map check.
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
__ j(equal, &heap_number);
- __ cmp(input_reg, Factory::undefined_value());
+ __ cmp(input_reg, factory()->undefined_value());
DeoptimizeIf(not_equal, env);
// Convert undefined to NaN.
- __ push(input_reg);
- __ mov(input_reg, Factory::nan_value());
- __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
- __ pop(input_reg);
+ ExternalReference nan = ExternalReference::address_of_nan();
+ __ movdbl(result_reg, Operand::StaticVariable(nan));
__ jmp(&done);
// Heap number to XMM conversion.
@@ -3206,19 +3415,19 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
// Heap number map check.
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
if (instr->truncating()) {
__ j(equal, &heap_number);
// Check for undefined. Undefined is converted to zero for truncating
// conversions.
- __ cmp(input_reg, Factory::undefined_value());
+ __ cmp(input_reg, factory()->undefined_value());
DeoptimizeIf(not_equal, instr->environment());
__ mov(input_reg, 0);
__ jmp(&done);
__ bind(&heap_number);
- if (CpuFeatures::IsSupported(SSE3)) {
+ if (isolate()->cpu_features()->IsSupported(SSE3)) {
CpuFeatures::Scope scope(SSE3);
NearLabel convert;
// Use more powerful conversion when sse3 is available.
@@ -3328,7 +3537,7 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
// the JS bitwise operations.
__ cvttsd2si(result_reg, Operand(input_reg));
__ cmp(result_reg, 0x80000000u);
- if (CpuFeatures::IsSupported(SSE3)) {
+ if (isolate()->cpu_features()->IsSupported(SSE3)) {
// This will deoptimize if the exponent of the input in out of range.
CpuFeatures::Scope scope(SSE3);
NearLabel convert, done;
@@ -3433,9 +3642,15 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
LOperand* input = instr->InputAt(0);
- ASSERT(input->IsRegister());
__ test(ToRegister(input), Immediate(kSmiTagMask));
- DeoptimizeIf(instr->condition(), instr->environment());
+ DeoptimizeIf(not_zero, instr->environment());
+}
+
+
+void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
+ LOperand* input = instr->InputAt(0);
+ __ test(ToRegister(input), Immediate(kSmiTagMask));
+ DeoptimizeIf(zero, instr->environment());
}
@@ -3489,9 +3704,9 @@ void LCodeGen::DoCheckMap(LCheckMap* instr) {
void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
- if (Heap::InNewSpace(*object)) {
+ if (isolate()->heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
- Factory::NewJSGlobalPropertyCell(object);
+ isolate()->factory()->NewJSGlobalPropertyCell(object);
__ mov(result, Operand::Cell(cell));
} else {
__ mov(result, object);
@@ -3561,7 +3776,13 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
__ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
__ push(Immediate(instr->hydrogen()->constant_properties()));
- __ push(Immediate(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)));
+ int flags = instr->hydrogen()->fast_elements()
+ ? ObjectLiteral::kFastElements
+ : ObjectLiteral::kNoFlags;
+ flags |= instr->hydrogen()->has_function()
+ ? ObjectLiteral::kHasFunction
+ : ObjectLiteral::kNoFlags;
+ __ push(Immediate(Smi::FromInt(flags)));
// Pick the right runtime function to call.
if (instr->hydrogen()->depth() > 1) {
@@ -3572,6 +3793,13 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
}
+void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
+ ASSERT(ToRegister(instr->InputAt(0)).is(eax));
+ __ push(eax);
+ CallRuntime(Runtime::kToFastProperties, 1, instr);
+}
+
+
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
NearLabel materialized;
// Registers will be used as follows:
@@ -3584,7 +3812,7 @@ void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
int literal_offset = FixedArray::kHeaderSize +
instr->hydrogen()->literal_index() * kPointerSize;
__ mov(ebx, FieldOperand(ecx, literal_offset));
- __ cmp(ebx, Factory::undefined_value());
+ __ cmp(ebx, factory()->undefined_value());
__ j(not_equal, &materialized);
// Create regexp literal using runtime function
@@ -3629,16 +3857,17 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
// space for nested functions that don't need literals cloning.
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (shared_info->num_literals() == 0 && !pretenure) {
- FastNewClosureStub stub;
+ if (!pretenure && shared_info->num_literals() == 0) {
+ FastNewClosureStub stub(
+ shared_info->strict_mode() ? kStrictMode : kNonStrictMode);
__ push(Immediate(shared_info));
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
} else {
__ push(Operand(ebp, StandardFrameConstants::kContextOffset));
__ push(Immediate(shared_info));
__ push(Immediate(pretenure
- ? Factory::true_value()
- : Factory::false_value()));
+ ? factory()->true_value()
+ : factory()->false_value()));
CallRuntime(Runtime::kNewClosure, 3, instr, false);
}
}
@@ -3668,11 +3897,11 @@ void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
instr->type_literal());
__ j(final_branch_condition, &true_label);
__ bind(&false_label);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ jmp(&done);
__ bind(&true_label);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ bind(&done);
}
@@ -3699,13 +3928,13 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
Register input,
Handle<String> type_name) {
Condition final_branch_condition = no_condition;
- if (type_name->Equals(Heap::number_symbol())) {
+ if (type_name->Equals(heap()->number_symbol())) {
__ JumpIfSmi(input, true_label);
__ cmp(FieldOperand(input, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ factory()->heap_number_map());
final_branch_condition = equal;
- } else if (type_name->Equals(Heap::string_symbol())) {
+ } else if (type_name->Equals(heap()->string_symbol())) {
__ JumpIfSmi(input, false_label);
__ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
__ j(above_equal, false_label);
@@ -3713,14 +3942,14 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
1 << Map::kIsUndetectable);
final_branch_condition = zero;
- } else if (type_name->Equals(Heap::boolean_symbol())) {
- __ cmp(input, Factory::true_value());
+ } else if (type_name->Equals(heap()->boolean_symbol())) {
+ __ cmp(input, factory()->true_value());
__ j(equal, true_label);
- __ cmp(input, Factory::false_value());
+ __ cmp(input, factory()->false_value());
final_branch_condition = equal;
- } else if (type_name->Equals(Heap::undefined_symbol())) {
- __ cmp(input, Factory::undefined_value());
+ } else if (type_name->Equals(heap()->undefined_symbol())) {
+ __ cmp(input, factory()->undefined_value());
__ j(equal, true_label);
__ JumpIfSmi(input, false_label);
// Check for undetectable objects => true.
@@ -3729,7 +3958,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
1 << Map::kIsUndetectable);
final_branch_condition = not_zero;
- } else if (type_name->Equals(Heap::function_symbol())) {
+ } else if (type_name->Equals(heap()->function_symbol())) {
__ JumpIfSmi(input, false_label);
__ CmpObjectType(input, JS_FUNCTION_TYPE, input);
__ j(equal, true_label);
@@ -3737,9 +3966,9 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
__ CmpInstanceType(input, JS_REGEXP_TYPE);
final_branch_condition = equal;
- } else if (type_name->Equals(Heap::object_symbol())) {
+ } else if (type_name->Equals(heap()->object_symbol())) {
__ JumpIfSmi(input, false_label);
- __ cmp(input, Factory::null_value());
+ __ cmp(input, factory()->null_value());
__ j(equal, true_label);
// Regular expressions => 'function', not 'object'.
__ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, input);
@@ -3770,11 +3999,11 @@ void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
EmitIsConstructCall(result);
__ j(equal, &true_label);
- __ mov(result, Factory::false_value());
+ __ mov(result, factory()->false_value());
__ jmp(&done);
__ bind(&true_label);
- __ mov(result, Factory::true_value());
+ __ mov(result, factory()->true_value());
__ bind(&done);
}
@@ -3838,8 +4067,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
// builtin)
SafepointGenerator safepoint_generator(this,
pointers,
- env->deoptimization_index(),
- true);
+ env->deoptimization_index());
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ push(Immediate(Smi::FromInt(strict_mode_flag())));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
@@ -3849,7 +4077,8 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
void LCodeGen::DoStackCheck(LStackCheck* instr) {
// Perform stack overflow check.
NearLabel done;
- ExternalReference stack_limit = ExternalReference::address_of_stack_limit();
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above_equal, &done);
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index ecd6caa3..4414e6a2 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -68,6 +68,9 @@ class LCodeGen BASE_EMBEDDED {
// Simple accessors.
MacroAssembler* masm() const { return masm_; }
CompilationInfo* info() const { return info_; }
+ Isolate* isolate() const { return info_->isolate(); }
+ Factory* factory() const { return isolate()->factory(); }
+ Heap* heap() const { return isolate()->heap(); }
// Support for converting LOperands to assembler types.
Operand ToOperand(LOperand* op) const;
@@ -95,6 +98,7 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
+ void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
@@ -162,11 +166,11 @@ class LCodeGen BASE_EMBEDDED {
void CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr,
bool adjusted = true);
- void CallRuntime(Runtime::Function* fun, int argc, LInstruction* instr,
+ void CallRuntime(const Runtime::Function* fun, int argc, LInstruction* instr,
bool adjusted = true);
void CallRuntime(Runtime::FunctionId id, int argc, LInstruction* instr,
bool adjusted = true) {
- Runtime::Function* function = Runtime::FunctionForId(id);
+ const Runtime::Function* function = Runtime::FunctionForId(id);
CallRuntime(function, argc, instr, adjusted);
}
@@ -242,6 +246,10 @@ class LCodeGen BASE_EMBEDDED {
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp);
+ void EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name);
LChunk* const chunk_;
MacroAssembler* const masm_;
diff --git a/src/ia32/lithium-gap-resolver-ia32.cc b/src/ia32/lithium-gap-resolver-ia32.cc
index 45c790f3..eabfecc5 100644
--- a/src/ia32/lithium-gap-resolver-ia32.cc
+++ b/src/ia32/lithium-gap-resolver-ia32.cc
@@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "v8.h"
+
#include "ia32/lithium-gap-resolver-ia32.h"
#include "ia32/lithium-codegen-ia32.h"
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 4440cdfa..199a80ae 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1366,13 +1366,23 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
- // The temporary operand is necessary to ensure that right is not allocated
- // into edx.
- LOperand* temp = FixedTemp(edx);
- LOperand* value = UseFixed(instr->left(), eax);
- LOperand* divisor = UseRegister(instr->right());
- LModI* mod = new LModI(value, divisor, temp);
- LInstruction* result = DefineFixed(mod, edx);
+
+ LInstruction* result;
+ if (instr->HasPowerOf2Divisor()) {
+ ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
+ LOperand* value = UseRegisterAtStart(instr->left());
+ LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
+ result = DefineSameAsFirst(mod);
+ } else {
+ // The temporary operand is necessary to ensure that right is
+ // not allocated into edx.
+ LOperand* temp = FixedTemp(edx);
+ LOperand* value = UseFixed(instr->left(), eax);
+ LOperand* divisor = UseRegister(instr->right());
+ LModI* mod = new LModI(value, divisor, temp);
+ result = DefineFixed(mod, edx);
+ }
+
return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanBeDivByZero))
? AssignEnvironment(result)
@@ -1577,9 +1587,10 @@ LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
}
-LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) {
+LInstruction* LChunkBuilder::DoExternalArrayLength(
+ HExternalArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LPixelArrayLength(array));
+ return DefineAsRegister(new LExternalArrayLength(array));
}
@@ -1622,8 +1633,9 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
LOperand* value = UseRegister(instr->value());
bool needs_check = !instr->value()->type().IsSmi();
if (needs_check) {
+ CpuFeatures* cpu_features = Isolate::Current()->cpu_features();
LOperand* xmm_temp =
- (instr->CanTruncateToInt32() && CpuFeatures::IsSupported(SSE3))
+ (instr->CanTruncateToInt32() && cpu_features->IsSupported(SSE3))
? NULL
: FixedTemp(xmm1);
LTaggedToI* res = new LTaggedToI(value, xmm_temp);
@@ -1644,7 +1656,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} else {
ASSERT(to.IsInteger32());
bool needs_temp = instr->CanTruncateToInt32() &&
- !CpuFeatures::IsSupported(SSE3);
+ !Isolate::Current()->cpu_features()->IsSupported(SSE3);
LOperand* value = needs_temp ?
UseTempRegister(instr->value()) : UseRegister(instr->value());
LOperand* temp = needs_temp ? TempRegister() : NULL;
@@ -1672,7 +1684,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
- return AssignEnvironment(new LCheckSmi(value, zero));
+ return AssignEnvironment(new LCheckNonSmi(value));
}
@@ -1693,7 +1705,7 @@ LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
- return AssignEnvironment(new LCheckSmi(value, not_zero));
+ return AssignEnvironment(new LCheckSmi(value));
}
@@ -1778,6 +1790,21 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
}
+LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
+ HLoadNamedFieldPolymorphic* instr) {
+ ASSERT(instr->representation().IsTagged());
+ if (instr->need_generic()) {
+ LOperand* obj = UseFixed(instr->object(), eax);
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return MarkAsCall(DefineFixed(result, eax), instr);
+ } else {
+ LOperand* obj = UseRegisterAtStart(instr->object());
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return AssignEnvironment(DefineAsRegister(result));
+ }
+}
+
+
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* object = UseFixed(instr->object(), eax);
@@ -1800,10 +1827,10 @@ LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
}
-LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer(
- HLoadPixelArrayExternalPointer* instr) {
+LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
+ HLoadExternalArrayPointer* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LLoadPixelArrayExternalPointer(input));
+ return DefineAsRegister(new LLoadExternalArrayPointer(input));
}
@@ -1818,16 +1845,24 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
}
-LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
- HLoadPixelArrayElement* instr) {
- ASSERT(instr->representation().IsInteger32());
+LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
+ HLoadKeyedSpecializedArrayElement* instr) {
+ ExternalArrayType array_type = instr->array_type();
+ Representation representation(instr->representation());
+ ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
+ (representation.IsDouble() && array_type == kExternalFloatArray));
ASSERT(instr->key()->representation().IsInteger32());
- LOperand* external_pointer =
- UseRegisterAtStart(instr->external_pointer());
- LOperand* key = UseRegisterAtStart(instr->key());
- LLoadPixelArrayElement* result =
- new LLoadPixelArrayElement(external_pointer, key);
- return DefineSameAsFirst(result);
+ LOperand* external_pointer = UseRegister(instr->external_pointer());
+ LOperand* key = UseRegister(instr->key());
+ LLoadKeyedSpecializedArrayElement* result =
+ new LLoadKeyedSpecializedArrayElement(external_pointer,
+ key);
+ LInstruction* load_instr = DefineAsRegister(result);
+ // An unsigned int array load might overflow and cause a deopt, make sure it
+ // has an environment.
+ return (array_type == kExternalUnsignedIntArray)
+ ? AssignEnvironment(load_instr)
+ : load_instr;
}
@@ -1860,20 +1895,39 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
}
-LInstruction* LChunkBuilder::DoStorePixelArrayElement(
- HStorePixelArrayElement* instr) {
- ASSERT(instr->value()->representation().IsInteger32());
+LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
+ HStoreKeyedSpecializedArrayElement* instr) {
+ Representation representation(instr->value()->representation());
+ ExternalArrayType array_type = instr->array_type();
+ ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
+ (representation.IsDouble() && array_type == kExternalFloatArray));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* val = UseRegister(instr->value());
LOperand* key = UseRegister(instr->key());
- // The generated code requires that the clamped value is in a byte
- // register. eax is an arbitrary choice to satisfy this requirement.
- LOperand* clamped = FixedTemp(eax);
+ LOperand* temp = NULL;
+
+ if (array_type == kExternalPixelArray) {
+ // The generated code for pixel array stores requires that the clamped value
+ // is in a byte register. eax is an arbitrary choice to satisfy this
+ // requirement.
+ temp = FixedTemp(eax);
+ }
+
+ LOperand* val = NULL;
+ if (array_type == kExternalByteArray ||
+ array_type == kExternalUnsignedByteArray) {
+ // We need a byte register in this case for the value.
+ val = UseFixed(instr->value(), eax);
+ } else {
+ val = UseRegister(instr->value());
+ }
- return new LStorePixelArrayElement(external_pointer, key, val, clamped);
+ return new LStoreKeyedSpecializedArrayElement(external_pointer,
+ key,
+ val,
+ temp);
}
@@ -1932,6 +1986,13 @@ LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
}
+LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
+ LOperand* char_code = UseRegister(instr->value());
+ LStringCharFromCode* result = new LStringCharFromCode(char_code);
+ return AssignPointerMap(DefineAsRegister(result));
+}
+
+
LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
LOperand* string = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LStringLength(string));
@@ -2011,6 +2072,13 @@ LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
}
+LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
+ LOperand* object = UseFixed(instr->value(), eax);
+ LToFastProperties* result = new LToFastProperties(object);
+ return MarkAsCall(DefineFixed(result, eax), instr);
+}
+
+
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
LTypeof* result = new LTypeof(UseAtStart(instr->value()));
return MarkAsCall(DefineFixed(result, eax), instr);
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index f8cb8710..a9d769b0 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -70,6 +70,7 @@ class LCodeGen;
V(CheckFunction) \
V(CheckInstanceType) \
V(CheckMap) \
+ V(CheckNonSmi) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
V(ClassOfTest) \
@@ -89,6 +90,7 @@ class LCodeGen;
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
+ V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \
V(Gap) \
@@ -117,14 +119,15 @@ class LCodeGen;
V(LazyBailout) \
V(LoadContextSlot) \
V(LoadElements) \
+ V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
+ V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
+ V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
- V(LoadPixelArrayElement) \
- V(LoadPixelArrayExternalPointer) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@@ -134,7 +137,6 @@ class LCodeGen;
V(OsrEntry) \
V(OuterContext) \
V(Parameter) \
- V(PixelArrayLength) \
V(Power) \
V(PushArgument) \
V(RegExpLiteral) \
@@ -147,14 +149,16 @@ class LCodeGen;
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
+ V(StoreKeyedSpecializedArrayElement) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
- V(StorePixelArrayElement) \
V(StringCharCodeAt) \
+ V(StringCharFromCode) \
V(StringLength) \
V(SubI) \
V(TaggedToI) \
V(Throw) \
+ V(ToFastProperties) \
V(Typeof) \
V(TypeofIs) \
V(TypeofIsAndBranch) \
@@ -1036,14 +1040,14 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
};
-class LPixelArrayLength: public LTemplateInstruction<1, 1, 0> {
+class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LPixelArrayLength(LOperand* value) {
+ explicit LExternalArrayLength(LOperand* value) {
inputs_[0] = value;
}
- DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel-array-length")
- DECLARE_HYDROGEN_ACCESSOR(PixelArrayLength)
+ DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
+ DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
};
@@ -1168,6 +1172,21 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> {
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedField)
+
+ LOperand* object() { return inputs_[0]; }
+};
+
+
+class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LLoadNamedFieldPolymorphic(LOperand* object) {
+ inputs_[0] = object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic")
+ DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic)
+
+ LOperand* object() { return inputs_[0]; }
};
@@ -1211,14 +1230,14 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> {
};
-class LLoadPixelArrayExternalPointer: public LTemplateInstruction<1, 1, 0> {
+class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LLoadPixelArrayExternalPointer(LOperand* object) {
+ explicit LLoadExternalArrayPointer(LOperand* object) {
inputs_[0] = object;
}
- DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer,
- "load-pixel-array-external-pointer")
+ DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer,
+ "load-external-array-pointer")
};
@@ -1237,19 +1256,23 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
};
-class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> {
+class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
- LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) {
+ LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
+ LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
- DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
- "load-pixel-array-element")
- DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement)
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
+ "load-keyed-specialized-array-element")
+ DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+ ExternalArrayType array_type() const {
+ return hydrogen()->array_type();
+ }
};
@@ -1489,7 +1512,7 @@ class LCallRuntime: public LTemplateInstruction<1, 0, 0> {
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
- Runtime::Function* function() const { return hydrogen()->function(); }
+ const Runtime::Function* function() const { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count(); }
};
@@ -1655,25 +1678,28 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
};
-class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 1> {
+class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 1> {
public:
- LStorePixelArrayElement(LOperand* external_pointer,
- LOperand* key,
- LOperand* val,
- LOperand* clamped) {
+ LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
+ LOperand* key,
+ LOperand* val,
+ LOperand* temp) {
inputs_[0] = external_pointer;
inputs_[1] = key;
inputs_[2] = val;
- temps_[0] = clamped;
+ temps_[0] = temp;
}
- DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
- "store-pixel-array-element")
- DECLARE_HYDROGEN_ACCESSOR(StorePixelArrayElement)
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
+ "store-keyed-specialized-array-element")
+ DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
+ ExternalArrayType array_type() const {
+ return hydrogen()->array_type();
+ }
};
@@ -1715,6 +1741,19 @@ class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> {
};
+class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LStringCharFromCode(LOperand* char_code) {
+ inputs_[0] = char_code;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
+ DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
+
+ LOperand* char_code() { return inputs_[0]; }
+};
+
+
class LStringLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LStringLength(LOperand* string) {
@@ -1778,20 +1817,21 @@ class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> {
class LCheckSmi: public LTemplateInstruction<0, 1, 0> {
public:
- LCheckSmi(LOperand* value, Condition condition)
- : condition_(condition) {
+ explicit LCheckSmi(LOperand* value) {
inputs_[0] = value;
}
- Condition condition() const { return condition_; }
+ DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi")
+};
- virtual void CompileToNative(LCodeGen* generator);
- virtual const char* Mnemonic() const {
- return (condition_ == zero) ? "check-non-smi" : "check-smi";
+
+class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
+ public:
+ explicit LCheckNonSmi(LOperand* value) {
+ inputs_[0] = value;
}
- private:
- Condition condition_;
+ DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
};
@@ -1831,6 +1871,17 @@ class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> {
};
+class LToFastProperties: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LToFastProperties(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
+ DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
+};
+
+
class LTypeof: public LTemplateInstruction<1, 1, 0> {
public:
explicit LTypeof(LOperand* value) {
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 91b6651f..ba30c49c 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -45,14 +45,14 @@ MacroAssembler::MacroAssembler(void* buffer, int size)
: Assembler(buffer, size),
generating_stub_(false),
allow_stub_calls_(true),
- code_object_(Heap::undefined_value()) {
+ code_object_(isolate()->heap()->undefined_value()) {
}
void MacroAssembler::RecordWriteHelper(Register object,
Register addr,
Register scratch) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Check that the object is not in new space.
Label not_in_new_space;
InNewSpace(object, scratch, not_equal, &not_in_new_space);
@@ -113,7 +113,7 @@ void MacroAssembler::RecordWrite(Register object,
// Clobber all input registers when running with the debug-code flag
// turned on to provoke errors.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
mov(object, Immediate(BitCast<int32_t>(kZapValue)));
mov(value, Immediate(BitCast<int32_t>(kZapValue)));
mov(scratch, Immediate(BitCast<int32_t>(kZapValue)));
@@ -141,7 +141,7 @@ void MacroAssembler::RecordWrite(Register object,
// Clobber all input registers when running with the debug-code flag
// turned on to provoke errors.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
mov(object, Immediate(BitCast<int32_t>(kZapValue)));
mov(address, Immediate(BitCast<int32_t>(kZapValue)));
mov(value, Immediate(BitCast<int32_t>(kZapValue)));
@@ -152,7 +152,7 @@ void MacroAssembler::RecordWrite(Register object,
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::DebugBreak() {
Set(eax, Immediate(0));
- mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak)));
+ mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak, isolate())));
CEntryStub ces(1);
call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
}
@@ -231,7 +231,7 @@ void MacroAssembler::IsInstanceJSObjectType(Register map,
void MacroAssembler::FCmp() {
- if (CpuFeatures::IsSupported(CMOV)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(CMOV)) {
fucomip();
ffree(0);
fincstp();
@@ -250,7 +250,7 @@ void MacroAssembler::AbortIfNotNumber(Register object) {
test(object, Immediate(kSmiTagMask));
j(zero, &ok);
cmp(FieldOperand(object, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ isolate()->factory()->heap_number_map());
Assert(equal, "Operand not a number");
bind(&ok);
}
@@ -285,15 +285,15 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) {
push(esi);
push(Immediate(Smi::FromInt(type)));
push(Immediate(CodeObject()));
- if (FLAG_debug_code) {
- cmp(Operand(esp, 0), Immediate(Factory::undefined_value()));
+ if (emit_debug_code()) {
+ cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value()));
Check(not_equal, "code object not properly patched");
}
}
void MacroAssembler::LeaveFrame(StackFrame::Type type) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
Immediate(Smi::FromInt(type)));
Check(equal, "stack frame types must match");
@@ -316,8 +316,10 @@ void MacroAssembler::EnterExitFramePrologue() {
push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
// Save the frame pointer and the context in top.
- ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
- ExternalReference context_address(Top::k_context_address);
+ ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address,
+ isolate());
+ ExternalReference context_address(Isolate::k_context_address,
+ isolate());
mov(Operand::StaticVariable(c_entry_fp_address), ebp);
mov(Operand::StaticVariable(context_address), esi);
}
@@ -339,7 +341,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
}
// Get the required frame alignment for the OS.
- static const int kFrameAlignment = OS::ActivationFrameAlignment();
+ const int kFrameAlignment = OS::ActivationFrameAlignment();
if (kFrameAlignment > 0) {
ASSERT(IsPowerOf2(kFrameAlignment));
and_(esp, -kFrameAlignment);
@@ -358,7 +360,8 @@ void MacroAssembler::EnterExitFrame(bool save_doubles) {
mov(edi, Operand(eax));
lea(esi, Operand(ebp, eax, times_4, offset));
- EnterExitFrameEpilogue(2, save_doubles);
+ // Reserve space for argc, argv and isolate.
+ EnterExitFrameEpilogue(3, save_doubles);
}
@@ -394,14 +397,15 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) {
void MacroAssembler::LeaveExitFrameEpilogue() {
// Restore current context from top and clear it in debug mode.
- ExternalReference context_address(Top::k_context_address);
+ ExternalReference context_address(Isolate::k_context_address, isolate());
mov(esi, Operand::StaticVariable(context_address));
#ifdef DEBUG
mov(Operand::StaticVariable(context_address), Immediate(0));
#endif
// Clear the top frame.
- ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
+ ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address,
+ isolate());
mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
}
@@ -435,15 +439,19 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
push(Immediate(0)); // NULL frame pointer.
}
// Save the current handler as the next handler.
- push(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
+ push(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
+ isolate())));
// Link this handler as the new current one.
- mov(Operand::StaticVariable(ExternalReference(Top::k_handler_address)), esp);
+ mov(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
+ isolate())),
+ esp);
}
void MacroAssembler::PopTryHandler() {
ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
- pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
+ pop(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
+ isolate())));
add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
}
@@ -458,7 +466,8 @@ void MacroAssembler::Throw(Register value) {
}
// Drop the sp to the top of the handler.
- ExternalReference handler_address(Top::k_handler_address);
+ ExternalReference handler_address(Isolate::k_handler_address,
+ isolate());
mov(esp, Operand::StaticVariable(handler_address));
// Restore next handler and frame pointer, discard handler state.
@@ -494,7 +503,8 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
}
// Drop sp to the top stack handler.
- ExternalReference handler_address(Top::k_handler_address);
+ ExternalReference handler_address(Isolate::k_handler_address,
+ isolate());
mov(esp, Operand::StaticVariable(handler_address));
// Unwind the handlers until the ENTRY handler is found.
@@ -516,12 +526,15 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
- ExternalReference external_caught(Top::k_external_caught_exception_address);
+ ExternalReference external_caught(
+ Isolate::k_external_caught_exception_address,
+ isolate());
mov(eax, false);
mov(Operand::StaticVariable(external_caught), eax);
// Set pending exception and eax to out of memory exception.
- ExternalReference pending_exception(Top::k_pending_exception_address);
+ ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ isolate());
mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
mov(Operand::StaticVariable(pending_exception), eax);
}
@@ -550,7 +563,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
// When generating debug code, make sure the lexical context is set.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
cmp(Operand(scratch), Immediate(0));
Check(not_equal, "we should not have an empty lexical context");
}
@@ -560,11 +573,11 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
// Check the context is a global context.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
push(scratch);
// Read the first word and compare to global_context_map.
mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
- cmp(scratch, Factory::global_context_map());
+ cmp(scratch, isolate()->factory()->global_context_map());
Check(equal, "JSGlobalObject::global_context should be a global context.");
pop(scratch);
}
@@ -584,14 +597,14 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
// Check the context is a global context.
- if (FLAG_debug_code) {
- cmp(holder_reg, Factory::null_value());
+ if (emit_debug_code()) {
+ cmp(holder_reg, isolate()->factory()->null_value());
Check(not_equal, "JSGlobalProxy::context() should not be null.");
push(holder_reg);
// Read the first word and compare to global_context_map(),
mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
- cmp(holder_reg, Factory::global_context_map());
+ cmp(holder_reg, isolate()->factory()->global_context_map());
Check(equal, "JSGlobalObject::global_context should be a global context.");
pop(holder_reg);
}
@@ -611,7 +624,7 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
Register scratch,
AllocationFlags flags) {
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
// Just return if allocation top is already known.
if ((flags & RESULT_CONTAINS_TOP) != 0) {
@@ -637,13 +650,13 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
Register scratch) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
test(result_end, Immediate(kObjectAlignmentMask));
Check(zero, "Unaligned allocation in new space");
}
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
// Update new top. Use scratch if available.
if (scratch.is(no_reg)) {
@@ -661,7 +674,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
Label* gc_required,
AllocationFlags flags) {
if (!FLAG_inline_new) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
mov(result, Immediate(0x7091));
if (result_end.is_valid()) {
@@ -683,7 +696,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
if (!top_reg.is(result)) {
mov(top_reg, result);
@@ -718,7 +731,7 @@ void MacroAssembler::AllocateInNewSpace(int header_size,
Label* gc_required,
AllocationFlags flags) {
if (!FLAG_inline_new) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
mov(result, Immediate(0x7091));
mov(result_end, Immediate(0x7191));
@@ -737,7 +750,7 @@ void MacroAssembler::AllocateInNewSpace(int header_size,
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
// We assume that element_count*element_size + header_size does not
// overflow.
@@ -764,7 +777,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
Label* gc_required,
AllocationFlags flags) {
if (!FLAG_inline_new) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
mov(result, Immediate(0x7091));
mov(result_end, Immediate(0x7191));
@@ -783,7 +796,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
if (!object_size.is(result_end)) {
mov(result_end, object_size);
}
@@ -804,7 +817,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
void MacroAssembler::UndoAllocationInNewSpace(Register object) {
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
// Make sure the object has no tag before resetting top.
and_(Operand(object), Immediate(~kHeapObjectTagMask));
@@ -830,7 +843,7 @@ void MacroAssembler::AllocateHeapNumber(Register result,
// Set the map.
mov(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::heap_number_map()));
+ Immediate(isolate()->factory()->heap_number_map()));
}
@@ -860,7 +873,7 @@ void MacroAssembler::AllocateTwoByteString(Register result,
// Set the map, length and hash field.
mov(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::string_map()));
+ Immediate(isolate()->factory()->string_map()));
mov(scratch1, length);
SmiTag(scratch1);
mov(FieldOperand(result, String::kLengthOffset), scratch1);
@@ -895,7 +908,7 @@ void MacroAssembler::AllocateAsciiString(Register result,
// Set the map, length and hash field.
mov(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::ascii_string_map()));
+ Immediate(isolate()->factory()->ascii_string_map()));
mov(scratch1, length);
SmiTag(scratch1);
mov(FieldOperand(result, String::kLengthOffset), scratch1);
@@ -921,7 +934,7 @@ void MacroAssembler::AllocateAsciiString(Register result,
// Set the map, length and hash field.
mov(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::ascii_string_map()));
+ Immediate(isolate()->factory()->ascii_string_map()));
mov(FieldOperand(result, String::kLengthOffset),
Immediate(Smi::FromInt(length)));
mov(FieldOperand(result, String::kHashFieldOffset),
@@ -943,7 +956,7 @@ void MacroAssembler::AllocateConsString(Register result,
// Set the map. The other fields are left uninitialized.
mov(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::cons_string_map()));
+ Immediate(isolate()->factory()->cons_string_map()));
}
@@ -961,7 +974,7 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
// Set the map. The other fields are left uninitialized.
mov(FieldOperand(result, HeapObject::kMapOffset),
- Immediate(Factory::cons_ascii_string_map()));
+ Immediate(isolate()->factory()->cons_ascii_string_map()));
}
@@ -1079,7 +1092,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
// If the prototype or initial map is the hole, don't return it and
// simply miss the cache instead. This will allow us to allocate a
// prototype object on-demand in the runtime system.
- cmp(Operand(result), Immediate(Factory::the_hole_value()));
+ cmp(Operand(result), Immediate(isolate()->factory()->the_hole_value()));
j(equal, miss, not_taken);
// If the function does not have an initial map, we're done.
@@ -1145,7 +1158,7 @@ void MacroAssembler::IllegalOperation(int num_arguments) {
if (num_arguments > 0) {
add(Operand(esp), Immediate(num_arguments * kPointerSize));
}
- mov(eax, Immediate(Factory::undefined_value()));
+ mov(eax, Immediate(isolate()->factory()->undefined_value()));
}
@@ -1174,9 +1187,9 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
- Runtime::Function* function = Runtime::FunctionForId(id);
+ const Runtime::Function* function = Runtime::FunctionForId(id);
Set(eax, Immediate(function->nargs));
- mov(ebx, Immediate(ExternalReference(function)));
+ mov(ebx, Immediate(ExternalReference(function, isolate())));
CEntryStub ces(1);
ces.SaveDoubles();
CallStub(&ces);
@@ -1189,7 +1202,8 @@ MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
}
-void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
+void MacroAssembler::CallRuntime(const Runtime::Function* f,
+ int num_arguments) {
// If the expected number of arguments of the runtime function is
// constant, we check that the actual number of arguments match the
// expectation.
@@ -1203,19 +1217,19 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
// should remove this need and make the runtime routine entry code
// smarter.
Set(eax, Immediate(num_arguments));
- mov(ebx, Immediate(ExternalReference(f)));
+ mov(ebx, Immediate(ExternalReference(f, isolate())));
CEntryStub ces(1);
CallStub(&ces);
}
-MaybeObject* MacroAssembler::TryCallRuntime(Runtime::Function* f,
+MaybeObject* MacroAssembler::TryCallRuntime(const Runtime::Function* f,
int num_arguments) {
if (f->nargs >= 0 && f->nargs != num_arguments) {
IllegalOperation(num_arguments);
// Since we did not call the stub, there was no allocation failure.
// Return some non-failure object.
- return Heap::undefined_value();
+ return isolate()->heap()->undefined_value();
}
// TODO(1236192): Most runtime routines don't need the number of
@@ -1223,7 +1237,7 @@ MaybeObject* MacroAssembler::TryCallRuntime(Runtime::Function* f,
// should remove this need and make the runtime routine entry code
// smarter.
Set(eax, Immediate(num_arguments));
- mov(ebx, Immediate(ExternalReference(f)));
+ mov(ebx, Immediate(ExternalReference(f, isolate())));
CEntryStub ces(1);
return TryCallStub(&ces);
}
@@ -1265,7 +1279,9 @@ MaybeObject* MacroAssembler::TryTailCallExternalReference(
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size) {
- TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
+ TailCallExternalReference(ExternalReference(fid, isolate()),
+ num_arguments,
+ result_size);
}
@@ -1273,7 +1289,7 @@ MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size) {
return TryTailCallExternalReference(
- ExternalReference(fid), num_arguments, result_size);
+ ExternalReference(fid, isolate()), num_arguments, result_size);
}
@@ -1320,7 +1336,7 @@ void MacroAssembler::PrepareCallApiFunction(int argc, Register scratch) {
// pointer to out cell.
lea(scratch, Operand(esp, (argc + 1) * kPointerSize));
mov(Operand(esp, 0 * kPointerSize), scratch); // output.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
mov(Operand(esp, (argc + 1) * kPointerSize), Immediate(0)); // out cell.
}
}
@@ -1373,9 +1389,9 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function,
// Check if the function scheduled an exception.
ExternalReference scheduled_exception_address =
- ExternalReference::scheduled_exception_address();
+ ExternalReference::scheduled_exception_address(isolate());
cmp(Operand::StaticVariable(scheduled_exception_address),
- Immediate(Factory::the_hole_value()));
+ Immediate(isolate()->factory()->the_hole_value()));
j(not_equal, &promote_scheduled_exception, not_taken);
LeaveApiExitFrame();
ret(stack_space * kPointerSize);
@@ -1387,14 +1403,17 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function,
}
bind(&empty_handle);
// It was zero; the result is undefined.
- mov(eax, Factory::undefined_value());
+ mov(eax, isolate()->factory()->undefined_value());
jmp(&prologue);
// HandleScope limit has changed. Delete allocated extensions.
+ ExternalReference delete_extensions =
+ ExternalReference::delete_handle_scope_extensions(isolate());
bind(&delete_allocated_handles);
mov(Operand::StaticVariable(limit_address), edi);
mov(edi, eax);
- mov(eax, Immediate(ExternalReference::delete_handle_scope_extensions()));
+ mov(Operand(esp, 0), Immediate(ExternalReference::isolate_address()));
+ mov(eax, Immediate(delete_extensions));
call(Operand(eax));
mov(eax, edi);
jmp(&leave_exit_frame);
@@ -1424,7 +1443,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
Handle<Code> code_constant,
const Operand& code_operand,
- Label* done,
+ NearLabel* done,
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
bool definitely_matches = false;
@@ -1467,7 +1486,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
if (!definitely_matches) {
Handle<Code> adaptor =
- Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
+ isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (!code_constant.is_null()) {
mov(edx, Immediate(code_constant));
add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
@@ -1492,7 +1511,7 @@ void MacroAssembler::InvokeCode(const Operand& code,
const ParameterCount& actual,
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
- Label done;
+ NearLabel done;
InvokePrologue(expected, actual, Handle<Code>::null(), code,
&done, flag, post_call_generator);
if (flag == CALL_FUNCTION) {
@@ -1512,7 +1531,7 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
RelocInfo::Mode rmode,
InvokeFlag flag,
PostCallGenerator* post_call_generator) {
- Label done;
+ NearLabel done;
Operand dummy(eax);
InvokePrologue(expected, actual, code, dummy, &done,
flag, post_call_generator);
@@ -1621,7 +1640,7 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
// (i.e., the static scope chain and runtime context chain do not agree).
// A variable occurring in such a scope should have slot type LOOKUP and
// not CONTEXT.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
cmp(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
Check(equal, "Yo dawg, I heard you liked function contexts "
"so I put function contexts in all your contexts");
@@ -1643,9 +1662,9 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
Register map) {
// Load the initial map. The global functions all have initial maps.
mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
Label ok, fail;
- CheckMap(map, Factory::meta_map(), &fail, false);
+ CheckMap(map, isolate()->factory()->meta_map(), &fail, false);
jmp(&ok);
bind(&fail);
Abort("Global functions must have initial map");
@@ -1787,18 +1806,19 @@ void MacroAssembler::DecrementCounter(Condition cc,
void MacroAssembler::Assert(Condition cc, const char* msg) {
- if (FLAG_debug_code) Check(cc, msg);
+ if (emit_debug_code()) Check(cc, msg);
}
void MacroAssembler::AssertFastElements(Register elements) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
+ Factory* factory = isolate()->factory();
Label ok;
cmp(FieldOperand(elements, HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(factory->fixed_array_map()));
j(equal, &ok);
cmp(FieldOperand(elements, HeapObject::kMapOffset),
- Immediate(Factory::fixed_cow_array_map()));
+ Immediate(factory->fixed_cow_array_map()));
j(equal, &ok);
Abort("JSObject with fast elements map has slow elements");
bind(&ok);
@@ -1860,10 +1880,10 @@ void MacroAssembler::Abort(const char* msg) {
void MacroAssembler::JumpIfNotNumber(Register reg,
TypeInfo info,
Label* on_not_number) {
- if (FLAG_debug_code) AbortIfSmi(reg);
+ if (emit_debug_code()) AbortIfSmi(reg);
if (!info.IsNumber()) {
cmp(FieldOperand(reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ isolate()->factory()->heap_number_map());
j(not_equal, on_not_number);
}
}
@@ -1874,7 +1894,7 @@ void MacroAssembler::ConvertToInt32(Register dst,
Register scratch,
TypeInfo info,
Label* on_not_int32) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
AbortIfSmi(source);
AbortIfNotNumber(source);
}
@@ -1968,6 +1988,9 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1,
void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
+ // Reserve space for Isolate address which is always passed as last parameter
+ num_arguments += 1;
+
int frameAlignment = OS::ActivationFrameAlignment();
if (frameAlignment != 0) {
// Make stack end at alignment and make room for num_arguments words
@@ -1993,8 +2016,13 @@ void MacroAssembler::CallCFunction(ExternalReference function,
void MacroAssembler::CallCFunction(Register function,
int num_arguments) {
+ // Pass current isolate address as additional parameter.
+ mov(Operand(esp, num_arguments * kPointerSize),
+ Immediate(ExternalReference::isolate_address()));
+ num_arguments += 1;
+
// Check stack alignment.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
CheckStackAlignment();
}
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 62bb0f36..bafb1750 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -474,13 +474,13 @@ class MacroAssembler: public Assembler {
void StubReturn(int argc);
// Call a runtime routine.
- void CallRuntime(Runtime::Function* f, int num_arguments);
+ void CallRuntime(const Runtime::Function* f, int num_arguments);
void CallRuntimeSaveDoubles(Runtime::FunctionId id);
// Call a runtime function, returning the CodeStub object called.
// Try to generate the stub code if necessary. Do not perform a GC
// but instead return a retry after GC failure.
- MUST_USE_RESULT MaybeObject* TryCallRuntime(Runtime::Function* f,
+ MUST_USE_RESULT MaybeObject* TryCallRuntime(const Runtime::Function* f,
int num_arguments);
// Convenience function: Same as above, but takes the fid instead.
@@ -646,7 +646,7 @@ class MacroAssembler: public Assembler {
const ParameterCount& actual,
Handle<Code> code_constant,
const Operand& code_operand,
- Label* done,
+ NearLabel* done,
InvokeFlag flag,
PostCallGenerator* post_call_generator = NULL);
@@ -695,14 +695,16 @@ void MacroAssembler::InNewSpace(Register object,
// The mask isn't really an address. We load it as an external reference in
// case the size of the new space is different between the snapshot maker
// and the running system.
- and_(Operand(scratch), Immediate(ExternalReference::new_space_mask()));
- cmp(Operand(scratch), Immediate(ExternalReference::new_space_start()));
+ and_(Operand(scratch),
+ Immediate(ExternalReference::new_space_mask(isolate())));
+ cmp(Operand(scratch),
+ Immediate(ExternalReference::new_space_start(isolate())));
j(cc, branch);
} else {
int32_t new_space_start = reinterpret_cast<int32_t>(
- ExternalReference::new_space_start().address());
+ ExternalReference::new_space_start(isolate()).address());
lea(scratch, Operand(object, -new_space_start));
- and_(scratch, Heap::NewSpaceMask());
+ and_(scratch, isolate()->heap()->NewSpaceMask());
j(cc, branch);
}
}
diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc
index 12134488..f1c773b8 100644
--- a/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/src/ia32/regexp-macro-assembler-ia32.cc
@@ -56,6 +56,7 @@ namespace internal {
*
* Each call to a public method should retain this convention.
* The stack will have the following structure:
+ * - Isolate* isolate (Address of the current isolate)
* - direct_call (if 1, direct call from JavaScript code, if 0
* call through the runtime system)
* - stack_area_base (High end of the memory area to use as
@@ -392,7 +393,7 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
__ mov(Operand(esp, 0 * kPointerSize), edx);
ExternalReference compare =
- ExternalReference::re_case_insensitive_compare_uc16();
+ ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
__ CallCFunction(compare, argument_count);
// Pop original values before reacting on result value.
__ pop(ebx);
@@ -678,7 +679,7 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(masm_->isolate());
__ mov(ecx, esp);
__ sub(ecx, Operand::StaticVariable(stack_limit));
// Handle it if the stack pointer is already below the stack limit.
@@ -842,7 +843,8 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ lea(eax, Operand(ebp, kStackHighEnd));
__ mov(Operand(esp, 1 * kPointerSize), eax);
__ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer());
- ExternalReference grow_stack = ExternalReference::re_grow_stack();
+ ExternalReference grow_stack =
+ ExternalReference::re_grow_stack(masm_->isolate());
__ CallCFunction(grow_stack, num_arguments);
// If return NULL, we have failed to grow the stack, and
// must exit with a stack-overflow exception.
@@ -866,10 +868,11 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
CodeDesc code_desc;
masm_->GetCode(&code_desc);
- Handle<Code> code = Factory::NewCode(code_desc,
- Code::ComputeFlags(Code::REGEXP),
- masm_->CodeObject());
- PROFILE(RegExpCodeCreateEvent(*code, *source));
+ Handle<Code> code =
+ masm_->isolate()->factory()->NewCode(code_desc,
+ Code::ComputeFlags(Code::REGEXP),
+ masm_->CodeObject());
+ PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source));
return Handle<Object>::cast(code);
}
@@ -1024,7 +1027,7 @@ void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
__ lea(eax, Operand(esp, -kPointerSize));
__ mov(Operand(esp, 0 * kPointerSize), eax);
ExternalReference check_stack_guard =
- ExternalReference::re_check_stack_guard_state();
+ ExternalReference::re_check_stack_guard_state(masm_->isolate());
__ CallCFunction(check_stack_guard, num_arguments);
}
@@ -1039,8 +1042,10 @@ static T& frame_entry(Address re_frame, int frame_offset) {
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame) {
- if (StackGuard::IsStackOverflow()) {
- Top::StackOverflow();
+ Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
+ ASSERT(isolate == Isolate::Current());
+ if (isolate->stack_guard()->IsStackOverflow()) {
+ isolate->StackOverflow();
return EXCEPTION;
}
@@ -1196,7 +1201,7 @@ void RegExpMacroAssemblerIA32::CheckPreemption() {
// Check for preemption.
Label no_preempt;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(masm_->isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(above, &no_preempt, taken);
@@ -1209,7 +1214,7 @@ void RegExpMacroAssemblerIA32::CheckPreemption() {
void RegExpMacroAssemblerIA32::CheckStackLimit() {
Label no_stack_overflow;
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit();
+ ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
__ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit));
__ j(above, &no_stack_overflow);
diff --git a/src/ia32/regexp-macro-assembler-ia32.h b/src/ia32/regexp-macro-assembler-ia32.h
index 51e2cb01..0af61f21 100644
--- a/src/ia32/regexp-macro-assembler-ia32.h
+++ b/src/ia32/regexp-macro-assembler-ia32.h
@@ -126,6 +126,7 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
static const int kRegisterOutput = kInputEnd + kPointerSize;
static const int kStackHighEnd = kRegisterOutput + kPointerSize;
static const int kDirectCall = kStackHighEnd + kPointerSize;
+ static const int kIsolate = kDirectCall + kPointerSize;
// Below the frame pointer - local stack variables.
// When adding local variables remember to push space for them in
// the frame in GetCode.
diff --git a/src/ia32/register-allocator-ia32.cc b/src/ia32/register-allocator-ia32.cc
index d840c0cc..6db13d47 100644
--- a/src/ia32/register-allocator-ia32.cc
+++ b/src/ia32/register-allocator-ia32.cc
@@ -42,12 +42,14 @@ namespace internal {
void Result::ToRegister() {
ASSERT(is_valid());
if (is_constant()) {
- Result fresh = CodeGeneratorScope::Current()->allocator()->Allocate();
+ CodeGenerator* code_generator =
+ CodeGeneratorScope::Current(Isolate::Current());
+ Result fresh = code_generator->allocator()->Allocate();
ASSERT(fresh.is_valid());
if (is_untagged_int32()) {
fresh.set_untagged_int32(true);
if (handle()->IsSmi()) {
- CodeGeneratorScope::Current()->masm()->Set(
+ code_generator->masm()->Set(
fresh.reg(),
Immediate(Smi::cast(*handle())->value()));
} else if (handle()->IsHeapNumber()) {
@@ -56,25 +58,23 @@ void Result::ToRegister() {
if (double_value == 0 && signbit(double_value)) {
// Negative zero must not be converted to an int32 unless
// the context allows it.
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(equal);
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(not_equal);
+ code_generator->unsafe_bailout_->Branch(equal);
+ code_generator->unsafe_bailout_->Branch(not_equal);
} else if (double_value == value) {
- CodeGeneratorScope::Current()->masm()->Set(
- fresh.reg(), Immediate(value));
+ code_generator->masm()->Set(fresh.reg(), Immediate(value));
} else {
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(equal);
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(not_equal);
+ code_generator->unsafe_bailout_->Branch(equal);
+ code_generator->unsafe_bailout_->Branch(not_equal);
}
} else {
// Constant is not a number. This was not predicted by AST analysis.
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(equal);
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(not_equal);
+ code_generator->unsafe_bailout_->Branch(equal);
+ code_generator->unsafe_bailout_->Branch(not_equal);
}
- } else if (CodeGeneratorScope::Current()->IsUnsafeSmi(handle())) {
- CodeGeneratorScope::Current()->MoveUnsafeSmi(fresh.reg(), handle());
+ } else if (code_generator->IsUnsafeSmi(handle())) {
+ code_generator->MoveUnsafeSmi(fresh.reg(), handle());
} else {
- CodeGeneratorScope::Current()->masm()->Set(fresh.reg(),
- Immediate(handle()));
+ code_generator->masm()->Set(fresh.reg(), Immediate(handle()));
}
// This result becomes a copy of the fresh one.
fresh.set_type_info(type_info());
@@ -85,17 +85,19 @@ void Result::ToRegister() {
void Result::ToRegister(Register target) {
+ CodeGenerator* code_generator =
+ CodeGeneratorScope::Current(Isolate::Current());
ASSERT(is_valid());
if (!is_register() || !reg().is(target)) {
- Result fresh = CodeGeneratorScope::Current()->allocator()->Allocate(target);
+ Result fresh = code_generator->allocator()->Allocate(target);
ASSERT(fresh.is_valid());
if (is_register()) {
- CodeGeneratorScope::Current()->masm()->mov(fresh.reg(), reg());
+ code_generator->masm()->mov(fresh.reg(), reg());
} else {
ASSERT(is_constant());
if (is_untagged_int32()) {
if (handle()->IsSmi()) {
- CodeGeneratorScope::Current()->masm()->Set(
+ code_generator->masm()->Set(
fresh.reg(),
Immediate(Smi::cast(*handle())->value()));
} else {
@@ -105,22 +107,20 @@ void Result::ToRegister(Register target) {
if (double_value == 0 && signbit(double_value)) {
// Negative zero must not be converted to an int32 unless
// the context allows it.
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(equal);
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(not_equal);
+ code_generator->unsafe_bailout_->Branch(equal);
+ code_generator->unsafe_bailout_->Branch(not_equal);
} else if (double_value == value) {
- CodeGeneratorScope::Current()->masm()->Set(
- fresh.reg(), Immediate(value));
+ code_generator->masm()->Set(fresh.reg(), Immediate(value));
} else {
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(equal);
- CodeGeneratorScope::Current()->unsafe_bailout_->Branch(not_equal);
+ code_generator->unsafe_bailout_->Branch(equal);
+ code_generator->unsafe_bailout_->Branch(not_equal);
}
}
} else {
- if (CodeGeneratorScope::Current()->IsUnsafeSmi(handle())) {
- CodeGeneratorScope::Current()->MoveUnsafeSmi(fresh.reg(), handle());
+ if (code_generator->IsUnsafeSmi(handle())) {
+ code_generator->MoveUnsafeSmi(fresh.reg(), handle());
} else {
- CodeGeneratorScope::Current()->masm()->Set(fresh.reg(),
- Immediate(handle()));
+ code_generator->masm()->Set(fresh.reg(), Immediate(handle()));
}
}
}
@@ -128,9 +128,9 @@ void Result::ToRegister(Register target) {
fresh.set_untagged_int32(is_untagged_int32());
*this = fresh;
} else if (is_register() && reg().is(target)) {
- ASSERT(CodeGeneratorScope::Current()->has_valid_frame());
- CodeGeneratorScope::Current()->frame()->Spill(target);
- ASSERT(CodeGeneratorScope::Current()->allocator()->count(target) == 1);
+ ASSERT(code_generator->has_valid_frame());
+ code_generator->frame()->Spill(target);
+ ASSERT(code_generator->allocator()->count(target) == 1);
}
ASSERT(is_register());
ASSERT(reg().is(target));
diff --git a/src/ia32/simulator-ia32.h b/src/ia32/simulator-ia32.h
index 43b7ea3b..cb660cd3 100644
--- a/src/ia32/simulator-ia32.h
+++ b/src/ia32/simulator-ia32.h
@@ -40,12 +40,12 @@ namespace internal {
typedef int (*regexp_matcher)(String*, int, const byte*,
- const byte*, int*, Address, int);
+ const byte*, int*, Address, int, Isolate*);
// Call the generated regexp code directly. The code at the entry address should
-// expect seven int/pointer sized arguments and return an int.
-#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
- (FUNCTION_CAST<regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6))
+// expect eight int/pointer sized arguments and return an int.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
+ (FUNCTION_CAST<regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7))
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 633097af..7730ee3d 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -39,14 +39,15 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-static void ProbeTable(MacroAssembler* masm,
+static void ProbeTable(Isolate* isolate,
+ MacroAssembler* masm,
Code::Flags flags,
StubCache::Table table,
Register name,
Register offset,
Register extra) {
- ExternalReference key_offset(SCTableReference::keyReference(table));
- ExternalReference value_offset(SCTableReference::valueReference(table));
+ ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
+ ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
Label miss;
@@ -113,8 +114,9 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Register r0,
Register r1) {
ASSERT(name->IsSymbol());
- __ IncrementCounter(&Counters::negative_lookups, 1);
- __ IncrementCounter(&Counters::negative_lookups_miss, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->negative_lookups(), 1);
+ __ IncrementCounter(counters->negative_lookups_miss(), 1);
Label done;
__ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
@@ -137,7 +139,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
// Check that the properties array is a dictionary.
__ cmp(FieldOperand(properties, HeapObject::kMapOffset),
- Immediate(Factory::hash_table_map()));
+ Immediate(masm->isolate()->factory()->hash_table_map()));
__ j(not_equal, miss_label);
// Compute the capacity mask.
@@ -177,7 +179,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
ASSERT_EQ(kSmiTagSize, 1);
__ mov(entity_name, Operand(properties, index, times_half_pointer_size,
kElementsStartOffset - kHeapObjectTag));
- __ cmp(entity_name, Factory::undefined_value());
+ __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
if (i != kProbes - 1) {
__ j(equal, &done, taken);
@@ -197,7 +199,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
}
__ bind(&done);
- __ DecrementCounter(&Counters::negative_lookups_miss, 1);
+ __ DecrementCounter(counters->negative_lookups_miss(), 1);
}
@@ -208,6 +210,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
Register scratch,
Register extra,
Register extra2) {
+ Isolate* isolate = Isolate::Current();
Label miss;
USE(extra2); // The register extra2 is not used on the ia32 platform.
@@ -240,7 +243,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
// Probe the primary table.
- ProbeTable(masm, flags, kPrimary, name, scratch, extra);
+ ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra);
// Primary miss: Compute hash for secondary probe.
__ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
@@ -252,7 +255,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
// Probe the secondary table.
- ProbeTable(masm, flags, kSecondary, name, scratch, extra);
+ ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
@@ -274,10 +277,11 @@ void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
MacroAssembler* masm, int index, Register prototype, Label* miss) {
// Check we're still in the same context.
__ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)),
- Top::global());
+ masm->isolate()->global());
__ j(not_equal, miss);
// Get the global function with the given index.
- JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
+ JSFunction* function =
+ JSFunction::cast(masm->isolate()->global_context()->get(index));
// Load its initial map. The global functions all have initial maps.
__ Set(prototype, Immediate(Handle<Map>(function->initial_map())));
// Load the prototype from the initial map.
@@ -395,7 +399,7 @@ static void PushInterceptorArguments(MacroAssembler* masm,
JSObject* holder_obj) {
__ push(name);
InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
- ASSERT(!Heap::InNewSpace(interceptor));
+ ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
Register scratch = name;
__ mov(scratch, Immediate(Handle<Object>(interceptor)));
__ push(scratch);
@@ -412,8 +416,9 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
JSObject* holder_obj) {
PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
__ CallExternalReference(
- ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)),
- 5);
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
+ masm->isolate()),
+ 5);
}
@@ -480,7 +485,7 @@ static MaybeObject* GenerateFastApiCall(MacroAssembler* masm,
__ mov(Operand(esp, 2 * kPointerSize), edi);
Object* call_data = optimization.api_call_info()->data();
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
- if (Heap::InNewSpace(call_data)) {
+ if (masm->isolate()->heap()->InNewSpace(call_data)) {
__ mov(ecx, api_call_info_handle);
__ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
__ mov(Operand(esp, 3 * kPointerSize), ebx);
@@ -574,7 +579,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
name,
holder,
miss);
- return Heap::undefined_value(); // Success.
+ return masm->isolate()->heap()->undefined_value(); // Success.
}
}
@@ -610,10 +615,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
(depth2 != kInvalidProtoDepth);
}
- __ IncrementCounter(&Counters::call_const_interceptor, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->call_const_interceptor(), 1);
if (can_do_fast_api_call) {
- __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1);
+ __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ReserveSpaceForFastApiCall(masm, scratch1);
}
@@ -672,7 +678,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
FreeSpaceForFastApiCall(masm, scratch1);
}
- return Heap::undefined_value(); // Success.
+ return masm->isolate()->heap()->undefined_value(); // Success.
}
void CompileRegular(MacroAssembler* masm,
@@ -700,9 +706,9 @@ class CallInterceptorCompiler BASE_EMBEDDED {
interceptor_holder);
__ CallExternalReference(
- ExternalReference(
- IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
- 5);
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
+ masm->isolate()),
+ 5);
// Restore the name_ register.
__ pop(name_);
@@ -728,7 +734,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
__ pop(receiver); // Restore the holder.
__ LeaveInternalFrame();
- __ cmp(eax, Factory::no_interceptor_result_sentinel());
+ __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
__ j(not_equal, interceptor_succeeded);
}
@@ -742,9 +748,9 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
Code* code = NULL;
if (kind == Code::LOAD_IC) {
- code = Builtins::builtin(Builtins::LoadIC_Miss);
+ code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss);
} else {
- code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
+ code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss);
}
Handle<Code> ic(code);
@@ -790,7 +796,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
__ push(eax);
__ push(scratch);
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
+ ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
+ masm->isolate()),
+ 3,
+ 1);
return;
}
@@ -851,10 +860,10 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
if (Serializer::enabled()) {
__ mov(scratch, Immediate(Handle<Object>(cell)));
__ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
- Immediate(Factory::the_hole_value()));
+ Immediate(masm->isolate()->factory()->the_hole_value()));
} else {
__ cmp(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)),
- Immediate(Factory::the_hole_value()));
+ Immediate(masm->isolate()->factory()->the_hole_value()));
}
__ j(not_equal, miss, not_taken);
return cell;
@@ -906,6 +915,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
&& !scratch2.is(scratch1));
+
// Keep track of the current object in register reg.
Register reg = object_reg;
JSObject* current = object;
@@ -930,7 +940,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
!current->IsJSGlobalObject() &&
!current->IsJSGlobalProxy()) {
if (!name->IsSymbol()) {
- MaybeObject* maybe_lookup_result = Heap::LookupSymbol(name);
+ MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name);
Object* lookup_result = NULL; // Initialization to please compiler.
if (!maybe_lookup_result->ToObject(&lookup_result)) {
set_failure(Failure::cast(maybe_lookup_result));
@@ -950,7 +960,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
__ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
reg = holder_reg; // from now the object is in holder_reg
__ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
- } else if (Heap::InNewSpace(prototype)) {
+ } else if (heap()->InNewSpace(prototype)) {
// Get the map of the current object.
__ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
__ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map())));
@@ -997,7 +1007,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
ASSERT(current == holder);
// Log the check depth.
- LOG(IntEvent("check-maps-depth", depth + 1));
+ LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
// Check the holder map.
__ cmp(FieldOperand(reg, HeapObject::kMapOffset),
@@ -1080,7 +1090,7 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
ASSERT(!scratch2.is(reg));
__ push(reg); // holder
// Push data from AccessorInfo.
- if (Heap::InNewSpace(callback_handle->data())) {
+ if (isolate()->heap()->InNewSpace(callback_handle->data())) {
__ mov(scratch1, Immediate(callback_handle));
__ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));
} else {
@@ -1204,7 +1214,7 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
- __ cmp(eax, Factory::no_interceptor_result_sentinel());
+ __ cmp(eax, factory()->no_interceptor_result_sentinel());
__ j(equal, &interceptor_failed);
__ LeaveInternalFrame();
__ ret(0);
@@ -1259,7 +1269,8 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
__ push(scratch2); // restore return address
ExternalReference ref =
- ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
+ masm()->isolate());
__ TailCallExternalReference(ref, 5, 1);
}
} else { // !compile_followup_inline
@@ -1273,8 +1284,9 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
name_reg, interceptor_holder);
__ push(scratch2); // restore old return address
- ExternalReference ref = ExternalReference(
- IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
+ isolate());
__ TailCallExternalReference(ref, 5, 1);
}
}
@@ -1325,7 +1337,7 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
}
// Check that the cell contains the same function.
- if (Heap::InNewSpace(function)) {
+ if (isolate()->heap()->InNewSpace(function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
@@ -1348,8 +1360,9 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
MaybeObject* CallStubCompiler::GenerateMissBranch() {
- MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(),
- kind_);
+ MaybeObject* maybe_obj =
+ isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
+ kind_);
Object* obj;
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
__ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
@@ -1405,10 +1418,8 @@ MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField(
// Handle call cache miss.
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(FIELD, name);
@@ -1429,7 +1440,9 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// -----------------------------------
// If object is not an array, bail out to regular call.
- if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsJSArray() || cell != NULL) {
+ return isolate()->heap()->undefined_value();
+ }
Label miss;
@@ -1459,7 +1472,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// Check that the elements are in fast mode and writable.
__ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(factory()->fixed_array_map()));
__ j(not_equal, &call_builtin);
if (argc == 1) { // Otherwise fall through to call builtin.
@@ -1508,9 +1521,9 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
}
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
const int kAllocationDelta = 4;
// Load top.
@@ -1535,7 +1548,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// ... and fill the rest with holes.
for (int i = 1; i < kAllocationDelta; i++) {
__ mov(Operand(edx, i * kPointerSize),
- Immediate(Factory::the_hole_value()));
+ Immediate(factory()->the_hole_value()));
}
// Restore receiver to edx as finish sequence assumes it's here.
@@ -1551,16 +1564,15 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
}
__ bind(&call_builtin);
- __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
- argc + 1,
- 1);
+ __ TailCallExternalReference(
+ ExternalReference(Builtins::c_ArrayPush, isolate()),
+ argc + 1,
+ 1);
}
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1581,7 +1593,9 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
// -----------------------------------
// If object is not an array, bail out to regular call.
- if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsJSArray() || cell != NULL) {
+ return heap()->undefined_value();
+ }
Label miss, return_undefined, call_builtin;
@@ -1603,7 +1617,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
// Check that the elements are in fast mode and writable.
__ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(factory()->fixed_array_map()));
__ j(not_equal, &call_builtin);
// Get the array's length into ecx and calculate new length.
@@ -1617,7 +1631,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
__ mov(eax, FieldOperand(ebx,
ecx, times_half_pointer_size,
FixedArray::kHeaderSize));
- __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
+ __ cmp(Operand(eax), Immediate(factory()->the_hole_value()));
__ j(equal, &call_builtin);
// Set the array's length.
@@ -1627,23 +1641,22 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
__ mov(FieldOperand(ebx,
ecx, times_half_pointer_size,
FixedArray::kHeaderSize),
- Immediate(Factory::the_hole_value()));
+ Immediate(factory()->the_hole_value()));
__ ret((argc + 1) * kPointerSize);
__ bind(&return_undefined);
- __ mov(eax, Immediate(Factory::undefined_value()));
+ __ mov(eax, Immediate(factory()->undefined_value()));
__ ret((argc + 1) * kPointerSize);
__ bind(&call_builtin);
- __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
- argc + 1,
- 1);
+ __ TailCallExternalReference(
+ ExternalReference(Builtins::c_ArrayPop, isolate()),
+ argc + 1,
+ 1);
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1665,7 +1678,9 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// -----------------------------------
// If object is not a string, bail out to regular call.
- if (!object->IsString() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsString() || cell != NULL) {
+ return isolate()->heap()->undefined_value();
+ }
const int argc = arguments().immediate();
@@ -1697,7 +1712,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
if (argc > 0) {
__ mov(index, Operand(esp, (argc - 0) * kPointerSize));
} else {
- __ Set(index, Immediate(Factory::undefined_value()));
+ __ Set(index, Immediate(factory()->undefined_value()));
}
StringCharCodeAtGenerator char_code_at_generator(receiver,
@@ -1716,7 +1731,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
- __ Set(eax, Immediate(Factory::nan_value()));
+ __ Set(eax, Immediate(factory()->nan_value()));
__ ret((argc + 1) * kPointerSize);
}
@@ -1724,10 +1739,8 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// Restore function name in ecx.
__ Set(ecx, Immediate(Handle<String>(name)));
__ bind(&name_miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1749,7 +1762,9 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// -----------------------------------
// If object is not a string, bail out to regular call.
- if (!object->IsString() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsString() || cell != NULL) {
+ return heap()->undefined_value();
+ }
const int argc = arguments().immediate();
@@ -1782,7 +1797,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
if (argc > 0) {
__ mov(index, Operand(esp, (argc - 0) * kPointerSize));
} else {
- __ Set(index, Immediate(Factory::undefined_value()));
+ __ Set(index, Immediate(factory()->undefined_value()));
}
StringCharAtGenerator char_at_generator(receiver,
@@ -1802,7 +1817,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
- __ Set(eax, Immediate(Factory::empty_string()));
+ __ Set(eax, Immediate(factory()->empty_string()));
__ ret((argc + 1) * kPointerSize);
}
@@ -1810,10 +1825,8 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// Restore function name in ecx.
__ Set(ecx, Immediate(Handle<String>(name)));
__ bind(&name_miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1838,7 +1851,9 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
- if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
+ if (!object->IsJSObject() || argc != 1) {
+ return isolate()->heap()->undefined_value();
+ }
Label miss;
GenerateNameCheck(name, &miss);
@@ -1885,10 +1900,8 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
__ bind(&miss);
// ecx: function name.
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
@@ -1908,14 +1921,19 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
- if (!CpuFeatures::IsSupported(SSE2)) return Heap::undefined_value();
+ if (!isolate()->cpu_features()->IsSupported(SSE2)) {
+ return isolate()->heap()->undefined_value();
+ }
+
CpuFeatures::Scope use_sse2(SSE2);
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
- if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
+ if (!object->IsJSObject() || argc != 1) {
+ return isolate()->heap()->undefined_value();
+ }
Label miss;
GenerateNameCheck(name, &miss);
@@ -1946,7 +1964,7 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
// Check if the argument is a heap number and load its value into xmm0.
Label slow;
- __ CheckMap(eax, Factory::heap_number_map(), &slow, true);
+ __ CheckMap(eax, factory()->heap_number_map(), &slow, true);
__ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
// Check if the argument is strictly positive. Note this also
@@ -2012,10 +2030,8 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
__ bind(&miss);
// ecx: function name.
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
@@ -2039,7 +2055,9 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
- if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
+ if (!object->IsJSObject() || argc != 1) {
+ return isolate()->heap()->undefined_value();
+ }
Label miss;
GenerateNameCheck(name, &miss);
@@ -2090,7 +2108,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
// Check if the argument is a heap number and load its exponent and
// sign into ebx.
__ bind(&not_smi);
- __ CheckMap(eax, Factory::heap_number_map(), &slow, true);
+ __ CheckMap(eax, factory()->heap_number_map(), &slow, true);
__ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
// Check the sign of the argument. If the argument is positive,
@@ -2117,16 +2135,75 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
__ bind(&miss);
// ecx: function name.
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
}
+MaybeObject* CallStubCompiler::CompileFastApiCall(
+ const CallOptimization& optimization,
+ Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
+ ASSERT(optimization.is_simple_api_call());
+ // Bail out if object is a global object as we don't want to
+ // repatch it to global receiver.
+ if (object->IsGlobalObject()) return heap()->undefined_value();
+ if (cell != NULL) return heap()->undefined_value();
+ int depth = optimization.GetPrototypeDepthOfExpectedType(
+ JSObject::cast(object), holder);
+ if (depth == kInvalidProtoDepth) return heap()->undefined_value();
+
+ Label miss, miss_before_stack_reserved;
+
+ GenerateNameCheck(name, &miss_before_stack_reserved);
+
+ // Get the receiver from the stack.
+ const int argc = arguments().immediate();
+ __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+
+ // Check that the receiver isn't a smi.
+ __ test(edx, Immediate(kSmiTagMask));
+ __ j(zero, &miss_before_stack_reserved, not_taken);
+
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->call_const(), 1);
+ __ IncrementCounter(counters->call_const_fast_api(), 1);
+
+ // Allocate space for v8::Arguments implicit values. Must be initialized
+ // before calling any runtime function.
+ __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
+
+ // Check that the maps haven't changed and find a Holder as a side effect.
+ CheckPrototypes(JSObject::cast(object), edx, holder,
+ ebx, eax, edi, name, depth, &miss);
+
+ // Move the return address on top of the stack.
+ __ mov(eax, Operand(esp, 3 * kPointerSize));
+ __ mov(Operand(esp, 0 * kPointerSize), eax);
+
+ // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
+ // duplicate of return address and will be overwritten.
+ MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
+ if (result->IsFailure()) return result;
+
+ __ bind(&miss);
+ __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
+
+ __ bind(&miss_before_stack_reserved);
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
+
+ // Return the generated code.
+ return GetCode(function);
+}
+
+
MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
@@ -2140,20 +2217,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
- SharedFunctionInfo* function_info = function->shared();
- if (function_info->HasBuiltinFunctionId()) {
- BuiltinFunctionId id = function_info->builtin_function_id();
+ if (HasCustomCallGenerator(function)) {
MaybeObject* maybe_result = CompileCustomCall(
- id, object, holder, NULL, function, name);
+ object, holder, NULL, function, name);
Object* result;
if (!maybe_result->ToObject(&result)) return maybe_result;
// undefined means bail out to regular compiler.
if (!result->IsUndefined()) return result;
}
- Label miss_in_smi_check;
+ Label miss;
- GenerateNameCheck(name, &miss_in_smi_check);
+ GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -2162,42 +2237,25 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// Check that the receiver isn't a smi.
if (check != NUMBER_CHECK) {
__ test(edx, Immediate(kSmiTagMask));
- __ j(zero, &miss_in_smi_check, not_taken);
+ __ j(zero, &miss, not_taken);
}
// Make sure that it's okay not to patch the on stack receiver
// unless we're doing a receiver map check.
ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
- CallOptimization optimization(function);
- int depth = kInvalidProtoDepth;
- Label miss;
-
+ SharedFunctionInfo* function_info = function->shared();
switch (check) {
case RECEIVER_MAP_CHECK:
- __ IncrementCounter(&Counters::call_const, 1);
-
- if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
- depth = optimization.GetPrototypeDepthOfExpectedType(
- JSObject::cast(object), holder);
- }
-
- if (depth != kInvalidProtoDepth) {
- __ IncrementCounter(&Counters::call_const_fast_api, 1);
-
- // Allocate space for v8::Arguments implicit values. Must be initialized
- // before to call any runtime function.
- __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
- }
+ __ IncrementCounter(isolate()->counters()->call_const(), 1);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), edx, holder,
- ebx, eax, edi, name, depth, &miss);
+ ebx, eax, edi, name, &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
if (object->IsGlobalObject()) {
- ASSERT(depth == kInvalidProtoDepth);
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
__ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
}
@@ -2250,9 +2308,9 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
} else {
Label fast;
// Check that the object is a boolean.
- __ cmp(edx, Factory::true_value());
+ __ cmp(edx, factory()->true_value());
__ j(equal, &fast, taken);
- __ cmp(edx, Factory::false_value());
+ __ cmp(edx, factory()->false_value());
__ j(not_equal, &miss, not_taken);
__ bind(&fast);
// Check that the maps starting from the prototype haven't changed.
@@ -2268,29 +2326,12 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
UNREACHABLE();
}
- if (depth != kInvalidProtoDepth) {
- // Move the return address on top of the stack.
- __ mov(eax, Operand(esp, 3 * kPointerSize));
- __ mov(Operand(esp, 0 * kPointerSize), eax);
-
- // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
- // duplicate of return address and will be overwritten.
- MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
- if (result->IsFailure()) return result;
- } else {
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
- }
+ __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
// Handle call cache miss.
__ bind(&miss);
- if (depth != kInvalidProtoDepth) {
- __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
- }
- __ bind(&miss_in_smi_check);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -2355,10 +2396,8 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// Handle load cache miss.
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(INTERCEPTOR, name);
@@ -2378,11 +2417,9 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
- SharedFunctionInfo* function_info = function->shared();
- if (function_info->HasBuiltinFunctionId()) {
- BuiltinFunctionId id = function_info->builtin_function_id();
+ if (HasCustomCallGenerator(function)) {
MaybeObject* maybe_result = CompileCustomCall(
- id, object, holder, cell, function, name);
+ object, holder, cell, function, name);
Object* result;
if (!maybe_result->ToObject(&result)) return maybe_result;
// undefined means bail out to regular compiler.
@@ -2410,7 +2447,8 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Jump to the cached code (tail call).
- __ IncrementCounter(&Counters::call_global_inline, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->call_global_inline(), 1);
ASSERT(function->is_compiled());
ParameterCount expected(function->shared()->formal_parameter_count());
if (V8::UseCrankshaft()) {
@@ -2427,11 +2465,9 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// Handle call cache miss.
__ bind(&miss);
- __ IncrementCounter(&Counters::call_global_inline_miss, 1);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ __ IncrementCounter(counters->call_global_inline_miss(), 1);
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(NORMAL, name);
@@ -2461,7 +2497,7 @@ MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
// Handle store cache miss.
__ bind(&miss);
__ mov(ecx, Immediate(Handle<String>(name))); // restore name
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2507,12 +2543,12 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
// Do tail-call to the runtime system.
ExternalReference store_callback_property =
- ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
+ ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
__ TailCallExternalReference(store_callback_property, 4, 1);
// Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2557,12 +2593,12 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
// Do tail-call to the runtime system.
ExternalReference store_ic_property =
- ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
+ ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
__ TailCallExternalReference(store_ic_property, 4, 1);
// Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2598,20 +2634,21 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
// cell could have been deleted and reintroducing the global needs
// to update the property details in the property dictionary of the
// global object. We bail out to the runtime system to do that.
- __ cmp(cell_operand, Factory::the_hole_value());
+ __ cmp(cell_operand, factory()->the_hole_value());
__ j(equal, &miss);
// Store the value in the cell.
__ mov(cell_operand, eax);
// Return the value (register eax).
- __ IncrementCounter(&Counters::named_store_global_inline, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->named_store_global_inline(), 1);
__ ret(0);
// Handle store cache miss.
__ bind(&miss);
- __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2631,7 +2668,8 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_store_field, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_store_field(), 1);
// Check that the name has not changed.
__ cmp(Operand(ecx), Immediate(Handle<String>(name)));
@@ -2647,8 +2685,8 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
// Handle store cache miss.
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_store_field, 1);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
+ __ DecrementCounter(counters->keyed_store_field(), 1);
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2682,7 +2720,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
// Get the elements array and make sure it is a fast element array, not 'cow'.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
__ cmp(FieldOperand(edi, HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
+ Immediate(factory()->fixed_array_map()));
__ j(not_equal, &miss, not_taken);
// Check that the key is within bounds.
@@ -2705,43 +2743,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
// Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
- __ jmp(ic, RelocInfo::CODE_TARGET);
-
- // Return the generated code.
- return GetCode(NORMAL, NULL);
-}
-
-
-MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray(
- JSObject* receiver) {
- // ----------- S t a t e -------------
- // -- eax : value
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- Label miss;
-
- // Check that the map matches.
- __ CheckMap(edx, Handle<Map>(receiver->map()), &miss, false);
-
- // Do the load.
- GenerateFastPixelArrayStore(masm(),
- edx,
- ecx,
- eax,
- edi,
- ebx,
- true,
- &miss,
- &miss,
- NULL,
- &miss);
-
- // Handle store cache miss.
- __ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2786,14 +2788,14 @@ MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
// Return undefined if maps of the full prototype chain are still the
// same and no global property with this name contains a value.
- __ mov(eax, Factory::undefined_value());
+ __ mov(eax, isolate()->factory()->undefined_value());
__ ret(0);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
- return GetCode(NONEXISTENT, Heap::empty_string());
+ return GetCode(NONEXISTENT, isolate()->heap()->empty_string());
}
@@ -2930,19 +2932,20 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
- __ cmp(ebx, Factory::the_hole_value());
+ __ cmp(ebx, factory()->the_hole_value());
__ j(equal, &miss, not_taken);
} else if (FLAG_debug_code) {
- __ cmp(ebx, Factory::the_hole_value());
+ __ cmp(ebx, factory()->the_hole_value());
__ Check(not_equal, "DontDelete cells can't contain the hole");
}
- __ IncrementCounter(&Counters::named_load_global_stub, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->named_load_global_stub(), 1);
__ mov(eax, ebx);
__ ret(0);
__ bind(&miss);
- __ IncrementCounter(&Counters::named_load_global_stub_miss, 1);
+ __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
@@ -2961,7 +2964,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_field, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_field(), 1);
// Check that the name has not changed.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
@@ -2970,7 +2974,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_field, 1);
+ __ DecrementCounter(counters->keyed_load_field(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -2990,7 +2994,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_callback, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_callback(), 1);
// Check that the name has not changed.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
@@ -3005,7 +3010,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_callback, 1);
+ __ DecrementCounter(counters->keyed_load_callback(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -3024,7 +3029,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_constant_function(), 1);
// Check that the name has not changed.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
@@ -3033,7 +3039,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi,
value, name, &miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
+ __ DecrementCounter(counters->keyed_load_constant_function(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -3051,7 +3057,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_interceptor(), 1);
// Check that the name has not changed.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
@@ -3070,7 +3077,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
name,
&miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
+ __ DecrementCounter(counters->keyed_load_interceptor(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -3086,7 +3093,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_array_length, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_array_length(), 1);
// Check that the name has not changed.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
@@ -3094,7 +3102,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
GenerateLoadArrayLength(masm(), edx, ecx, &miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_array_length, 1);
+ __ DecrementCounter(counters->keyed_load_array_length(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -3110,7 +3118,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_string_length, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_string_length(), 1);
// Check that the name has not changed.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
@@ -3118,7 +3127,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_string_length, 1);
+ __ DecrementCounter(counters->keyed_load_string_length(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -3134,7 +3143,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_function_prototype(), 1);
// Check that the name has not changed.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
@@ -3142,7 +3152,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
+ __ DecrementCounter(counters->keyed_load_function_prototype(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -3182,7 +3192,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
// Load the result and make sure it's not the hole.
__ mov(ebx, Operand(ecx, eax, times_2,
FixedArray::kHeaderSize - kHeapObjectTag));
- __ cmp(ebx, Factory::the_hole_value());
+ __ cmp(ebx, factory()->the_hole_value());
__ j(equal, &miss, not_taken);
__ mov(eax, ebx);
__ ret(0);
@@ -3195,37 +3205,6 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) {
- // ----------- S t a t e -------------
- // -- eax : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- Label miss;
-
- // Check that the map matches.
- __ CheckMap(edx, Handle<Map>(receiver->map()), &miss, false);
-
- GenerateFastPixelArrayLoad(masm(),
- edx,
- eax,
- ecx,
- ebx,
- eax,
- &miss,
- &miss,
- &miss);
-
- // Handle load cache miss.
- __ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Miss));
- __ jmp(ic, RelocInfo::CODE_TARGET);
-
- // Return the generated code.
- return GetCode(NORMAL, NULL);
-}
-
-
// Specialized stub for constructing objects from functions which only have only
// simple assignments of the form this.x = ...; in their body.
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
@@ -3242,7 +3221,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// code for the function thereby hitting the break points.
__ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
- __ cmp(ebx, Factory::undefined_value());
+ __ cmp(ebx, factory()->undefined_value());
__ j(not_equal, &generic_stub_call, not_taken);
#endif
@@ -3279,7 +3258,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// ebx: initial map
// edx: JSObject (untagged)
__ mov(Operand(edx, JSObject::kMapOffset), ebx);
- __ mov(ebx, Factory::empty_fixed_array());
+ __ mov(ebx, factory()->empty_fixed_array());
__ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
__ mov(Operand(edx, JSObject::kElementsOffset), ebx);
@@ -3296,7 +3275,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
__ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
// Use edi for holding undefined which is used in several places below.
- __ mov(edi, Factory::undefined_value());
+ __ mov(edi, factory()->undefined_value());
// eax: argc
// ecx: first argument
@@ -3313,7 +3292,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
int arg_number = shared->GetThisPropertyAssignmentArgument(i);
__ mov(ebx, edi);
__ cmp(eax, arg_number);
- if (CpuFeatures::IsSupported(CMOV)) {
+ if (isolate()->cpu_features()->IsSupported(CMOV)) {
CpuFeatures::Scope use_cmov(CMOV);
__ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize));
} else {
@@ -3348,15 +3327,16 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
__ pop(ecx);
__ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
__ push(ecx);
- __ IncrementCounter(&Counters::constructed_objects, 1);
- __ IncrementCounter(&Counters::constructed_objects_stub, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->constructed_objects(), 1);
+ __ IncrementCounter(counters->constructed_objects_stub(), 1);
__ ret(0);
// Jump to the generic stub in case the specialized code cannot handle the
// construction.
__ bind(&generic_stub_call);
- Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
- Handle<Code> generic_construct_stub(code);
+ Handle<Code> generic_construct_stub =
+ isolate()->builtins()->JSConstructStubGeneric();
__ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -3365,7 +3345,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
- ExternalArrayType array_type, Code::Flags flags) {
+ JSObject*receiver, ExternalArrayType array_type, Code::Flags flags) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3381,25 +3361,9 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &slow, not_taken);
- // Get the map of the receiver.
- __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks. We need
- // to check this explicitly since this generic stub does not perform
- // map checks.
- __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
- 1 << Map::kIsAccessCheckNeeded);
- __ j(not_zero, &slow, not_taken);
-
- __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
- __ j(not_equal, &slow, not_taken);
-
- // Check that the elements array is the appropriate type of
- // ExternalArray.
+ // Check that the map matches.
+ __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, false);
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
- Handle<Map> map(Heap::MapForExternalArrayType(array_type));
- __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
- Immediate(map));
- __ j(not_equal, &slow, not_taken);
// eax: key, known to be a smi.
// edx: receiver, known to be a JSObject.
@@ -3410,21 +3374,21 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
__ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &slow);
-
__ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
// ebx: base pointer of external storage
switch (array_type) {
case kExternalByteArray:
- __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0));
+ __ movsx_b(eax, Operand(ebx, ecx, times_1, 0));
break;
case kExternalUnsignedByteArray:
- __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0));
+ case kExternalPixelArray:
+ __ movzx_b(eax, Operand(ebx, ecx, times_1, 0));
break;
case kExternalShortArray:
- __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0));
+ __ movsx_w(eax, Operand(ebx, ecx, times_2, 0));
break;
case kExternalUnsignedShortArray:
- __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0));
+ __ movzx_w(eax, Operand(ebx, ecx, times_2, 0));
break;
case kExternalIntArray:
case kExternalUnsignedIntArray:
@@ -3499,7 +3463,6 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(0);
} else {
- __ mov(eax, ecx);
__ SmiTag(eax);
__ ret(0);
}
@@ -3513,7 +3476,8 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// Slow case: Jump to runtime.
__ bind(&slow);
- __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3534,7 +3498,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
- ExternalArrayType array_type, Code::Flags flags) {
+ JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
@@ -3546,30 +3510,16 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
// Check that the object isn't a smi.
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &slow);
- // Get the map from the receiver.
- __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks. We need
- // to do this because this generic stub does not perform map checks.
- __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
- 1 << Map::kIsAccessCheckNeeded);
- __ j(not_zero, &slow);
+
+ // Check that the map matches.
+ __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, false);
+
// Check that the key is a smi.
__ test(ecx, Immediate(kSmiTagMask));
__ j(not_zero, &slow);
- // Get the instance type from the map of the receiver.
- __ CmpInstanceType(edi, JS_OBJECT_TYPE);
- __ j(not_equal, &slow);
-
- // Check that the elements array is the appropriate type of
- // ExternalArray.
- // eax: value
- // edx: receiver, a JSObject
- // ecx: key, a smi
- __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
- __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)),
- &slow, true);
// Check that the index is in range.
+ __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
__ mov(ebx, ecx);
__ SmiUntag(ebx);
__ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
@@ -3584,13 +3534,28 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
// edi: elements array
// ebx: untagged index
__ test(eax, Immediate(kSmiTagMask));
- __ j(not_equal, &check_heap_number);
+ if (array_type == kExternalPixelArray)
+ __ j(not_equal, &slow);
+ else
+ __ j(not_equal, &check_heap_number);
+
// smi case
__ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed.
__ SmiUntag(ecx);
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
// ecx: base pointer of external storage
switch (array_type) {
+ case kExternalPixelArray:
+ { // Clamp the value to [0..255].
+ NearLabel done;
+ __ test(ecx, Immediate(0xFFFFFF00));
+ __ j(zero, &done);
+ __ setcc(negative, ecx); // 1 if negative, 0 if positive.
+ __ dec_b(ecx); // 0 if negative, 255 if positive.
+ __ bind(&done);
+ }
+ __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+ break;
case kExternalByteArray:
case kExternalUnsignedByteArray:
__ mov_b(Operand(edi, ebx, times_1, 0), ecx);
@@ -3616,87 +3581,100 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
}
__ ret(0); // Return the original value.
- __ bind(&check_heap_number);
- // eax: value
- // edx: receiver
- // ecx: key
- // edi: elements array
- // ebx: untagged index
- __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
- Immediate(Factory::heap_number_map()));
- __ j(not_equal, &slow);
-
- // The WebGL specification leaves the behavior of storing NaN and
- // +/-Infinity into integer arrays basically undefined. For more
- // reproducible behavior, convert these to zero.
- __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
- // ebx: untagged index
- // edi: base pointer of external storage
- if (array_type == kExternalFloatArray) {
- __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
- __ fstp_s(Operand(edi, ebx, times_4, 0));
- __ ret(0);
- } else {
- // Perform float-to-int conversion with truncation (round-to-zero)
- // behavior.
-
- // For the moment we make the slow call to the runtime on
- // processors that don't support SSE2. The code in IntegerConvert
- // (code-stubs-ia32.cc) is roughly what is needed here though the
- // conversion failure case does not need to be handled.
- if (CpuFeatures::IsSupported(SSE2)) {
- if (array_type != kExternalIntArray &&
- array_type != kExternalUnsignedIntArray) {
- ASSERT(CpuFeatures::IsSupported(SSE2));
- CpuFeatures::Scope scope(SSE2);
- __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset));
- // ecx: untagged integer value
- switch (array_type) {
- case kExternalByteArray:
- case kExternalUnsignedByteArray:
- __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
- break;
- case kExternalShortArray:
- case kExternalUnsignedShortArray:
- __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
- break;
- default:
- UNREACHABLE();
- break;
- }
- } else {
- if (CpuFeatures::IsSupported(SSE3)) {
- CpuFeatures::Scope scope(SSE3);
- // fisttp stores values as signed integers. To represent the
- // entire range of int and unsigned int arrays, store as a
- // 64-bit int and discard the high 32 bits.
- // If the value is NaN or +/-infinity, the result is 0x80000000,
- // which is automatically zero when taken mod 2^n, n < 32.
- __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
- __ sub(Operand(esp), Immediate(2 * kPointerSize));
- __ fisttp_d(Operand(esp, 0));
- __ pop(ecx);
- __ add(Operand(esp), Immediate(kPointerSize));
- } else {
- ASSERT(CpuFeatures::IsSupported(SSE2));
+ // TODO(danno): handle heap number -> pixel array conversion
+ if (array_type != kExternalPixelArray) {
+ __ bind(&check_heap_number);
+ // eax: value
+ // edx: receiver
+ // ecx: key
+ // edi: elements array
+ // ebx: untagged index
+ __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
+ Immediate(factory()->heap_number_map()));
+ __ j(not_equal, &slow);
+
+ // The WebGL specification leaves the behavior of storing NaN and
+ // +/-Infinity into integer arrays basically undefined. For more
+ // reproducible behavior, convert these to zero.
+ __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
+ // ebx: untagged index
+ // edi: base pointer of external storage
+ if (array_type == kExternalFloatArray) {
+ __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
+ __ fstp_s(Operand(edi, ebx, times_4, 0));
+ __ ret(0);
+ } else {
+ // Perform float-to-int conversion with truncation (round-to-zero)
+ // behavior.
+
+ // For the moment we make the slow call to the runtime on
+ // processors that don't support SSE2. The code in IntegerConvert
+ // (code-stubs-ia32.cc) is roughly what is needed here though the
+ // conversion failure case does not need to be handled.
+ if (isolate()->cpu_features()->IsSupported(SSE2)) {
+ if (array_type != kExternalIntArray &&
+ array_type != kExternalUnsignedIntArray) {
+ ASSERT(isolate()->cpu_features()->IsSupported(SSE2));
CpuFeatures::Scope scope(SSE2);
- // We can easily implement the correct rounding behavior for the
- // range [0, 2^31-1]. For the time being, to keep this code simple,
- // make the slow runtime call for values outside this range.
- // Note: we could do better for signed int arrays.
- __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
- // We will need the key if we have to make the slow runtime call.
- __ push(ecx);
- __ LoadPowerOf2(xmm1, ecx, 31);
- __ pop(ecx);
- __ ucomisd(xmm1, xmm0);
- __ j(above_equal, &slow);
- __ cvttsd2si(ecx, Operand(xmm0));
+ __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset));
+ // ecx: untagged integer value
+ switch (array_type) {
+ case kExternalPixelArray:
+ { // Clamp the value to [0..255].
+ NearLabel done;
+ __ test(ecx, Immediate(0xFFFFFF00));
+ __ j(zero, &done);
+ __ setcc(negative, ecx); // 1 if negative, 0 if positive.
+ __ dec_b(ecx); // 0 if negative, 255 if positive.
+ __ bind(&done);
+ }
+ __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+ case kExternalByteArray:
+ case kExternalUnsignedByteArray:
+ __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+ break;
+ case kExternalShortArray:
+ case kExternalUnsignedShortArray:
+ __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ } else {
+ if (isolate()->cpu_features()->IsSupported(SSE3)) {
+ CpuFeatures::Scope scope(SSE3);
+ // fisttp stores values as signed integers. To represent the
+ // entire range of int and unsigned int arrays, store as a
+ // 64-bit int and discard the high 32 bits.
+ // If the value is NaN or +/-infinity, the result is 0x80000000,
+ // which is automatically zero when taken mod 2^n, n < 32.
+ __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
+ __ sub(Operand(esp), Immediate(2 * kPointerSize));
+ __ fisttp_d(Operand(esp, 0));
+ __ pop(ecx);
+ __ add(Operand(esp), Immediate(kPointerSize));
+ } else {
+ ASSERT(isolate()->cpu_features()->IsSupported(SSE2));
+ CpuFeatures::Scope scope(SSE2);
+ // We can easily implement the correct rounding behavior for the
+ // range [0, 2^31-1]. For the time being, to keep this code simple,
+ // make the slow runtime call for values outside this range.
+ // Note: we could do better for signed int arrays.
+ __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
+ // We will need the key if we have to make the slow runtime call.
+ __ push(ecx);
+ __ LoadPowerOf2(xmm1, ecx, 31);
+ __ pop(ecx);
+ __ ucomisd(xmm1, xmm0);
+ __ j(above_equal, &slow);
+ __ cvttsd2si(ecx, Operand(xmm0));
+ }
+ // ecx: untagged integer value
+ __ mov(Operand(edi, ebx, times_4, 0), ecx);
}
- // ecx: untagged integer value
- __ mov(Operand(edi, ebx, times_4, 0), ecx);
+ __ ret(0); // Return original value.
}
- __ ret(0); // Return original value.
}
}
diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc
index 93d711e9..2613cafa 100644
--- a/src/ia32/virtual-frame-ia32.cc
+++ b/src/ia32/virtual-frame-ia32.cc
@@ -501,7 +501,7 @@ void VirtualFrame::AllocateStackSlots() {
// them later. First sync everything above the stack pointer so we can
// use pushes to allocate and initialize the locals.
SyncRange(stack_pointer_ + 1, element_count() - 1);
- Handle<Object> undefined = Factory::undefined_value();
+ Handle<Object> undefined = FACTORY->undefined_value();
FrameElement initial_value =
FrameElement::ConstantElement(undefined, FrameElement::SYNCED);
if (count == 1) {
@@ -824,11 +824,11 @@ void VirtualFrame::UntaggedPushFrameSlotAt(int index) {
__ bind(&not_smi);
if (!original.type_info().IsNumber()) {
__ cmp(FieldOperand(fresh_reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
cgen()->unsafe_bailout_->Branch(not_equal);
}
- if (!CpuFeatures::IsSupported(SSE2)) {
+ if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) {
UNREACHABLE();
} else {
CpuFeatures::Scope use_sse2(SSE2);
@@ -931,7 +931,7 @@ Result VirtualFrame::CallJSFunction(int arg_count) {
}
-Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
+Result VirtualFrame::CallRuntime(const Runtime::Function* f, int arg_count) {
PrepareForCall(arg_count, arg_count);
ASSERT(cgen()->HasValidEntryRegisters());
__ CallRuntime(f, arg_count);
@@ -1016,7 +1016,8 @@ Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
PrepareForCall(0, 0); // No stack arguments.
MoveResultsToRegisters(&name, &receiver, ecx, eax);
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kLoadIC_Initialize));
return RawCallCodeObject(ic, mode);
}
@@ -1028,7 +1029,8 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
PrepareForCall(0, 0);
MoveResultsToRegisters(&key, &receiver, eax, edx);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_Initialize));
return RawCallCodeObject(ic, mode);
}
@@ -1038,9 +1040,9 @@ Result VirtualFrame::CallStoreIC(Handle<String> name,
StrictModeFlag strict_mode) {
// Value and (if not contextual) receiver are on top of the frame.
// The IC expects name in ecx, value in eax, and receiver in edx.
- Handle<Code> ic(Builtins::builtin(
- (strict_mode == kStrictMode) ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ (strict_mode == kStrictMode) ? Builtins::kStoreIC_Initialize_Strict
+ : Builtins::kStoreIC_Initialize));
Result value = Pop();
RelocInfo::Mode mode;
@@ -1105,9 +1107,9 @@ Result VirtualFrame::CallKeyedStoreIC(StrictModeFlag strict_mode) {
receiver.Unuse();
}
- Handle<Code> ic(Builtins::builtin(
- (strict_mode == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ (strict_mode == kStrictMode) ? Builtins::kKeyedStoreIC_Initialize_Strict
+ : Builtins::kKeyedStoreIC_Initialize));
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
}
@@ -1119,7 +1121,8 @@ Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
// The IC expects the name in ecx and the rest on the stack and
// drops them all.
InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
+ Handle<Code> ic = Isolate::Current()->stub_cache()->ComputeCallInitialize(
+ arg_count, in_loop);
// Spill args, receiver, and function. The call will drop args and
// receiver.
Result name = Pop();
@@ -1137,7 +1140,9 @@ Result VirtualFrame::CallKeyedCallIC(RelocInfo::Mode mode,
// The IC expects the name in ecx and the rest on the stack and
// drops them all.
InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
+ Handle<Code> ic =
+ Isolate::Current()->stub_cache()->ComputeKeyedCallInitialize(arg_count,
+ in_loop);
// Spill args, receiver, and function. The call will drop args and
// receiver.
Result name = Pop();
@@ -1152,7 +1157,8 @@ Result VirtualFrame::CallConstructor(int arg_count) {
// Arguments, receiver, and function are on top of the frame. The
// IC expects arg count in eax, function in edi, and the arguments
// and receiver on the stack.
- Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kJSConstructCall));
// Duplicate the function before preparing the frame.
PushElementAt(arg_count);
Result function = Pop();
diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h
index 51874309..504a8fc3 100644
--- a/src/ia32/virtual-frame-ia32.h
+++ b/src/ia32/virtual-frame-ia32.h
@@ -67,7 +67,9 @@ class VirtualFrame: public ZoneObject {
private:
bool previous_state_;
- CodeGenerator* cgen() {return CodeGeneratorScope::Current();}
+ CodeGenerator* cgen() {
+ return CodeGeneratorScope::Current(Isolate::Current());
+ }
};
// An illegal index into the virtual frame.
@@ -79,7 +81,9 @@ class VirtualFrame: public ZoneObject {
// Construct a virtual frame as a clone of an existing one.
explicit inline VirtualFrame(VirtualFrame* original);
- CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
+ CodeGenerator* cgen() {
+ return CodeGeneratorScope::Current(Isolate::Current());
+ }
MacroAssembler* masm() { return cgen()->masm(); }
@@ -344,7 +348,7 @@ class VirtualFrame: public ZoneObject {
// Call runtime given the number of arguments expected on (and
// removed from) the stack.
- Result CallRuntime(Runtime::Function* f, int arg_count);
+ Result CallRuntime(const Runtime::Function* f, int arg_count);
Result CallRuntime(Runtime::FunctionId id, int arg_count);
#ifdef ENABLE_DEBUGGER_SUPPORT
diff --git a/src/ic-inl.h b/src/ic-inl.h
index 9d358edd..b4f789cb 100644
--- a/src/ic-inl.h
+++ b/src/ic-inl.h
@@ -41,13 +41,14 @@ Address IC::address() {
Address result = pc() - Assembler::kCallTargetAddressOffset;
#ifdef ENABLE_DEBUGGER_SUPPORT
+ Debug* debug = Isolate::Current()->debug();
// First check if any break points are active if not just return the address
// of the call.
- if (!Debug::has_break_points()) return result;
+ if (!debug->has_break_points()) return result;
// At least one break point is active perform additional test to ensure that
// break point locations are updated correctly.
- if (Debug::IsDebugBreak(Assembler::target_address_at(result))) {
+ if (debug->IsDebugBreak(Assembler::target_address_at(result))) {
// If the call site is a call to debug break then return the address in
// the original code instead of the address in the running code. This will
// cause the original code to be updated and keeps the breakpoint active in
diff --git a/src/ic.cc b/src/ic.cc
index 087a959a..382b438a 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -65,8 +65,8 @@ void IC::TraceIC(const char* type,
const char* extra_info) {
if (FLAG_trace_ic) {
State new_state = StateFrom(new_target,
- Heap::undefined_value(),
- Heap::undefined_value());
+ HEAP->undefined_value(),
+ HEAP->undefined_value());
PrintF("[%s (%c->%c)%s", type,
TransitionMarkFromState(old_state),
TransitionMarkFromState(new_state),
@@ -78,11 +78,13 @@ void IC::TraceIC(const char* type,
#endif
-IC::IC(FrameDepth depth) {
+IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
+ ASSERT(isolate == Isolate::Current());
// To improve the performance of the (much used) IC code, we unfold
// a few levels of the stack frame iteration code. This yields a
// ~35% speedup when running DeltaBlue with the '--nouse-ic' flag.
- const Address entry = Top::c_entry_fp(Top::GetCurrentThread());
+ const Address entry =
+ Isolate::c_entry_fp(isolate->thread_local_top());
Address* pc_address =
reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
@@ -136,9 +138,11 @@ Address IC::OriginalCodeAddress() {
#endif
-static bool HasNormalObjectsInPrototypeChain(LookupResult* lookup,
+static bool HasNormalObjectsInPrototypeChain(Isolate* isolate,
+ LookupResult* lookup,
Object* receiver) {
- Object* end = lookup->IsProperty() ? lookup->holder() : Heap::null_value();
+ Object* end = lookup->IsProperty()
+ ? lookup->holder() : isolate->heap()->null_value();
for (Object* current = receiver;
current != end;
current = current->GetPrototype()) {
@@ -231,7 +235,7 @@ IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
RelocInfo::Mode IC::ComputeMode() {
Address addr = address();
- Code* code = Code::cast(Heap::FindCodeObject(addr));
+ Code* code = Code::cast(isolate()->heap()->FindCodeObject(addr));
for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
!it.done(); it.next()) {
RelocInfo* info = it.rinfo();
@@ -245,18 +249,19 @@ RelocInfo::Mode IC::ComputeMode() {
Failure* IC::TypeError(const char* type,
Handle<Object> object,
Handle<Object> key) {
- HandleScope scope;
+ HandleScope scope(isolate());
Handle<Object> args[2] = { key, object };
- Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2));
- return Top::Throw(*error);
+ Handle<Object> error = isolate()->factory()->NewTypeError(
+ type, HandleVector(args, 2));
+ return isolate()->Throw(*error);
}
Failure* IC::ReferenceError(const char* type, Handle<String> name) {
- HandleScope scope;
- Handle<Object> error =
- Factory::NewReferenceError(type, HandleVector(&name, 1));
- return Top::Throw(*error);
+ HandleScope scope(isolate());
+ Handle<Object> error = isolate()->factory()->NewReferenceError(
+ type, HandleVector(&name, 1));
+ return isolate()->Throw(*error);
}
@@ -268,9 +273,13 @@ void IC::Clear(Address address) {
switch (target->kind()) {
case Code::LOAD_IC: return LoadIC::Clear(address, target);
- case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target);
+ case Code::KEYED_LOAD_IC:
+ case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC:
+ return KeyedLoadIC::Clear(address, target);
case Code::STORE_IC: return StoreIC::Clear(address, target);
- case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
+ case Code::KEYED_STORE_IC:
+ case Code::KEYED_EXTERNAL_ARRAY_STORE_IC:
+ return KeyedStoreIC::Clear(address, target);
case Code::CALL_IC: return CallIC::Clear(address, target);
case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
case Code::BINARY_OP_IC:
@@ -288,9 +297,10 @@ void CallICBase::Clear(Address address, Code* target) {
State state = target->ic_state();
if (state == UNINITIALIZED) return;
Code* code =
- StubCache::FindCallInitialize(target->arguments_count(),
- target->ic_in_loop(),
- target->kind());
+ Isolate::Current()->stub_cache()->FindCallInitialize(
+ target->arguments_count(),
+ target->ic_in_loop(),
+ target->kind());
SetTargetAtAddress(address, code);
}
@@ -298,7 +308,7 @@ void CallICBase::Clear(Address address, Code* target) {
void KeyedLoadIC::ClearInlinedVersion(Address address) {
// Insert null as the map to check for to make sure the map check fails
// sending control flow to the IC instead of the inlined version.
- PatchInlinedLoad(address, Heap::null_value());
+ PatchInlinedLoad(address, HEAP->null_value());
}
@@ -316,10 +326,11 @@ void LoadIC::ClearInlinedVersion(Address address) {
// Reset the map check of the inlined inobject property load (if
// present) to guarantee failure by holding an invalid map (the null
// value). The offset can be patched to anything.
- PatchInlinedLoad(address, Heap::null_value(), 0);
+ Heap* heap = HEAP;
+ PatchInlinedLoad(address, heap->null_value(), 0);
PatchInlinedContextualLoad(address,
- Heap::null_value(),
- Heap::null_value(),
+ heap->null_value(),
+ heap->null_value(),
true);
}
@@ -335,7 +346,7 @@ void StoreIC::ClearInlinedVersion(Address address) {
// Reset the map check of the inlined inobject property store (if
// present) to guarantee failure by holding an invalid map (the null
// value). The offset can be patched to anything.
- PatchInlinedStore(address, Heap::null_value(), 0);
+ PatchInlinedStore(address, HEAP->null_value(), 0);
}
@@ -353,14 +364,14 @@ void KeyedStoreIC::ClearInlinedVersion(Address address) {
// Insert null as the elements map to check for. This will make
// sure that the elements fast-case map check fails so that control
// flows to the IC instead of the inlined version.
- PatchInlinedStore(address, Heap::null_value());
+ PatchInlinedStore(address, HEAP->null_value());
}
void KeyedStoreIC::RestoreInlinedVersion(Address address) {
// Restore the fast-case elements map check so that the inlined
// version can be used again.
- PatchInlinedStore(address, Heap::fixed_array_map());
+ PatchInlinedStore(address, HEAP->fixed_array_map());
}
@@ -419,8 +430,8 @@ static void LookupForRead(Object* object,
Object* CallICBase::TryCallAsFunction(Object* object) {
- HandleScope scope;
- Handle<Object> target(object);
+ HandleScope scope(isolate());
+ Handle<Object> target(object, isolate());
Handle<Object> delegate = Execution::GetFunctionDelegate(target);
if (delegate->IsJSFunction()) {
@@ -455,7 +466,7 @@ void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
int index = frame->ComputeExpressionsCount() - (argc + 1);
- frame->SetExpression(index, *Factory::ToObject(object));
+ frame->SetExpression(index, *isolate()->factory()->ToObject(object));
}
}
@@ -527,7 +538,7 @@ MaybeObject* CallICBase::LoadFunction(State state,
ASSERT(!result->IsTheHole());
- HandleScope scope;
+ HandleScope scope(isolate());
// Wrap result in a handle because ReceiverToObjectIfRequired may allocate
// new object and cause GC.
Handle<Object> result_handle(result);
@@ -539,11 +550,12 @@ MaybeObject* CallICBase::LoadFunction(State state,
if (result_handle->IsJSFunction()) {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Handle stepping into a function if step into is active.
- if (Debug::StepInActive()) {
+ Debug* debug = isolate()->debug();
+ if (debug->StepInActive()) {
// Protect the result in a handle as the debugger can allocate and might
// cause GC.
- Handle<JSFunction> function(JSFunction::cast(*result_handle));
- Debug::HandleStepIn(function, object, fp(), false);
+ Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate());
+ debug->HandleStepIn(function, object, fp(), false);
return *function;
}
#endif
@@ -569,7 +581,7 @@ bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
// Fetch the arguments passed to the called function.
const int argc = target()->arguments_count();
- Address entry = Top::c_entry_fp(Top::GetCurrentThread());
+ Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
Arguments args(argc + 1,
&Memory::Object_at(fp +
@@ -619,13 +631,13 @@ MaybeObject* CallICBase::ComputeMonomorphicStub(
switch (lookup->type()) {
case FIELD: {
int index = lookup->GetFieldIndex();
- maybe_code = StubCache::ComputeCallField(argc,
- in_loop,
- kind_,
- *name,
- *object,
- lookup->holder(),
- index);
+ maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
+ in_loop,
+ kind_,
+ *name,
+ *object,
+ lookup->holder(),
+ index);
break;
}
case CONSTANT_FUNCTION: {
@@ -633,14 +645,15 @@ MaybeObject* CallICBase::ComputeMonomorphicStub(
// call; used for rewriting to monomorphic state and making sure
// that the code stub is in the stub cache.
JSFunction* function = lookup->GetConstantFunction();
- maybe_code = StubCache::ComputeCallConstant(argc,
- in_loop,
- kind_,
- extra_ic_state,
- *name,
- *object,
- lookup->holder(),
- function);
+ maybe_code =
+ isolate()->stub_cache()->ComputeCallConstant(argc,
+ in_loop,
+ kind_,
+ extra_ic_state,
+ *name,
+ *object,
+ lookup->holder(),
+ function);
break;
}
case NORMAL: {
@@ -653,35 +666,36 @@ MaybeObject* CallICBase::ComputeMonomorphicStub(
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
if (!cell->value()->IsJSFunction()) return NULL;
JSFunction* function = JSFunction::cast(cell->value());
- maybe_code = StubCache::ComputeCallGlobal(argc,
- in_loop,
- kind_,
- *name,
- *receiver,
- global,
- cell,
- function);
+ maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
+ in_loop,
+ kind_,
+ *name,
+ *receiver,
+ global,
+ cell,
+ function);
} else {
// There is only one shared stub for calling normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// applicable.
if (lookup->holder() != *receiver) return NULL;
- maybe_code = StubCache::ComputeCallNormal(argc,
- in_loop,
- kind_,
- *name,
- *receiver);
+ maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
+ in_loop,
+ kind_,
+ *name,
+ *receiver);
}
break;
}
case INTERCEPTOR: {
ASSERT(HasInterceptorGetter(lookup->holder()));
- maybe_code = StubCache::ComputeCallInterceptor(argc,
- kind_,
- *name,
- *object,
- lookup->holder());
+ maybe_code = isolate()->stub_cache()->ComputeCallInterceptor(
+ argc,
+ kind_,
+ *name,
+ *object,
+ lookup->holder());
break;
}
default:
@@ -701,7 +715,8 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
if (lookup->holder() != *object &&
- HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) {
+ HasNormalObjectsInPrototypeChain(
+ isolate(), lookup, object->GetPrototype())) {
// Suppress optimization for prototype chains with slow properties objects
// in the middle.
return;
@@ -716,7 +731,9 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
// This is the first time we execute this inline cache.
// Set the target to the pre monomorphic stub to delay
// setting the monomorphic state.
- maybe_code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_);
+ maybe_code = isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
+ in_loop,
+ kind_);
} else if (state == MONOMORPHIC) {
if (kind_ == Code::CALL_IC &&
TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
@@ -736,7 +753,9 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
object,
name);
} else {
- maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_);
+ maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(argc,
+ in_loop,
+ kind_);
}
} else {
maybe_code = ComputeMonomorphicStub(lookup,
@@ -764,7 +783,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
object->GetPrototype())->map();
// Update the stub cache.
- StubCache::Set(*name, map, Code::cast(code));
+ isolate()->stub_cache()->Set(*name, map, Code::cast(code));
}
USE(had_proto_failure);
@@ -793,7 +812,7 @@ MaybeObject* KeyedCallIC::LoadFunction(State state,
if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) {
int argc = target()->arguments_count();
InLoopFlag in_loop = target()->ic_in_loop();
- MaybeObject* maybe_code = StubCache::ComputeCallMegamorphic(
+ MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
argc, in_loop, Code::KEYED_CALL_IC);
Object* code;
if (maybe_code->ToObject(&code)) {
@@ -805,9 +824,9 @@ MaybeObject* KeyedCallIC::LoadFunction(State state,
}
}
- HandleScope scope;
+ HandleScope scope(isolate());
Handle<Object> result = GetProperty(object, key);
- RETURN_IF_EMPTY_HANDLE(result);
+ RETURN_IF_EMPTY_HANDLE(isolate(), result);
// Make receiver an object if the callee requires it. Strict mode or builtin
// functions do not wrap the receiver, non-strict functions and objects
@@ -848,8 +867,8 @@ MaybeObject* LoadIC::Load(State state,
// objects is read-only and therefore always returns the length of
// the underlying string value. See ECMA-262 15.5.5.1.
if ((object->IsString() || object->IsStringWrapper()) &&
- name->Equals(Heap::length_symbol())) {
- HandleScope scope;
+ name->Equals(isolate()->heap()->length_symbol())) {
+ HandleScope scope(isolate());
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
#endif
@@ -858,24 +877,29 @@ MaybeObject* LoadIC::Load(State state,
Map* map = HeapObject::cast(*object)->map();
const int offset = String::kLengthOffset;
PatchInlinedLoad(address(), map, offset);
- set_target(Builtins::builtin(Builtins::LoadIC_StringLength));
+ set_target(isolate()->builtins()->builtin(
+ Builtins::kLoadIC_StringLength));
} else {
- set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength));
+ set_target(isolate()->builtins()->builtin(
+ Builtins::kLoadIC_StringWrapperLength));
}
} else if (state == MONOMORPHIC && object->IsStringWrapper()) {
- set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength));
+ set_target(isolate()->builtins()->builtin(
+ Builtins::kLoadIC_StringWrapperLength));
} else {
set_target(non_monomorphic_stub);
}
// Get the string if we have a string wrapper object.
if (object->IsJSValue()) {
- object = Handle<Object>(Handle<JSValue>::cast(object)->value());
+ object = Handle<Object>(Handle<JSValue>::cast(object)->value(),
+ isolate());
}
return Smi::FromInt(String::cast(*object)->length());
}
// Use specialized code for getting the length of arrays.
- if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
+ if (object->IsJSArray() &&
+ name->Equals(isolate()->heap()->length_symbol())) {
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
#endif
@@ -883,7 +907,8 @@ MaybeObject* LoadIC::Load(State state,
Map* map = HeapObject::cast(*object)->map();
const int offset = JSArray::kLengthOffset;
PatchInlinedLoad(address(), map, offset);
- set_target(Builtins::builtin(Builtins::LoadIC_ArrayLength));
+ set_target(isolate()->builtins()->builtin(
+ Builtins::kLoadIC_ArrayLength));
} else {
set_target(non_monomorphic_stub);
}
@@ -891,13 +916,15 @@ MaybeObject* LoadIC::Load(State state,
}
// Use specialized code for getting prototype of functions.
- if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) &&
+ if (object->IsJSFunction() &&
+ name->Equals(isolate()->heap()->prototype_symbol()) &&
JSFunction::cast(*object)->should_have_prototype()) {
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
#endif
if (state == PREMONOMORPHIC) {
- set_target(Builtins::builtin(Builtins::LoadIC_FunctionPrototype));
+ set_target(isolate()->builtins()->builtin(
+ Builtins::kLoadIC_FunctionPrototype));
} else {
set_target(non_monomorphic_stub);
}
@@ -919,7 +946,7 @@ MaybeObject* LoadIC::Load(State state,
if (FLAG_strict || IsContextual(object)) {
return ReferenceError("not_defined", name);
}
- LOG(SuspectReadEvent(*name, *object));
+ LOG(isolate(), SuspectReadEvent(*name, *object));
}
bool can_be_inlined_precheck =
@@ -970,7 +997,7 @@ MaybeObject* LoadIC::Load(State state,
lookup.IsDontDelete())) {
set_target(megamorphic_stub());
TRACE_IC_NAMED("[LoadIC : inline contextual patch %s]\n", name);
- ASSERT(cell->value() != Heap::the_hole_value());
+ ASSERT(cell->value() != isolate()->heap()->the_hole_value());
return cell->value();
}
} else {
@@ -1017,7 +1044,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
if (!object->IsJSObject()) return;
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- if (HasNormalObjectsInPrototypeChain(lookup, *object)) return;
+ if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
// Compute the code stub for this load.
MaybeObject* maybe_code = NULL;
@@ -1029,20 +1056,23 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
maybe_code = pre_monomorphic_stub();
} else if (!lookup->IsProperty()) {
// Nonexistent property. The result is undefined.
- maybe_code = StubCache::ComputeLoadNonexistent(*name, *receiver);
+ maybe_code = isolate()->stub_cache()->ComputeLoadNonexistent(*name,
+ *receiver);
} else {
// Compute monomorphic stub.
switch (lookup->type()) {
case FIELD: {
- maybe_code = StubCache::ComputeLoadField(*name, *receiver,
- lookup->holder(),
- lookup->GetFieldIndex());
+ maybe_code = isolate()->stub_cache()->ComputeLoadField(
+ *name,
+ *receiver,
+ lookup->holder(),
+ lookup->GetFieldIndex());
break;
}
case CONSTANT_FUNCTION: {
Object* constant = lookup->GetConstantFunction();
- maybe_code = StubCache::ComputeLoadConstant(*name, *receiver,
- lookup->holder(), constant);
+ maybe_code = isolate()->stub_cache()->ComputeLoadConstant(
+ *name, *receiver, lookup->holder(), constant);
break;
}
case NORMAL: {
@@ -1050,7 +1080,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
GlobalObject* global = GlobalObject::cast(lookup->holder());
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
- maybe_code = StubCache::ComputeLoadGlobal(*name,
+ maybe_code = isolate()->stub_cache()->ComputeLoadGlobal(*name,
*receiver,
global,
cell,
@@ -1061,7 +1091,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
// property must be found in the receiver for the stub to be
// applicable.
if (lookup->holder() != *receiver) return;
- maybe_code = StubCache::ComputeLoadNormal();
+ maybe_code = isolate()->stub_cache()->ComputeLoadNormal();
}
break;
}
@@ -1070,14 +1100,14 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
AccessorInfo* callback =
AccessorInfo::cast(lookup->GetCallbackObject());
if (v8::ToCData<Address>(callback->getter()) == 0) return;
- maybe_code = StubCache::ComputeLoadCallback(*name, *receiver,
- lookup->holder(), callback);
+ maybe_code = isolate()->stub_cache()->ComputeLoadCallback(
+ *name, *receiver, lookup->holder(), callback);
break;
}
case INTERCEPTOR: {
ASSERT(HasInterceptorGetter(lookup->holder()));
- maybe_code = StubCache::ComputeLoadInterceptor(*name, *receiver,
- lookup->holder());
+ maybe_code = isolate()->stub_cache()->ComputeLoadInterceptor(
+ *name, *receiver, lookup->holder());
break;
}
default:
@@ -1101,7 +1131,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
Map* map = JSObject::cast(object->IsJSObject() ? *object :
object->GetPrototype())->map();
- StubCache::Set(*name, map, Code::cast(code));
+ isolate()->stub_cache()->Set(*name, map, Code::cast(code));
}
#ifdef DEBUG
@@ -1126,11 +1156,13 @@ MaybeObject* KeyedLoadIC::Load(State state,
// TODO(1073): don't ignore the current stub state.
// Use specialized code for getting the length of strings.
- if (object->IsString() && name->Equals(Heap::length_symbol())) {
+ if (object->IsString() &&
+ name->Equals(isolate()->heap()->length_symbol())) {
Handle<String> string = Handle<String>::cast(object);
Object* code = NULL;
{ MaybeObject* maybe_code =
- StubCache::ComputeKeyedLoadStringLength(*name, *string);
+ isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name,
+ *string);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
set_target(Code::cast(code));
@@ -1141,11 +1173,13 @@ MaybeObject* KeyedLoadIC::Load(State state,
}
// Use specialized code for getting the length of arrays.
- if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
+ if (object->IsJSArray() &&
+ name->Equals(isolate()->heap()->length_symbol())) {
Handle<JSArray> array = Handle<JSArray>::cast(object);
Object* code;
{ MaybeObject* maybe_code =
- StubCache::ComputeKeyedLoadArrayLength(*name, *array);
+ isolate()->stub_cache()->ComputeKeyedLoadArrayLength(*name,
+ *array);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
set_target(Code::cast(code));
@@ -1156,12 +1190,14 @@ MaybeObject* KeyedLoadIC::Load(State state,
}
// Use specialized code for getting prototype of functions.
- if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) &&
+ if (object->IsJSFunction() &&
+ name->Equals(isolate()->heap()->prototype_symbol()) &&
JSFunction::cast(*object)->should_have_prototype()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(object);
Object* code;
{ MaybeObject* maybe_code =
- StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function);
+ isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype(
+ *name, *function);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
set_target(Code::cast(code));
@@ -1176,10 +1212,10 @@ MaybeObject* KeyedLoadIC::Load(State state,
// the element or char if so.
uint32_t index = 0;
if (name->AsArrayIndex(&index)) {
- HandleScope scope;
+ HandleScope scope(isolate());
// Rewrite to the generic keyed load stub.
if (FLAG_use_ic) set_target(generic_stub());
- return Runtime::GetElementOrCharAt(object, index);
+ return Runtime::GetElementOrCharAt(isolate(), object, index);
}
// Named lookup.
@@ -1229,22 +1265,16 @@ MaybeObject* KeyedLoadIC::Load(State state,
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (receiver->HasExternalArrayElements()) {
MaybeObject* probe =
- StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver,
- false,
- kNonStrictMode);
+ isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
+ *receiver, false, kNonStrictMode);
stub = probe->IsFailure() ?
NULL : Code::cast(probe->ToObjectUnchecked());
} else if (receiver->HasIndexedInterceptor()) {
stub = indexed_interceptor_stub();
- } else if (receiver->HasPixelElements()) {
- MaybeObject* probe =
- StubCache::ComputeKeyedLoadPixelArray(*receiver);
- stub = probe->IsFailure() ?
- NULL : Code::cast(probe->ToObjectUnchecked());
} else if (key->IsSmi() &&
receiver->map()->has_fast_elements()) {
MaybeObject* probe =
- StubCache::ComputeKeyedLoadSpecialized(*receiver);
+ isolate()->stub_cache()->ComputeKeyedLoadSpecialized(*receiver);
stub = probe->IsFailure() ?
NULL : Code::cast(probe->ToObjectUnchecked());
}
@@ -1270,7 +1300,7 @@ MaybeObject* KeyedLoadIC::Load(State state,
}
// Get the property.
- return Runtime::GetObjectProperty(object, key);
+ return Runtime::GetObjectProperty(isolate(), object, key);
}
@@ -1282,7 +1312,7 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
if (!object->IsJSObject()) return;
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- if (HasNormalObjectsInPrototypeChain(lookup, *object)) return;
+ if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
// Compute the code stub for this load.
MaybeObject* maybe_code = NULL;
@@ -1297,17 +1327,14 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
// Compute a monomorphic stub.
switch (lookup->type()) {
case FIELD: {
- maybe_code = StubCache::ComputeKeyedLoadField(*name, *receiver,
- lookup->holder(),
- lookup->GetFieldIndex());
+ maybe_code = isolate()->stub_cache()->ComputeKeyedLoadField(
+ *name, *receiver, lookup->holder(), lookup->GetFieldIndex());
break;
}
case CONSTANT_FUNCTION: {
Object* constant = lookup->GetConstantFunction();
- maybe_code = StubCache::ComputeKeyedLoadConstant(*name,
- *receiver,
- lookup->holder(),
- constant);
+ maybe_code = isolate()->stub_cache()->ComputeKeyedLoadConstant(
+ *name, *receiver, lookup->holder(), constant);
break;
}
case CALLBACKS: {
@@ -1315,16 +1342,14 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
AccessorInfo* callback =
AccessorInfo::cast(lookup->GetCallbackObject());
if (v8::ToCData<Address>(callback->getter()) == 0) return;
- maybe_code = StubCache::ComputeKeyedLoadCallback(*name,
- *receiver,
- lookup->holder(),
- callback);
+ maybe_code = isolate()->stub_cache()->ComputeKeyedLoadCallback(
+ *name, *receiver, lookup->holder(), callback);
break;
}
case INTERCEPTOR: {
ASSERT(HasInterceptorGetter(lookup->holder()));
- maybe_code = StubCache::ComputeKeyedLoadInterceptor(*name, *receiver,
- lookup->holder());
+ maybe_code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
+ *name, *receiver, lookup->holder());
break;
}
default: {
@@ -1400,7 +1425,7 @@ MaybeObject* StoreIC::Store(State state,
if (!object->IsJSObject()) {
// The length property of string values is read-only. Throw in strict mode.
if (strict_mode == kStrictMode && object->IsString() &&
- name->Equals(Heap::length_symbol())) {
+ name->Equals(isolate()->heap()->length_symbol())) {
return TypeError("strict_read_only_property", object, name);
}
// Ignore stores where the receiver is not a JSObject.
@@ -1412,7 +1437,7 @@ MaybeObject* StoreIC::Store(State state,
// Check if the given name is an array index.
uint32_t index;
if (name->AsArrayIndex(&index)) {
- HandleScope scope;
+ HandleScope scope(isolate());
Handle<Object> result = SetElement(receiver, index, value, strict_mode);
if (result.is_null()) return Failure::Exception();
return *value;
@@ -1420,15 +1445,15 @@ MaybeObject* StoreIC::Store(State state,
// Use specialized code for setting the length of arrays.
if (receiver->IsJSArray()
- && name->Equals(Heap::length_symbol())
+ && name->Equals(isolate()->heap()->length_symbol())
&& receiver->AllowsSetElementsLength()) {
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
#endif
Builtins::Name target = (strict_mode == kStrictMode)
- ? Builtins::StoreIC_ArrayLength_Strict
- : Builtins::StoreIC_ArrayLength;
- set_target(Builtins::builtin(target));
+ ? Builtins::kStoreIC_ArrayLength_Strict
+ : Builtins::kStoreIC_ArrayLength;
+ set_target(isolate()->builtins()->builtin(target));
return receiver->SetProperty(*name, *value, NONE, strict_mode);
}
@@ -1544,17 +1569,17 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
Object* code = NULL;
switch (type) {
case FIELD: {
- maybe_code = StubCache::ComputeStoreField(
+ maybe_code = isolate()->stub_cache()->ComputeStoreField(
*name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
break;
}
case MAP_TRANSITION: {
if (lookup->GetAttributes() != NONE) return;
- HandleScope scope;
+ HandleScope scope(isolate());
ASSERT(type == MAP_TRANSITION);
Handle<Map> transition(lookup->GetTransitionMap());
int index = transition->PropertyIndexFor(*name);
- maybe_code = StubCache::ComputeStoreField(
+ maybe_code = isolate()->stub_cache()->ComputeStoreField(
*name, *receiver, index, *transition, strict_mode);
break;
}
@@ -1566,11 +1591,11 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
- maybe_code = StubCache::ComputeStoreGlobal(
+ maybe_code = isolate()->stub_cache()->ComputeStoreGlobal(
*name, *global, cell, strict_mode);
} else {
if (lookup->holder() != *receiver) return;
- maybe_code = StubCache::ComputeStoreNormal(strict_mode);
+ maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
}
break;
}
@@ -1578,13 +1603,13 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
if (v8::ToCData<Address>(callback->setter()) == 0) return;
- maybe_code = StubCache::ComputeStoreCallback(
+ maybe_code = isolate()->stub_cache()->ComputeStoreCallback(
*name, *receiver, callback, strict_mode);
break;
}
case INTERCEPTOR: {
ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
- maybe_code = StubCache::ComputeStoreInterceptor(
+ maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor(
*name, *receiver, strict_mode);
break;
}
@@ -1608,7 +1633,9 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
}
} else if (state == MEGAMORPHIC) {
// Update the stub cache.
- StubCache::Set(*name, receiver->map(), Code::cast(code));
+ isolate()->stub_cache()->Set(*name,
+ receiver->map(),
+ Code::cast(code));
}
#ifdef DEBUG
@@ -1638,7 +1665,7 @@ MaybeObject* KeyedStoreIC::Store(State state,
// Check if the given name is an array index.
uint32_t index;
if (name->AsArrayIndex(&index)) {
- HandleScope scope;
+ HandleScope scope(isolate());
Handle<Object> result = SetElement(receiver, index, value, strict_mode);
if (result.is_null()) return Failure::Exception();
return *value;
@@ -1670,18 +1697,14 @@ MaybeObject* KeyedStoreIC::Store(State state,
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (receiver->HasExternalArrayElements()) {
MaybeObject* probe =
- StubCache::ComputeKeyedLoadOrStoreExternalArray(
+ isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
*receiver, true, strict_mode);
stub = probe->IsFailure() ?
NULL : Code::cast(probe->ToObjectUnchecked());
- } else if (receiver->HasPixelElements()) {
- MaybeObject* probe =
- StubCache::ComputeKeyedStorePixelArray(*receiver, strict_mode);
- stub = probe->IsFailure() ?
- NULL : Code::cast(probe->ToObjectUnchecked());
} else if (key->IsSmi() && receiver->map()->has_fast_elements()) {
MaybeObject* probe =
- StubCache::ComputeKeyedStoreSpecialized(*receiver, strict_mode);
+ isolate()->stub_cache()->ComputeKeyedStoreSpecialized(
+ *receiver, strict_mode);
stub = probe->IsFailure() ?
NULL : Code::cast(probe->ToObjectUnchecked());
}
@@ -1691,7 +1714,8 @@ MaybeObject* KeyedStoreIC::Store(State state,
}
// Set the property.
- return Runtime::SetObjectProperty(object, key, value, NONE, strict_mode);
+ return Runtime::SetObjectProperty(
+ isolate(), object , key, value, NONE, strict_mode);
}
@@ -1724,17 +1748,17 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
switch (type) {
case FIELD: {
- maybe_code = StubCache::ComputeKeyedStoreField(
+ maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
*name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
break;
}
case MAP_TRANSITION: {
if (lookup->GetAttributes() == NONE) {
- HandleScope scope;
+ HandleScope scope(isolate());
ASSERT(type == MAP_TRANSITION);
Handle<Map> transition(lookup->GetTransitionMap());
int index = transition->PropertyIndexFor(*name);
- maybe_code = StubCache::ComputeKeyedStoreField(
+ maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
*name, *receiver, index, *transition, strict_mode);
break;
}
@@ -1775,11 +1799,12 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
// Static IC stub generators.
//
-static JSFunction* CompileFunction(JSFunction* function,
+static JSFunction* CompileFunction(Isolate* isolate,
+ JSFunction* function,
InLoopFlag in_loop) {
// Compile now with optimization.
- HandleScope scope;
- Handle<JSFunction> function_handle(function);
+ HandleScope scope(isolate);
+ Handle<JSFunction> function_handle(function, isolate);
if (in_loop == IN_LOOP) {
CompileLazyInLoop(function_handle, CLEAR_EXCEPTION);
} else {
@@ -1790,10 +1815,11 @@ static JSFunction* CompileFunction(JSFunction* function,
// Used from ic-<arch>.cc.
-MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) {
+MUST_USE_RESULT MaybeObject* CallIC_Miss(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 2);
- CallIC ic;
+ CallIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
MaybeObject* maybe_result = ic.LoadFunction(state,
@@ -1813,15 +1839,18 @@ MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) {
if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
return result;
}
- return CompileFunction(JSFunction::cast(result), ic.target()->ic_in_loop());
+ return CompileFunction(isolate,
+ JSFunction::cast(result),
+ ic.target()->ic_in_loop());
}
// Used from ic-<arch>.cc.
-MUST_USE_RESULT MaybeObject* KeyedCallIC_Miss(Arguments args) {
+MUST_USE_RESULT MaybeObject* KeyedCallIC_Miss(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 2);
- KeyedCallIC ic;
+ KeyedCallIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
Object* result;
{ MaybeObject* maybe_result =
@@ -1832,35 +1861,40 @@ MUST_USE_RESULT MaybeObject* KeyedCallIC_Miss(Arguments args) {
if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
return result;
}
- return CompileFunction(JSFunction::cast(result), ic.target()->ic_in_loop());
+ return CompileFunction(isolate,
+ JSFunction::cast(result),
+ ic.target()->ic_in_loop());
}
// Used from ic-<arch>.cc.
-MUST_USE_RESULT MaybeObject* LoadIC_Miss(Arguments args) {
+MUST_USE_RESULT MaybeObject* LoadIC_Miss(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 2);
- LoadIC ic;
+ LoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
return ic.Load(state, args.at<Object>(0), args.at<String>(1));
}
// Used from ic-<arch>.cc
-MUST_USE_RESULT MaybeObject* KeyedLoadIC_Miss(Arguments args) {
+MUST_USE_RESULT MaybeObject* KeyedLoadIC_Miss(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 2);
- KeyedLoadIC ic;
+ KeyedLoadIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
}
// Used from ic-<arch>.cc.
-MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) {
+MUST_USE_RESULT MaybeObject* StoreIC_Miss(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 3);
- StoreIC ic;
+ StoreIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
return ic.Store(state,
@@ -1871,7 +1905,8 @@ MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) {
}
-MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) {
+MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation nha;
ASSERT(args.length() == 2);
@@ -1892,7 +1927,9 @@ MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) {
// Extend storage is called in a store inline cache when
// it is necessary to extend the properties array of a
// JSObject.
-MUST_USE_RESULT MaybeObject* SharedStoreIC_ExtendStorage(Arguments args) {
+MUST_USE_RESULT MaybeObject* SharedStoreIC_ExtendStorage(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 3);
@@ -1926,10 +1963,11 @@ MUST_USE_RESULT MaybeObject* SharedStoreIC_ExtendStorage(Arguments args) {
// Used from ic-<arch>.cc.
-MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(Arguments args) {
+MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 3);
- KeyedStoreIC ic;
+ KeyedStoreIC ic(isolate);
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
return ic.Store(state,
@@ -1999,10 +2037,11 @@ BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Object* left,
Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info);
-MUST_USE_RESULT MaybeObject* BinaryOp_Patch(Arguments args) {
+MUST_USE_RESULT MaybeObject* BinaryOp_Patch(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 5);
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<Object> left = args.at<Object>(0);
Handle<Object> right = args.at<Object>(1);
int key = Smi::cast(args[2])->value();
@@ -2013,7 +2052,7 @@ MUST_USE_RESULT MaybeObject* BinaryOp_Patch(Arguments args) {
BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(*left, *right);
Handle<Code> code = GetBinaryOpStub(key, type);
if (!code.is_null()) {
- BinaryOpIC ic;
+ BinaryOpIC ic(isolate);
ic.patch(*code);
if (FLAG_trace_ic) {
PrintF("[BinaryOpIC (%s->%s)#%s]\n",
@@ -2023,7 +2062,8 @@ MUST_USE_RESULT MaybeObject* BinaryOp_Patch(Arguments args) {
}
}
- Handle<JSBuiltinsObject> builtins = Top::builtins();
+ Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
+ isolate->thread_local_top()->context_->builtins(), isolate);
Object* builtin = NULL; // Initialization calms down the compiler.
switch (op) {
case Token::ADD:
@@ -2063,7 +2103,8 @@ MUST_USE_RESULT MaybeObject* BinaryOp_Patch(Arguments args) {
UNREACHABLE();
}
- Handle<JSFunction> builtin_function(JSFunction::cast(builtin));
+ Handle<JSFunction> builtin_function(JSFunction::cast(builtin),
+ isolate);
bool caught_exception;
Object** builtin_args[] = { right.location() };
@@ -2090,6 +2131,7 @@ const char* TRBinaryOpIC::GetName(TypeInfo type_info) {
case SMI: return "SMI";
case INT32: return "Int32s";
case HEAP_NUMBER: return "HeapNumbers";
+ case ODDBALL: return "Oddball";
case STRING: return "Strings";
case GENERIC: return "Generic";
default: return "Invalid";
@@ -2104,6 +2146,7 @@ TRBinaryOpIC::State TRBinaryOpIC::ToState(TypeInfo type_info) {
case SMI:
case INT32:
case HEAP_NUMBER:
+ case ODDBALL:
case STRING:
return MONOMORPHIC;
case GENERIC:
@@ -2151,6 +2194,10 @@ TRBinaryOpIC::TypeInfo TRBinaryOpIC::GetTypeInfo(Handle<Object> left,
return STRING;
}
+ // Check for oddball objects.
+ if (left->IsUndefined() && right->IsNumber()) return ODDBALL;
+ if (left->IsNumber() && right->IsUndefined()) return ODDBALL;
+
return GENERIC;
}
@@ -2162,10 +2209,11 @@ Handle<Code> GetTypeRecordingBinaryOpStub(int key,
TRBinaryOpIC::TypeInfo result_type);
-MaybeObject* TypeRecordingBinaryOp_Patch(Arguments args) {
+MaybeObject* TypeRecordingBinaryOp_Patch(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 5);
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<Object> left = args.at<Object>(0);
Handle<Object> right = args.at<Object>(1);
int key = Smi::cast(args[2])->value();
@@ -2207,7 +2255,7 @@ MaybeObject* TypeRecordingBinaryOp_Patch(Arguments args) {
TRBinaryOpIC::GetName(result_type),
Token::Name(op));
}
- TRBinaryOpIC ic;
+ TRBinaryOpIC ic(isolate);
ic.patch(*code);
// Activate inlined smi code.
@@ -2216,7 +2264,8 @@ MaybeObject* TypeRecordingBinaryOp_Patch(Arguments args) {
}
}
- Handle<JSBuiltinsObject> builtins = Top::builtins();
+ Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
+ isolate->thread_local_top()->context_->builtins(), isolate);
Object* builtin = NULL; // Initialization calms down the compiler.
switch (op) {
case Token::ADD:
@@ -2256,7 +2305,7 @@ MaybeObject* TypeRecordingBinaryOp_Patch(Arguments args) {
UNREACHABLE();
}
- Handle<JSFunction> builtin_function(JSFunction::cast(builtin));
+ Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate);
bool caught_exception;
Object** builtin_args[] = { right.location() };
@@ -2316,16 +2365,17 @@ CompareIC::State CompareIC::TargetState(State state,
// Used from ic_<arch>.cc.
-Code* CompareIC_Miss(Arguments args) {
+Code* CompareIC_Miss(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 3);
- CompareIC ic(static_cast<Token::Value>(Smi::cast(args[2])->value()));
+ CompareIC ic(isolate, static_cast<Token::Value>(Smi::cast(args[2])->value()));
ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
return ic.target();
}
-static Address IC_utilities[] = {
+static const Address IC_utilities[] = {
#define ADDR(name) FUNCTION_ADDR(name),
IC_UTIL_LIST(ADDR)
NULL
diff --git a/src/ic.h b/src/ic.h
index e12cbaf8..bb8a9813 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -86,7 +86,7 @@ class IC {
// Construct the IC structure with the given number of extra
// JavaScript frames on the stack.
- explicit IC(FrameDepth depth);
+ IC(FrameDepth depth, Isolate* isolate);
// Get the call-site target; used for determining the state.
Code* target() { return GetTargetAtAddress(address()); }
@@ -130,6 +130,7 @@ class IC {
protected:
Address fp() const { return fp_; }
Address pc() const { return *pc_address_; }
+ Isolate* isolate() const { return isolate_; }
#ifdef ENABLE_DEBUGGER_SUPPORT
// Computes the address in the original code when the code running is
@@ -148,10 +149,10 @@ class IC {
const char* extra_info = "");
#endif
- static Failure* TypeError(const char* type,
- Handle<Object> object,
- Handle<Object> key);
- static Failure* ReferenceError(const char* type, Handle<String> name);
+ Failure* TypeError(const char* type,
+ Handle<Object> object,
+ Handle<Object> key);
+ Failure* ReferenceError(const char* type, Handle<String> name);
// Access the target code for the given IC address.
static inline Code* GetTargetAtAddress(Address address);
@@ -167,6 +168,8 @@ class IC {
// invoke the garbage collector.
Address* pc_address_;
+ Isolate* isolate_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
};
@@ -189,7 +192,8 @@ class IC_Utility {
class CallICBase: public IC {
protected:
- explicit CallICBase(Code::Kind kind) : IC(EXTRA_CALL_FRAME), kind_(kind) {}
+ CallICBase(Code::Kind kind, Isolate* isolate)
+ : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {}
public:
MUST_USE_RESULT MaybeObject* LoadFunction(State state,
@@ -233,7 +237,9 @@ class CallICBase: public IC {
class CallIC: public CallICBase {
public:
- CallIC() : CallICBase(Code::CALL_IC) { ASSERT(target()->is_call_stub()); }
+ explicit CallIC(Isolate* isolate) : CallICBase(Code::CALL_IC, isolate) {
+ ASSERT(target()->is_call_stub());
+ }
// Code generator routines.
static void GenerateInitialize(MacroAssembler* masm, int argc) {
@@ -247,7 +253,8 @@ class CallIC: public CallICBase {
class KeyedCallIC: public CallICBase {
public:
- KeyedCallIC() : CallICBase(Code::KEYED_CALL_IC) {
+ explicit KeyedCallIC(Isolate* isolate)
+ : CallICBase(Code::KEYED_CALL_IC, isolate) {
ASSERT(target()->is_keyed_call_stub());
}
@@ -267,7 +274,9 @@ class KeyedCallIC: public CallICBase {
class LoadIC: public IC {
public:
- LoadIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_load_stub()); }
+ explicit LoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
+ ASSERT(target()->is_load_stub());
+ }
MUST_USE_RESULT MaybeObject* Load(State state,
Handle<Object> object,
@@ -305,14 +314,17 @@ class LoadIC: public IC {
Handle<String> name);
// Stub accessors.
- static Code* megamorphic_stub() {
- return Builtins::builtin(Builtins::LoadIC_Megamorphic);
+ Code* megamorphic_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kLoadIC_Megamorphic);
}
static Code* initialize_stub() {
- return Builtins::builtin(Builtins::LoadIC_Initialize);
+ return Isolate::Current()->builtins()->builtin(
+ Builtins::kLoadIC_Initialize);
}
- static Code* pre_monomorphic_stub() {
- return Builtins::builtin(Builtins::LoadIC_PreMonomorphic);
+ Code* pre_monomorphic_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kLoadIC_PreMonomorphic);
}
static void Clear(Address address, Code* target);
@@ -330,7 +342,9 @@ class LoadIC: public IC {
class KeyedLoadIC: public IC {
public:
- KeyedLoadIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_keyed_load_stub()); }
+ explicit KeyedLoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
+ ASSERT(target()->is_keyed_load_stub());
+ }
MUST_USE_RESULT MaybeObject* Load(State state,
Handle<Object> object,
@@ -367,23 +381,29 @@ class KeyedLoadIC: public IC {
// Stub accessors.
static Code* initialize_stub() {
- return Builtins::builtin(Builtins::KeyedLoadIC_Initialize);
+ return Isolate::Current()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_Initialize);
}
- static Code* megamorphic_stub() {
- return Builtins::builtin(Builtins::KeyedLoadIC_Generic);
+ Code* megamorphic_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_Generic);
}
- static Code* generic_stub() {
- return Builtins::builtin(Builtins::KeyedLoadIC_Generic);
+ Code* generic_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_Generic);
}
- static Code* pre_monomorphic_stub() {
- return Builtins::builtin(Builtins::KeyedLoadIC_PreMonomorphic);
+ Code* pre_monomorphic_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_PreMonomorphic);
}
- static Code* string_stub() {
- return Builtins::builtin(Builtins::KeyedLoadIC_String);
+ Code* string_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_String);
}
- static Code* indexed_interceptor_stub() {
- return Builtins::builtin(Builtins::KeyedLoadIC_IndexedInterceptor);
+ Code* indexed_interceptor_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_IndexedInterceptor);
}
static void Clear(Address address, Code* target);
@@ -398,7 +418,9 @@ class KeyedLoadIC: public IC {
class StoreIC: public IC {
public:
- StoreIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_store_stub()); }
+ explicit StoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
+ ASSERT(target()->is_store_stub());
+ }
MUST_USE_RESULT MaybeObject* Store(State state,
StrictModeFlag strict_mode,
@@ -441,23 +463,29 @@ class StoreIC: public IC {
}
// Stub accessors.
- static Code* megamorphic_stub() {
- return Builtins::builtin(Builtins::StoreIC_Megamorphic);
+ Code* megamorphic_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kStoreIC_Megamorphic);
}
- static Code* megamorphic_stub_strict() {
- return Builtins::builtin(Builtins::StoreIC_Megamorphic_Strict);
+ Code* megamorphic_stub_strict() {
+ return isolate()->builtins()->builtin(
+ Builtins::kStoreIC_Megamorphic_Strict);
}
static Code* initialize_stub() {
- return Builtins::builtin(Builtins::StoreIC_Initialize);
+ return Isolate::Current()->builtins()->builtin(
+ Builtins::kStoreIC_Initialize);
}
static Code* initialize_stub_strict() {
- return Builtins::builtin(Builtins::StoreIC_Initialize_Strict);
+ return Isolate::Current()->builtins()->builtin(
+ Builtins::kStoreIC_Initialize_Strict);
}
- static Code* global_proxy_stub() {
- return Builtins::builtin(Builtins::StoreIC_GlobalProxy);
+ Code* global_proxy_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kStoreIC_GlobalProxy);
}
- static Code* global_proxy_stub_strict() {
- return Builtins::builtin(Builtins::StoreIC_GlobalProxy_Strict);
+ Code* global_proxy_stub_strict() {
+ return isolate()->builtins()->builtin(
+ Builtins::kStoreIC_GlobalProxy_Strict);
}
static void Clear(Address address, Code* target);
@@ -472,7 +500,7 @@ class StoreIC: public IC {
class KeyedStoreIC: public IC {
public:
- KeyedStoreIC() : IC(NO_EXTRA_FRAME) { }
+ explicit KeyedStoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
MUST_USE_RESULT MaybeObject* Store(State state,
StrictModeFlag strict_mode,
@@ -511,22 +539,28 @@ class KeyedStoreIC: public IC {
// Stub accessors.
static Code* initialize_stub() {
- return Builtins::builtin(Builtins::KeyedStoreIC_Initialize);
+ return Isolate::Current()->builtins()->builtin(
+ Builtins::kKeyedStoreIC_Initialize);
}
- static Code* initialize_stub_strict() {
- return Builtins::builtin(Builtins::KeyedStoreIC_Initialize_Strict);
+ Code* megamorphic_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedStoreIC_Generic);
}
- static Code* megamorphic_stub() {
- return Builtins::builtin(Builtins::KeyedStoreIC_Generic);
+ static Code* initialize_stub_strict() {
+ return Isolate::Current()->builtins()->builtin(
+ Builtins::kKeyedStoreIC_Initialize_Strict);
}
- static Code* megamorphic_stub_strict() {
- return Builtins::builtin(Builtins::KeyedStoreIC_Generic_Strict);
+ Code* megamorphic_stub_strict() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedStoreIC_Generic_Strict);
}
- static Code* generic_stub() {
- return Builtins::builtin(Builtins::KeyedStoreIC_Generic);
+ Code* generic_stub() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedStoreIC_Generic);
}
- static Code* generic_stub_strict() {
- return Builtins::builtin(Builtins::KeyedStoreIC_Generic_Strict);
+ Code* generic_stub_strict() {
+ return isolate()->builtins()->builtin(
+ Builtins::kKeyedStoreIC_Generic_Strict);
}
static void Clear(Address address, Code* target);
@@ -555,7 +589,7 @@ class BinaryOpIC: public IC {
GENERIC // Non-specialized case (processes any type combination).
};
- BinaryOpIC() : IC(NO_EXTRA_FRAME) { }
+ explicit BinaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
void patch(Code* code);
@@ -576,11 +610,12 @@ class TRBinaryOpIC: public IC {
SMI,
INT32,
HEAP_NUMBER,
+ ODDBALL,
STRING, // Only used for addition operation. At least one string operand.
GENERIC
};
- TRBinaryOpIC() : IC(NO_EXTRA_FRAME) { }
+ explicit TRBinaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
void patch(Code* code);
@@ -604,7 +639,8 @@ class CompareIC: public IC {
GENERIC
};
- explicit CompareIC(Token::Value op) : IC(EXTRA_CALL_FRAME), op_(op) { }
+ CompareIC(Isolate* isolate, Token::Value op)
+ : IC(EXTRA_CALL_FRAME, isolate), op_(op) { }
// Update the inline cache for the given operands.
void UpdateCaches(Handle<Object> x, Handle<Object> y);
diff --git a/src/interpreter-irregexp.cc b/src/interpreter-irregexp.cc
index c9c3cc4c..1c6c52ca 100644
--- a/src/interpreter-irregexp.cc
+++ b/src/interpreter-irregexp.cc
@@ -40,10 +40,10 @@ namespace v8 {
namespace internal {
-static unibrow::Mapping<unibrow::Ecma262Canonicalize> interp_canonicalize;
+typedef unibrow::Mapping<unibrow::Ecma262Canonicalize> Canonicalize;
-
-static bool BackRefMatchesNoCase(int from,
+static bool BackRefMatchesNoCase(Canonicalize* interp_canonicalize,
+ int from,
int current,
int len,
Vector<const uc16> subject) {
@@ -53,8 +53,8 @@ static bool BackRefMatchesNoCase(int from,
if (old_char == new_char) continue;
unibrow::uchar old_string[1] = { old_char };
unibrow::uchar new_string[1] = { new_char };
- interp_canonicalize.get(old_char, '\0', old_string);
- interp_canonicalize.get(new_char, '\0', new_string);
+ interp_canonicalize->get(old_char, '\0', old_string);
+ interp_canonicalize->get(new_char, '\0', new_string);
if (old_string[0] != new_string[0]) {
return false;
}
@@ -63,7 +63,8 @@ static bool BackRefMatchesNoCase(int from,
}
-static bool BackRefMatchesNoCase(int from,
+static bool BackRefMatchesNoCase(Canonicalize* interp_canonicalize,
+ int from,
int current,
int len,
Vector<const char> subject) {
@@ -150,11 +151,11 @@ static int32_t Load16Aligned(const byte* pc) {
// matching terminates.
class BacktrackStack {
public:
- explicit BacktrackStack() {
- if (cache_ != NULL) {
+ explicit BacktrackStack(Isolate* isolate) : isolate_(isolate) {
+ if (isolate->irregexp_interpreter_backtrack_stack_cache() != NULL) {
// If the cache is not empty reuse the previously allocated stack.
- data_ = cache_;
- cache_ = NULL;
+ data_ = isolate->irregexp_interpreter_backtrack_stack_cache();
+ isolate->set_irregexp_interpreter_backtrack_stack_cache(NULL);
} else {
// Cache was empty. Allocate a new backtrack stack.
data_ = NewArray<int>(kBacktrackStackSize);
@@ -162,9 +163,9 @@ class BacktrackStack {
}
~BacktrackStack() {
- if (cache_ == NULL) {
+ if (isolate_->irregexp_interpreter_backtrack_stack_cache() == NULL) {
// The cache is empty. Keep this backtrack stack around.
- cache_ = data_;
+ isolate_->set_irregexp_interpreter_backtrack_stack_cache(data_);
} else {
// A backtrack stack was already cached, just release this one.
DeleteArray(data_);
@@ -179,16 +180,15 @@ class BacktrackStack {
static const int kBacktrackStackSize = 10000;
int* data_;
- static int* cache_;
+ Isolate* isolate_;
DISALLOW_COPY_AND_ASSIGN(BacktrackStack);
};
-int* BacktrackStack::cache_ = NULL;
-
template <typename Char>
-static bool RawMatch(const byte* code_base,
+static bool RawMatch(Isolate* isolate,
+ const byte* code_base,
Vector<const Char> subject,
int* registers,
int current,
@@ -197,7 +197,7 @@ static bool RawMatch(const byte* code_base,
// BacktrackStack ensures that the memory allocated for the backtracking stack
// is returned to the system or cached if there is no stack being cached at
// the moment.
- BacktrackStack backtrack_stack;
+ BacktrackStack backtrack_stack(isolate);
int* backtrack_stack_base = backtrack_stack.data();
int* backtrack_sp = backtrack_stack_base;
int backtrack_stack_space = backtrack_stack.max_size();
@@ -584,7 +584,8 @@ static bool RawMatch(const byte* code_base,
pc = code_base + Load32Aligned(pc + 4);
break;
} else {
- if (BackRefMatchesNoCase(from, current, len, subject)) {
+ if (BackRefMatchesNoCase(isolate->interp_canonicalize_mapping(),
+ from, current, len, subject)) {
current += len;
pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
} else {
@@ -624,7 +625,8 @@ static bool RawMatch(const byte* code_base,
}
-bool IrregexpInterpreter::Match(Handle<ByteArray> code_array,
+bool IrregexpInterpreter::Match(Isolate* isolate,
+ Handle<ByteArray> code_array,
Handle<String> subject,
int* registers,
int start_position) {
@@ -636,7 +638,8 @@ bool IrregexpInterpreter::Match(Handle<ByteArray> code_array,
if (subject->IsAsciiRepresentation()) {
Vector<const char> subject_vector = subject->ToAsciiVector();
if (start_position != 0) previous_char = subject_vector[start_position - 1];
- return RawMatch(code_base,
+ return RawMatch(isolate,
+ code_base,
subject_vector,
registers,
start_position,
@@ -644,7 +647,8 @@ bool IrregexpInterpreter::Match(Handle<ByteArray> code_array,
} else {
Vector<const uc16> subject_vector = subject->ToUC16Vector();
if (start_position != 0) previous_char = subject_vector[start_position - 1];
- return RawMatch(code_base,
+ return RawMatch(isolate,
+ code_base,
subject_vector,
registers,
start_position,
diff --git a/src/interpreter-irregexp.h b/src/interpreter-irregexp.h
index 0ad8846d..076f0c50 100644
--- a/src/interpreter-irregexp.h
+++ b/src/interpreter-irregexp.h
@@ -36,7 +36,8 @@ namespace internal {
class IrregexpInterpreter {
public:
- static bool Match(Handle<ByteArray> code,
+ static bool Match(Isolate* isolate,
+ Handle<ByteArray> code,
Handle<String> subject,
int* captures,
int start_position);
diff --git a/src/isolate.cc b/src/isolate.cc
new file mode 100644
index 00000000..a1635321
--- /dev/null
+++ b/src/isolate.cc
@@ -0,0 +1,895 @@
+// Copyright 2006-2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "ast.h"
+#include "bootstrapper.h"
+#include "codegen.h"
+#include "compilation-cache.h"
+#include "debug.h"
+#include "deoptimizer.h"
+#include "heap-profiler.h"
+#include "hydrogen.h"
+#include "isolate.h"
+#include "lithium-allocator.h"
+#include "log.h"
+#include "regexp-stack.h"
+#include "runtime-profiler.h"
+#include "scanner.h"
+#include "scopeinfo.h"
+#include "serialize.h"
+#include "simulator.h"
+#include "spaces.h"
+#include "stub-cache.h"
+#include "version.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+// Create a dummy thread that will wait forever on a semaphore. The only
+// purpose for this thread is to have some stack area to save essential data
+// into for use by a stacks only core dump (aka minidump).
+class PreallocatedMemoryThread: public Thread {
+ public:
+ char* data() {
+ if (data_ready_semaphore_ != NULL) {
+ // Initial access is guarded until the data has been published.
+ data_ready_semaphore_->Wait();
+ delete data_ready_semaphore_;
+ data_ready_semaphore_ = NULL;
+ }
+ return data_;
+ }
+
+ unsigned length() {
+ if (data_ready_semaphore_ != NULL) {
+ // Initial access is guarded until the data has been published.
+ data_ready_semaphore_->Wait();
+ delete data_ready_semaphore_;
+ data_ready_semaphore_ = NULL;
+ }
+ return length_;
+ }
+
+ // Stop the PreallocatedMemoryThread and release its resources.
+ void StopThread() {
+ keep_running_ = false;
+ wait_for_ever_semaphore_->Signal();
+
+ // Wait for the thread to terminate.
+ Join();
+
+ if (data_ready_semaphore_ != NULL) {
+ delete data_ready_semaphore_;
+ data_ready_semaphore_ = NULL;
+ }
+
+ delete wait_for_ever_semaphore_;
+ wait_for_ever_semaphore_ = NULL;
+ }
+
+ protected:
+ // When the thread starts running it will allocate a fixed number of bytes
+ // on the stack and publish the location of this memory for others to use.
+ void Run() {
+ EmbeddedVector<char, 15 * 1024> local_buffer;
+
+ // Initialize the buffer with a known good value.
+ OS::StrNCpy(local_buffer, "Trace data was not generated.\n",
+ local_buffer.length());
+
+ // Publish the local buffer and signal its availability.
+ data_ = local_buffer.start();
+ length_ = local_buffer.length();
+ data_ready_semaphore_->Signal();
+
+ while (keep_running_) {
+ // This thread will wait here until the end of time.
+ wait_for_ever_semaphore_->Wait();
+ }
+
+ // Make sure we access the buffer after the wait to remove all possibility
+ // of it being optimized away.
+ OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n",
+ local_buffer.length());
+ }
+
+
+ private:
+ explicit PreallocatedMemoryThread(Isolate* isolate)
+ : Thread(isolate, "v8:PreallocMem"),
+ keep_running_(true),
+ wait_for_ever_semaphore_(OS::CreateSemaphore(0)),
+ data_ready_semaphore_(OS::CreateSemaphore(0)),
+ data_(NULL),
+ length_(0) {
+ }
+
+ // Used to make sure that the thread keeps looping even for spurious wakeups.
+ bool keep_running_;
+
+ // This semaphore is used by the PreallocatedMemoryThread to wait for ever.
+ Semaphore* wait_for_ever_semaphore_;
+ // Semaphore to signal that the data has been initialized.
+ Semaphore* data_ready_semaphore_;
+
+ // Location and size of the preallocated memory block.
+ char* data_;
+ unsigned length_;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread);
+};
+
+
+void Isolate::PreallocatedMemoryThreadStart() {
+ if (preallocated_memory_thread_ != NULL) return;
+ preallocated_memory_thread_ = new PreallocatedMemoryThread(this);
+ preallocated_memory_thread_->Start();
+}
+
+
+void Isolate::PreallocatedMemoryThreadStop() {
+ if (preallocated_memory_thread_ == NULL) return;
+ preallocated_memory_thread_->StopThread();
+ // Done with the thread entirely.
+ delete preallocated_memory_thread_;
+ preallocated_memory_thread_ = NULL;
+}
+
+
+void Isolate::PreallocatedStorageInit(size_t size) {
+ ASSERT(free_list_.next_ == &free_list_);
+ ASSERT(free_list_.previous_ == &free_list_);
+ PreallocatedStorage* free_chunk =
+ reinterpret_cast<PreallocatedStorage*>(new char[size]);
+ free_list_.next_ = free_list_.previous_ = free_chunk;
+ free_chunk->next_ = free_chunk->previous_ = &free_list_;
+ free_chunk->size_ = size - sizeof(PreallocatedStorage);
+ preallocated_storage_preallocated_ = true;
+}
+
+
+void* Isolate::PreallocatedStorageNew(size_t size) {
+ if (!preallocated_storage_preallocated_) {
+ return FreeStoreAllocationPolicy::New(size);
+ }
+ ASSERT(free_list_.next_ != &free_list_);
+ ASSERT(free_list_.previous_ != &free_list_);
+
+ size = (size + kPointerSize - 1) & ~(kPointerSize - 1);
+ // Search for exact fit.
+ for (PreallocatedStorage* storage = free_list_.next_;
+ storage != &free_list_;
+ storage = storage->next_) {
+ if (storage->size_ == size) {
+ storage->Unlink();
+ storage->LinkTo(&in_use_list_);
+ return reinterpret_cast<void*>(storage + 1);
+ }
+ }
+ // Search for first fit.
+ for (PreallocatedStorage* storage = free_list_.next_;
+ storage != &free_list_;
+ storage = storage->next_) {
+ if (storage->size_ >= size + sizeof(PreallocatedStorage)) {
+ storage->Unlink();
+ storage->LinkTo(&in_use_list_);
+ PreallocatedStorage* left_over =
+ reinterpret_cast<PreallocatedStorage*>(
+ reinterpret_cast<char*>(storage + 1) + size);
+ left_over->size_ = storage->size_ - size - sizeof(PreallocatedStorage);
+ ASSERT(size + left_over->size_ + sizeof(PreallocatedStorage) ==
+ storage->size_);
+ storage->size_ = size;
+ left_over->LinkTo(&free_list_);
+ return reinterpret_cast<void*>(storage + 1);
+ }
+ }
+ // Allocation failure.
+ ASSERT(false);
+ return NULL;
+}
+
+
+// We don't attempt to coalesce.
+void Isolate::PreallocatedStorageDelete(void* p) {
+ if (p == NULL) {
+ return;
+ }
+ if (!preallocated_storage_preallocated_) {
+ FreeStoreAllocationPolicy::Delete(p);
+ return;
+ }
+ PreallocatedStorage* storage = reinterpret_cast<PreallocatedStorage*>(p) - 1;
+ ASSERT(storage->next_->previous_ == storage);
+ ASSERT(storage->previous_->next_ == storage);
+ storage->Unlink();
+ storage->LinkTo(&free_list_);
+}
+
+
+Isolate* Isolate::default_isolate_ = NULL;
+Thread::LocalStorageKey Isolate::isolate_key_;
+Thread::LocalStorageKey Isolate::thread_id_key_;
+Thread::LocalStorageKey Isolate::per_isolate_thread_data_key_;
+Mutex* Isolate::process_wide_mutex_ = OS::CreateMutex();
+Isolate::ThreadDataTable* Isolate::thread_data_table_ = NULL;
+Isolate::ThreadId Isolate::highest_thread_id_ = 0;
+
+
+class IsolateInitializer {
+ public:
+ IsolateInitializer() {
+ Isolate::EnsureDefaultIsolate();
+ }
+};
+
+static IsolateInitializer* EnsureDefaultIsolateAllocated() {
+ // TODO(isolates): Use the system threading API to do this once?
+ static IsolateInitializer static_initializer;
+ return &static_initializer;
+}
+
+// This variable only needed to trigger static intialization.
+static IsolateInitializer* static_initializer = EnsureDefaultIsolateAllocated();
+
+
+Isolate::ThreadId Isolate::AllocateThreadId() {
+ ThreadId new_id;
+ {
+ ScopedLock lock(process_wide_mutex_);
+ new_id = ++highest_thread_id_;
+ }
+ return new_id;
+}
+
+
+Isolate::PerIsolateThreadData* Isolate::AllocatePerIsolateThreadData(
+ ThreadId thread_id) {
+ ASSERT(thread_id != 0);
+ ASSERT(Thread::GetThreadLocalInt(thread_id_key_) == thread_id);
+ PerIsolateThreadData* per_thread = new PerIsolateThreadData(this, thread_id);
+ {
+ ScopedLock lock(process_wide_mutex_);
+ ASSERT(thread_data_table_->Lookup(this, thread_id) == NULL);
+ thread_data_table_->Insert(per_thread);
+ ASSERT(thread_data_table_->Lookup(this, thread_id) == per_thread);
+ }
+ return per_thread;
+}
+
+
+Isolate::PerIsolateThreadData*
+ Isolate::FindOrAllocatePerThreadDataForThisThread() {
+ ThreadId thread_id = Thread::GetThreadLocalInt(thread_id_key_);
+ if (thread_id == 0) {
+ thread_id = AllocateThreadId();
+ Thread::SetThreadLocalInt(thread_id_key_, thread_id);
+ }
+ PerIsolateThreadData* per_thread = NULL;
+ {
+ ScopedLock lock(process_wide_mutex_);
+ per_thread = thread_data_table_->Lookup(this, thread_id);
+ if (per_thread == NULL) {
+ per_thread = AllocatePerIsolateThreadData(thread_id);
+ }
+ }
+ return per_thread;
+}
+
+
+void Isolate::EnsureDefaultIsolate() {
+ ScopedLock lock(process_wide_mutex_);
+ if (default_isolate_ == NULL) {
+ isolate_key_ = Thread::CreateThreadLocalKey();
+ thread_id_key_ = Thread::CreateThreadLocalKey();
+ per_isolate_thread_data_key_ = Thread::CreateThreadLocalKey();
+ thread_data_table_ = new Isolate::ThreadDataTable();
+ default_isolate_ = new Isolate();
+ }
+ // Can't use SetIsolateThreadLocals(default_isolate_, NULL) here
+ // becase a non-null thread data may be already set.
+ Thread::SetThreadLocal(isolate_key_, default_isolate_);
+ CHECK(default_isolate_->PreInit());
+}
+
+
+Debugger* Isolate::GetDefaultIsolateDebugger() {
+ EnsureDefaultIsolate();
+ return default_isolate_->debugger();
+}
+
+
+StackGuard* Isolate::GetDefaultIsolateStackGuard() {
+ EnsureDefaultIsolate();
+ return default_isolate_->stack_guard();
+}
+
+
+void Isolate::EnterDefaultIsolate() {
+ EnsureDefaultIsolate();
+ ASSERT(default_isolate_ != NULL);
+
+ PerIsolateThreadData* data = CurrentPerIsolateThreadData();
+ // If not yet in default isolate - enter it.
+ if (data == NULL || data->isolate() != default_isolate_) {
+ default_isolate_->Enter();
+ }
+}
+
+
+Isolate* Isolate::GetDefaultIsolateForLocking() {
+ EnsureDefaultIsolate();
+ return default_isolate_;
+}
+
+
+Isolate::ThreadDataTable::ThreadDataTable()
+ : list_(NULL) {
+}
+
+
+Isolate::PerIsolateThreadData*
+ Isolate::ThreadDataTable::Lookup(Isolate* isolate, ThreadId thread_id) {
+ for (PerIsolateThreadData* data = list_; data != NULL; data = data->next_) {
+ if (data->Matches(isolate, thread_id)) return data;
+ }
+ return NULL;
+}
+
+
+void Isolate::ThreadDataTable::Insert(Isolate::PerIsolateThreadData* data) {
+ if (list_ != NULL) list_->prev_ = data;
+ data->next_ = list_;
+ list_ = data;
+}
+
+
+void Isolate::ThreadDataTable::Remove(PerIsolateThreadData* data) {
+ if (list_ == data) list_ = data->next_;
+ if (data->next_ != NULL) data->next_->prev_ = data->prev_;
+ if (data->prev_ != NULL) data->prev_->next_ = data->next_;
+}
+
+
+void Isolate::ThreadDataTable::Remove(Isolate* isolate, ThreadId thread_id) {
+ PerIsolateThreadData* data = Lookup(isolate, thread_id);
+ if (data != NULL) {
+ Remove(data);
+ }
+}
+
+
+#ifdef DEBUG
+#define TRACE_ISOLATE(tag) \
+ do { \
+ if (FLAG_trace_isolates) { \
+ PrintF("Isolate %p " #tag "\n", reinterpret_cast<void*>(this)); \
+ } \
+ } while (false)
+#else
+#define TRACE_ISOLATE(tag)
+#endif
+
+
+Isolate::Isolate()
+ : state_(UNINITIALIZED),
+ entry_stack_(NULL),
+ stack_trace_nesting_level_(0),
+ incomplete_message_(NULL),
+ preallocated_memory_thread_(NULL),
+ preallocated_message_space_(NULL),
+ bootstrapper_(NULL),
+ runtime_profiler_(NULL),
+ compilation_cache_(NULL),
+ counters_(new Counters()),
+ cpu_features_(NULL),
+ code_range_(NULL),
+ break_access_(OS::CreateMutex()),
+ logger_(new Logger()),
+ stats_table_(new StatsTable()),
+ stub_cache_(NULL),
+ deoptimizer_data_(NULL),
+ capture_stack_trace_for_uncaught_exceptions_(false),
+ stack_trace_for_uncaught_exceptions_frame_limit_(0),
+ stack_trace_for_uncaught_exceptions_options_(StackTrace::kOverview),
+ transcendental_cache_(NULL),
+ memory_allocator_(NULL),
+ keyed_lookup_cache_(NULL),
+ context_slot_cache_(NULL),
+ descriptor_lookup_cache_(NULL),
+ handle_scope_implementer_(NULL),
+ scanner_constants_(NULL),
+ in_use_list_(0),
+ free_list_(0),
+ preallocated_storage_preallocated_(false),
+ pc_to_code_cache_(NULL),
+ write_input_buffer_(NULL),
+ global_handles_(NULL),
+ context_switcher_(NULL),
+ thread_manager_(NULL),
+ ast_sentinels_(NULL),
+ string_tracker_(NULL),
+ regexp_stack_(NULL),
+ frame_element_constant_list_(0),
+ result_constant_list_(0) {
+ TRACE_ISOLATE(constructor);
+
+ memset(isolate_addresses_, 0,
+ sizeof(isolate_addresses_[0]) * (k_isolate_address_count + 1));
+
+ heap_.isolate_ = this;
+ zone_.isolate_ = this;
+ stack_guard_.isolate_ = this;
+
+#if defined(V8_TARGET_ARCH_ARM) && !defined(__arm__) || \
+ defined(V8_TARGET_ARCH_MIPS) && !defined(__mips__)
+ simulator_initialized_ = false;
+ simulator_i_cache_ = NULL;
+ simulator_redirection_ = NULL;
+#endif
+
+#ifdef DEBUG
+ // heap_histograms_ initializes itself.
+ memset(&js_spill_information_, 0, sizeof(js_spill_information_));
+ memset(code_kind_statistics_, 0,
+ sizeof(code_kind_statistics_[0]) * Code::NUMBER_OF_KINDS);
+#endif
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ debug_ = NULL;
+ debugger_ = NULL;
+#endif
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ producer_heap_profile_ = NULL;
+#endif
+
+ handle_scope_data_.Initialize();
+
+#define ISOLATE_INIT_EXECUTE(type, name, initial_value) \
+ name##_ = (initial_value);
+ ISOLATE_INIT_LIST(ISOLATE_INIT_EXECUTE)
+#undef ISOLATE_INIT_EXECUTE
+
+#define ISOLATE_INIT_ARRAY_EXECUTE(type, name, length) \
+ memset(name##_, 0, sizeof(type) * length);
+ ISOLATE_INIT_ARRAY_LIST(ISOLATE_INIT_ARRAY_EXECUTE)
+#undef ISOLATE_INIT_ARRAY_EXECUTE
+}
+
+void Isolate::TearDown() {
+ TRACE_ISOLATE(tear_down);
+
+ // Temporarily set this isolate as current so that various parts of
+ // the isolate can access it in their destructors without having a
+ // direct pointer. We don't use Enter/Exit here to avoid
+ // initializing the thread data.
+ PerIsolateThreadData* saved_data = CurrentPerIsolateThreadData();
+ Isolate* saved_isolate = UncheckedCurrent();
+ SetIsolateThreadLocals(this, NULL);
+
+ Deinit();
+
+ if (!IsDefaultIsolate()) {
+ delete this;
+ }
+
+ // Restore the previous current isolate.
+ SetIsolateThreadLocals(saved_isolate, saved_data);
+}
+
+
+void Isolate::Deinit() {
+ if (state_ == INITIALIZED) {
+ TRACE_ISOLATE(deinit);
+
+ if (FLAG_hydrogen_stats) HStatistics::Instance()->Print();
+
+ // We must stop the logger before we tear down other components.
+ logger_->EnsureTickerStopped();
+
+ delete deoptimizer_data_;
+ deoptimizer_data_ = NULL;
+ if (FLAG_preemption) {
+ v8::Locker locker;
+ v8::Locker::StopPreemption();
+ }
+ builtins_.TearDown();
+ bootstrapper_->TearDown();
+
+ // Remove the external reference to the preallocated stack memory.
+ delete preallocated_message_space_;
+ preallocated_message_space_ = NULL;
+ PreallocatedMemoryThreadStop();
+
+ HeapProfiler::TearDown();
+ CpuProfiler::TearDown();
+ if (runtime_profiler_ != NULL) {
+ runtime_profiler_->TearDown();
+ delete runtime_profiler_;
+ runtime_profiler_ = NULL;
+ }
+ heap_.TearDown();
+ logger_->TearDown();
+
+ // The default isolate is re-initializable due to legacy API.
+ state_ = PREINITIALIZED;
+ }
+}
+
+
+void Isolate::SetIsolateThreadLocals(Isolate* isolate,
+ PerIsolateThreadData* data) {
+ Thread::SetThreadLocal(isolate_key_, isolate);
+ Thread::SetThreadLocal(per_isolate_thread_data_key_, data);
+}
+
+
+Isolate::~Isolate() {
+ TRACE_ISOLATE(destructor);
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ delete producer_heap_profile_;
+ producer_heap_profile_ = NULL;
+#endif
+
+ delete scanner_constants_;
+ scanner_constants_ = NULL;
+
+ delete regexp_stack_;
+ regexp_stack_ = NULL;
+
+ delete ast_sentinels_;
+ ast_sentinels_ = NULL;
+
+ delete descriptor_lookup_cache_;
+ descriptor_lookup_cache_ = NULL;
+ delete context_slot_cache_;
+ context_slot_cache_ = NULL;
+ delete keyed_lookup_cache_;
+ keyed_lookup_cache_ = NULL;
+
+ delete transcendental_cache_;
+ transcendental_cache_ = NULL;
+ delete stub_cache_;
+ stub_cache_ = NULL;
+ delete stats_table_;
+ stats_table_ = NULL;
+
+ delete logger_;
+ logger_ = NULL;
+
+ delete counters_;
+ counters_ = NULL;
+ delete cpu_features_;
+ cpu_features_ = NULL;
+
+ delete handle_scope_implementer_;
+ handle_scope_implementer_ = NULL;
+ delete break_access_;
+ break_access_ = NULL;
+
+ delete compilation_cache_;
+ compilation_cache_ = NULL;
+ delete bootstrapper_;
+ bootstrapper_ = NULL;
+ delete pc_to_code_cache_;
+ pc_to_code_cache_ = NULL;
+ delete write_input_buffer_;
+ write_input_buffer_ = NULL;
+
+ delete context_switcher_;
+ context_switcher_ = NULL;
+ delete thread_manager_;
+ thread_manager_ = NULL;
+
+ delete string_tracker_;
+ string_tracker_ = NULL;
+
+ delete memory_allocator_;
+ memory_allocator_ = NULL;
+ delete code_range_;
+ code_range_ = NULL;
+ delete global_handles_;
+ global_handles_ = NULL;
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ delete debugger_;
+ debugger_ = NULL;
+ delete debug_;
+ debug_ = NULL;
+#endif
+}
+
+
+bool Isolate::PreInit() {
+ if (state_ != UNINITIALIZED) return true;
+
+ TRACE_ISOLATE(preinit);
+
+ ASSERT(Isolate::Current() == this);
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ debug_ = new Debug(this);
+ debugger_ = new Debugger();
+ debugger_->isolate_ = this;
+#endif
+
+ memory_allocator_ = new MemoryAllocator();
+ memory_allocator_->isolate_ = this;
+ code_range_ = new CodeRange();
+ code_range_->isolate_ = this;
+
+ // Safe after setting Heap::isolate_, initializing StackGuard and
+ // ensuring that Isolate::Current() == this.
+ heap_.SetStackLimits();
+
+#ifdef DEBUG
+ DisallowAllocationFailure disallow_allocation_failure;
+#endif
+
+#define C(name) isolate_addresses_[Isolate::k_##name] = \
+ reinterpret_cast<Address>(name());
+ ISOLATE_ADDRESS_LIST(C)
+ ISOLATE_ADDRESS_LIST_PROF(C)
+#undef C
+
+ string_tracker_ = new StringTracker();
+ string_tracker_->isolate_ = this;
+ thread_manager_ = new ThreadManager();
+ thread_manager_->isolate_ = this;
+ compilation_cache_ = new CompilationCache(this);
+ transcendental_cache_ = new TranscendentalCache();
+ keyed_lookup_cache_ = new KeyedLookupCache();
+ context_slot_cache_ = new ContextSlotCache();
+ descriptor_lookup_cache_ = new DescriptorLookupCache();
+ scanner_constants_ = new ScannerConstants();
+ pc_to_code_cache_ = new PcToCodeCache(this);
+ write_input_buffer_ = new StringInputBuffer();
+ global_handles_ = new GlobalHandles(this);
+ bootstrapper_ = new Bootstrapper();
+ cpu_features_ = new CpuFeatures();
+ handle_scope_implementer_ = new HandleScopeImplementer();
+ stub_cache_ = new StubCache(this);
+ ast_sentinels_ = new AstSentinels();
+ regexp_stack_ = new RegExpStack();
+ regexp_stack_->isolate_ = this;
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ producer_heap_profile_ = new ProducerHeapProfile();
+ producer_heap_profile_->isolate_ = this;
+#endif
+
+ state_ = PREINITIALIZED;
+ return true;
+}
+
+
+void Isolate::InitializeThreadLocal() {
+ thread_local_top_.Initialize();
+ clear_pending_exception();
+ clear_pending_message();
+ clear_scheduled_exception();
+}
+
+
+bool Isolate::Init(Deserializer* des) {
+ ASSERT(state_ != INITIALIZED);
+
+ TRACE_ISOLATE(init);
+
+ bool create_heap_objects = des == NULL;
+
+#ifdef DEBUG
+ // The initialization process does not handle memory exhaustion.
+ DisallowAllocationFailure disallow_allocation_failure;
+#endif
+
+ if (state_ == UNINITIALIZED && !PreInit()) return false;
+
+ // Enable logging before setting up the heap
+ logger_->Setup();
+
+ CpuProfiler::Setup();
+ HeapProfiler::Setup();
+
+ // Setup the platform OS support.
+ OS::Setup();
+
+ // Initialize other runtime facilities
+#if defined(USE_SIMULATOR)
+#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS)
+ Simulator::Initialize();
+#endif
+#endif
+
+ { // NOLINT
+ // Ensure that the thread has a valid stack guard. The v8::Locker object
+ // will ensure this too, but we don't have to use lockers if we are only
+ // using one thread.
+ ExecutionAccess lock(this);
+ stack_guard_.InitThread(lock);
+ }
+
+ // Setup the object heap
+ ASSERT(!heap_.HasBeenSetup());
+ if (!heap_.Setup(create_heap_objects)) {
+ V8::SetFatalError();
+ return false;
+ }
+
+ bootstrapper_->Initialize(create_heap_objects);
+ builtins_.Setup(create_heap_objects);
+
+ InitializeThreadLocal();
+
+ // Only preallocate on the first initialization.
+ if (FLAG_preallocate_message_memory && preallocated_message_space_ == NULL) {
+ // Start the thread which will set aside some memory.
+ PreallocatedMemoryThreadStart();
+ preallocated_message_space_ =
+ new NoAllocationStringAllocator(
+ preallocated_memory_thread_->data(),
+ preallocated_memory_thread_->length());
+ PreallocatedStorageInit(preallocated_memory_thread_->length() / 4);
+ }
+
+ if (FLAG_preemption) {
+ v8::Locker locker;
+ v8::Locker::StartPreemption(100);
+ }
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ debug_->Setup(create_heap_objects);
+#endif
+ stub_cache_->Initialize(create_heap_objects);
+
+ // If we are deserializing, read the state into the now-empty heap.
+ if (des != NULL) {
+ des->Deserialize();
+ stub_cache_->Clear();
+ }
+
+ // Deserializing may put strange things in the root array's copy of the
+ // stack guard.
+ heap_.SetStackLimits();
+
+ // Setup the CPU support. Must be done after heap setup and after
+ // any deserialization because we have to have the initial heap
+ // objects in place for creating the code object used for probing.
+ CPU::Setup();
+
+ deoptimizer_data_ = new DeoptimizerData;
+ runtime_profiler_ = new RuntimeProfiler(this);
+ runtime_profiler_->Setup();
+
+ // If we are deserializing, log non-function code objects and compiled
+ // functions found in the snapshot.
+ if (des != NULL && FLAG_log_code) {
+ HandleScope scope;
+ LOG(this, LogCodeObjects());
+ LOG(this, LogCompiledFunctions());
+ }
+
+ state_ = INITIALIZED;
+ return true;
+}
+
+
+void Isolate::Enter() {
+ Isolate* current_isolate = NULL;
+ PerIsolateThreadData* current_data = CurrentPerIsolateThreadData();
+ if (current_data != NULL) {
+ current_isolate = current_data->isolate_;
+ ASSERT(current_isolate != NULL);
+ if (current_isolate == this) {
+ ASSERT(Current() == this);
+ ASSERT(entry_stack_ != NULL);
+ ASSERT(entry_stack_->previous_thread_data == NULL ||
+ entry_stack_->previous_thread_data->thread_id() ==
+ Thread::GetThreadLocalInt(thread_id_key_));
+ // Same thread re-enters the isolate, no need to re-init anything.
+ entry_stack_->entry_count++;
+ return;
+ }
+ }
+
+ // Threads can have default isolate set into TLS as Current but not yet have
+ // PerIsolateThreadData for it, as it requires more advanced phase of the
+ // initialization. For example, a thread might be the one that system used for
+ // static initializers - in this case the default isolate is set in TLS but
+ // the thread did not yet Enter the isolate. If PerisolateThreadData is not
+ // there, use the isolate set in TLS.
+ if (current_isolate == NULL) {
+ current_isolate = Isolate::UncheckedCurrent();
+ }
+
+ PerIsolateThreadData* data = FindOrAllocatePerThreadDataForThisThread();
+ ASSERT(data != NULL);
+ ASSERT(data->isolate_ == this);
+
+ EntryStackItem* item = new EntryStackItem(current_data,
+ current_isolate,
+ entry_stack_);
+ entry_stack_ = item;
+
+ SetIsolateThreadLocals(this, data);
+
+ CHECK(PreInit());
+
+ // In case it's the first time some thread enters the isolate.
+ set_thread_id(data->thread_id());
+}
+
+
+void Isolate::Exit() {
+ ASSERT(entry_stack_ != NULL);
+ ASSERT(entry_stack_->previous_thread_data == NULL ||
+ entry_stack_->previous_thread_data->thread_id() ==
+ Thread::GetThreadLocalInt(thread_id_key_));
+
+ if (--entry_stack_->entry_count > 0) return;
+
+ ASSERT(CurrentPerIsolateThreadData() != NULL);
+ ASSERT(CurrentPerIsolateThreadData()->isolate_ == this);
+
+ // Pop the stack.
+ EntryStackItem* item = entry_stack_;
+ entry_stack_ = item->previous_item;
+
+ PerIsolateThreadData* previous_thread_data = item->previous_thread_data;
+ Isolate* previous_isolate = item->previous_isolate;
+
+ delete item;
+
+ // Reinit the current thread for the isolate it was running before this one.
+ SetIsolateThreadLocals(previous_isolate, previous_thread_data);
+}
+
+
+void Isolate::ResetEagerOptimizingData() {
+ compilation_cache_->ResetEagerOptimizingData();
+}
+
+
+#ifdef DEBUG
+#define ISOLATE_FIELD_OFFSET(type, name, ignored) \
+const intptr_t Isolate::name##_debug_offset_ = OFFSET_OF(Isolate, name##_);
+ISOLATE_INIT_LIST(ISOLATE_FIELD_OFFSET)
+ISOLATE_INIT_ARRAY_LIST(ISOLATE_FIELD_OFFSET)
+#undef ISOLATE_FIELD_OFFSET
+#endif
+
+} } // namespace v8::internal
diff --git a/src/isolate.h b/src/isolate.h
new file mode 100644
index 00000000..03a4866f
--- /dev/null
+++ b/src/isolate.h
@@ -0,0 +1,1308 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_ISOLATE_H_
+#define V8_ISOLATE_H_
+
+#include "../include/v8-debug.h"
+#include "allocation.h"
+#include "apiutils.h"
+#include "atomicops.h"
+#include "builtins.h"
+#include "contexts.h"
+#include "execution.h"
+#include "frames.h"
+#include "global-handles.h"
+#include "handles.h"
+#include "heap.h"
+#include "regexp-stack.h"
+#include "runtime-profiler.h"
+#include "runtime.h"
+#include "zone.h"
+
+namespace v8 {
+namespace internal {
+
+class AstSentinels;
+class Bootstrapper;
+class CodeGenerator;
+class CodeRange;
+class CompilationCache;
+class ContextSlotCache;
+class ContextSwitcher;
+class Counters;
+class CpuFeatures;
+class CpuProfiler;
+class DeoptimizerData;
+class Deserializer;
+class EmptyStatement;
+class ExternalReferenceTable;
+class Factory;
+class FunctionInfoListener;
+class HandleScopeImplementer;
+class HeapProfiler;
+class InlineRuntimeFunctionsTable;
+class NoAllocationStringAllocator;
+class PcToCodeCache;
+class PreallocatedMemoryThread;
+class ProducerHeapProfile;
+class RegExpStack;
+class SaveContext;
+class ScannerConstants;
+class StringInputBuffer;
+class StringTracker;
+class StubCache;
+class ThreadManager;
+class ThreadState;
+class ThreadVisitor; // Defined in v8threads.h
+class VMState;
+
+// 'void function pointer', used to roundtrip the
+// ExternalReference::ExternalReferenceRedirector since we can not include
+// assembler.h, where it is defined, here.
+typedef void* ExternalReferenceRedirectorPointer();
+
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+class Debug;
+class Debugger;
+class DebuggerAgent;
+#endif
+
+#if !defined(__arm__) && defined(V8_TARGET_ARCH_ARM) || \
+ !defined(__mips__) && defined(V8_TARGET_ARCH_MIPS)
+class Redirection;
+class Simulator;
+#endif
+
+
+// Static indirection table for handles to constants. If a frame
+// element represents a constant, the data contains an index into
+// this table of handles to the actual constants.
+// Static indirection table for handles to constants. If a Result
+// represents a constant, the data contains an index into this table
+// of handles to the actual constants.
+typedef ZoneList<Handle<Object> > ZoneObjectList;
+
+#define RETURN_IF_SCHEDULED_EXCEPTION(isolate) \
+ if (isolate->has_scheduled_exception()) \
+ return isolate->PromoteScheduledException()
+
+#define RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, value) \
+ if (call.is_null()) { \
+ ASSERT(isolate->has_pending_exception()); \
+ return value; \
+ }
+
+#define RETURN_IF_EMPTY_HANDLE(isolate, call) \
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, Failure::Exception())
+
+#define ISOLATE_ADDRESS_LIST(C) \
+ C(handler_address) \
+ C(c_entry_fp_address) \
+ C(context_address) \
+ C(pending_exception_address) \
+ C(external_caught_exception_address)
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+#define ISOLATE_ADDRESS_LIST_PROF(C) \
+ C(js_entry_sp_address)
+#else
+#define ISOLATE_ADDRESS_LIST_PROF(C)
+#endif
+
+
+class ThreadLocalTop BASE_EMBEDDED {
+ public:
+ // Initialize the thread data.
+ void Initialize();
+
+ // Get the top C++ try catch handler or NULL if none are registered.
+ //
+ // This method is not guarenteed to return an address that can be
+ // used for comparison with addresses into the JS stack. If such an
+ // address is needed, use try_catch_handler_address.
+ v8::TryCatch* TryCatchHandler();
+
+ // Get the address of the top C++ try catch handler or NULL if
+ // none are registered.
+ //
+ // This method always returns an address that can be compared to
+ // pointers into the JavaScript stack. When running on actual
+ // hardware, try_catch_handler_address and TryCatchHandler return
+ // the same pointer. When running on a simulator with a separate JS
+ // stack, try_catch_handler_address returns a JS stack address that
+ // corresponds to the place on the JS stack where the C++ handler
+ // would have been if the stack were not separate.
+ inline Address try_catch_handler_address() {
+ return try_catch_handler_address_;
+ }
+
+ // Set the address of the top C++ try catch handler.
+ inline void set_try_catch_handler_address(Address address) {
+ try_catch_handler_address_ = address;
+ }
+
+ void Free() {
+ ASSERT(!has_pending_message_);
+ ASSERT(!external_caught_exception_);
+ ASSERT(try_catch_handler_address_ == NULL);
+ }
+
+ // The context where the current execution method is created and for variable
+ // lookups.
+ Context* context_;
+ int thread_id_;
+ MaybeObject* pending_exception_;
+ bool has_pending_message_;
+ const char* pending_message_;
+ Object* pending_message_obj_;
+ Script* pending_message_script_;
+ int pending_message_start_pos_;
+ int pending_message_end_pos_;
+ // Use a separate value for scheduled exceptions to preserve the
+ // invariants that hold about pending_exception. We may want to
+ // unify them later.
+ MaybeObject* scheduled_exception_;
+ bool external_caught_exception_;
+ SaveContext* save_context_;
+ v8::TryCatch* catcher_;
+
+ // Stack.
+ Address c_entry_fp_; // the frame pointer of the top c entry frame
+ Address handler_; // try-blocks are chained through the stack
+
+#ifdef USE_SIMULATOR
+#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS)
+ Simulator* simulator_;
+#endif
+#endif // USE_SIMULATOR
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ Address js_entry_sp_; // the stack pointer of the bottom js entry frame
+ Address external_callback_; // the external callback we're currently in
+#endif
+
+#ifdef ENABLE_VMSTATE_TRACKING
+ StateTag current_vm_state_;
+#endif
+
+ // Generated code scratch locations.
+ int32_t formal_count_;
+
+ // Call back function to report unsafe JS accesses.
+ v8::FailedAccessCheckCallback failed_access_check_callback_;
+
+ private:
+ Address try_catch_handler_address_;
+};
+
+#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS)
+
+#define ISOLATE_PLATFORM_INIT_LIST(V) \
+ /* VirtualFrame::SpilledScope state */ \
+ V(bool, is_virtual_frame_in_spilled_scope, false) \
+ /* CodeGenerator::EmitNamedStore state */ \
+ V(int, inlined_write_barrier_size, -1)
+
+#if !defined(__arm__) && !defined(__mips__)
+class HashMap;
+#endif
+
+#else
+
+#define ISOLATE_PLATFORM_INIT_LIST(V)
+
+#endif
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+
+#define ISOLATE_DEBUGGER_INIT_LIST(V) \
+ V(v8::Debug::EventCallback, debug_event_callback, NULL) \
+ V(DebuggerAgent*, debugger_agent_instance, NULL)
+#else
+
+#define ISOLATE_DEBUGGER_INIT_LIST(V)
+
+#endif
+
+#ifdef DEBUG
+
+#define ISOLATE_INIT_DEBUG_ARRAY_LIST(V) \
+ V(CommentStatistic, paged_space_comments_statistics, \
+ CommentStatistic::kMaxComments + 1)
+#else
+
+#define ISOLATE_INIT_DEBUG_ARRAY_LIST(V)
+
+#endif
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+#define ISOLATE_LOGGING_INIT_LIST(V) \
+ V(CpuProfiler*, cpu_profiler, NULL) \
+ V(HeapProfiler*, heap_profiler, NULL)
+
+#else
+
+#define ISOLATE_LOGGING_INIT_LIST(V)
+
+#endif
+
+#define ISOLATE_INIT_ARRAY_LIST(V) \
+ /* SerializerDeserializer state. */ \
+ V(Object*, serialize_partial_snapshot_cache, kPartialSnapshotCacheCapacity) \
+ V(int, jsregexp_static_offsets_vector, kJSRegexpStaticOffsetsVectorSize) \
+ V(int, bad_char_shift_table, kUC16AlphabetSize) \
+ V(int, good_suffix_shift_table, (kBMMaxShift + 1)) \
+ V(int, suffix_table, (kBMMaxShift + 1)) \
+ ISOLATE_INIT_DEBUG_ARRAY_LIST(V)
+
+typedef List<HeapObject*, PreallocatedStorage> DebugObjectCache;
+
+#define ISOLATE_INIT_LIST(V) \
+ /* AssertNoZoneAllocation state. */ \
+ V(bool, zone_allow_allocation, true) \
+ /* SerializerDeserializer state. */ \
+ V(int, serialize_partial_snapshot_cache_length, 0) \
+ /* Assembler state. */ \
+ /* A previously allocated buffer of kMinimalBufferSize bytes, or NULL. */ \
+ V(byte*, assembler_spare_buffer, NULL) \
+ V(FatalErrorCallback, exception_behavior, NULL) \
+ V(v8::Debug::MessageHandler, message_handler, NULL) \
+ /* To distinguish the function templates, so that we can find them in the */ \
+ /* function cache of the global context. */ \
+ V(int, next_serial_number, 0) \
+ V(ExternalReferenceRedirectorPointer*, external_reference_redirector, NULL) \
+ V(bool, always_allow_natives_syntax, false) \
+ /* Part of the state of liveedit. */ \
+ V(FunctionInfoListener*, active_function_info_listener, NULL) \
+ /* State for Relocatable. */ \
+ V(Relocatable*, relocatable_top, NULL) \
+ /* State for CodeEntry in profile-generator. */ \
+ V(CodeGenerator*, current_code_generator, NULL) \
+ V(bool, jump_target_compiling_deferred_code, false) \
+ V(DebugObjectCache*, string_stream_debug_object_cache, NULL) \
+ V(Object*, string_stream_current_security_token, NULL) \
+ /* TODO(isolates): Release this on destruction? */ \
+ V(int*, irregexp_interpreter_backtrack_stack_cache, NULL) \
+ /* Serializer state. */ \
+ V(ExternalReferenceTable*, external_reference_table, NULL) \
+ /* AstNode state. */ \
+ V(unsigned, ast_node_id, 0) \
+ V(unsigned, ast_node_count, 0) \
+ ISOLATE_PLATFORM_INIT_LIST(V) \
+ ISOLATE_LOGGING_INIT_LIST(V) \
+ ISOLATE_DEBUGGER_INIT_LIST(V)
+
+class Isolate {
+ // These forward declarations are required to make the friend declarations in
+ // PerIsolateThreadData work on some older versions of gcc.
+ class ThreadDataTable;
+ class EntryStackItem;
+ public:
+ ~Isolate();
+
+ typedef int ThreadId;
+
+ // A thread has a PerIsolateThreadData instance for each isolate that it has
+ // entered. That instance is allocated when the isolate is initially entered
+ // and reused on subsequent entries.
+ class PerIsolateThreadData {
+ public:
+ PerIsolateThreadData(Isolate* isolate, ThreadId thread_id)
+ : isolate_(isolate),
+ thread_id_(thread_id),
+ stack_limit_(0),
+ thread_state_(NULL),
+#if !defined(__arm__) && defined(V8_TARGET_ARCH_ARM) || \
+ !defined(__mips__) && defined(V8_TARGET_ARCH_MIPS)
+ simulator_(NULL),
+#endif
+ next_(NULL),
+ prev_(NULL) { }
+ Isolate* isolate() const { return isolate_; }
+ ThreadId thread_id() const { return thread_id_; }
+ void set_stack_limit(uintptr_t value) { stack_limit_ = value; }
+ uintptr_t stack_limit() const { return stack_limit_; }
+ ThreadState* thread_state() const { return thread_state_; }
+ void set_thread_state(ThreadState* value) { thread_state_ = value; }
+
+#if !defined(__arm__) && defined(V8_TARGET_ARCH_ARM) || \
+ !defined(__mips__) && defined(V8_TARGET_ARCH_MIPS)
+ Simulator* simulator() const { return simulator_; }
+ void set_simulator(Simulator* simulator) {
+ simulator_ = simulator;
+ }
+#endif
+
+ bool Matches(Isolate* isolate, ThreadId thread_id) const {
+ return isolate_ == isolate && thread_id_ == thread_id;
+ }
+
+ private:
+ Isolate* isolate_;
+ ThreadId thread_id_;
+ uintptr_t stack_limit_;
+ ThreadState* thread_state_;
+
+#if !defined(__arm__) && defined(V8_TARGET_ARCH_ARM) || \
+ !defined(__mips__) && defined(V8_TARGET_ARCH_MIPS)
+ Simulator* simulator_;
+#endif
+
+ PerIsolateThreadData* next_;
+ PerIsolateThreadData* prev_;
+
+ friend class Isolate;
+ friend class ThreadDataTable;
+ friend class EntryStackItem;
+
+ DISALLOW_COPY_AND_ASSIGN(PerIsolateThreadData);
+ };
+
+
+ enum AddressId {
+#define C(name) k_##name,
+ ISOLATE_ADDRESS_LIST(C)
+ ISOLATE_ADDRESS_LIST_PROF(C)
+#undef C
+ k_isolate_address_count
+ };
+
+ // Returns the PerIsolateThreadData for the current thread (or NULL if one is
+ // not currently set).
+ static PerIsolateThreadData* CurrentPerIsolateThreadData() {
+ return reinterpret_cast<PerIsolateThreadData*>(
+ Thread::GetThreadLocal(per_isolate_thread_data_key_));
+ }
+
+ // Returns the isolate inside which the current thread is running.
+ INLINE(static Isolate* Current()) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(
+ Thread::GetExistingThreadLocal(isolate_key_));
+ ASSERT(isolate != NULL);
+ return isolate;
+ }
+
+ INLINE(static Isolate* UncheckedCurrent()) {
+ return reinterpret_cast<Isolate*>(Thread::GetThreadLocal(isolate_key_));
+ }
+
+ bool Init(Deserializer* des);
+
+ bool IsInitialized() { return state_ == INITIALIZED; }
+
+ // True if at least one thread Enter'ed this isolate.
+ bool IsInUse() { return entry_stack_ != NULL; }
+
+ // Destroys the non-default isolates.
+ // Sets default isolate into "has_been_disposed" state rather then destroying,
+ // for legacy API reasons.
+ void TearDown();
+
+ bool IsDefaultIsolate() const { return this == default_isolate_; }
+
+ // Ensures that process-wide resources and the default isolate have been
+ // allocated. It is only necessary to call this method in rare casses, for
+ // example if you are using V8 from within the body of a static initializer.
+ // Safe to call multiple times.
+ static void EnsureDefaultIsolate();
+
+ // Get the debugger from the default isolate. Preinitializes the
+ // default isolate if needed.
+ static Debugger* GetDefaultIsolateDebugger();
+
+ // Get the stack guard from the default isolate. Preinitializes the
+ // default isolate if needed.
+ static StackGuard* GetDefaultIsolateStackGuard();
+
+ // Returns the key used to store the pointer to the current isolate.
+ // Used internally for V8 threads that do not execute JavaScript but still
+ // are part of the domain of an isolate (like the context switcher).
+ static Thread::LocalStorageKey isolate_key() {
+ return isolate_key_;
+ }
+
+ // Returns the key used to store process-wide thread IDs.
+ static Thread::LocalStorageKey thread_id_key() {
+ return thread_id_key_;
+ }
+
+ // Atomically allocates a new thread ID.
+ static ThreadId AllocateThreadId();
+
+ // If a client attempts to create a Locker without specifying an isolate,
+ // we assume that the client is using legacy behavior. Set up the current
+ // thread to be inside the implicit isolate (or fail a check if we have
+ // switched to non-legacy behavior).
+ static void EnterDefaultIsolate();
+
+ // Debug.
+ // Mutex for serializing access to break control structures.
+ Mutex* break_access() { return break_access_; }
+
+ Address get_address_from_id(AddressId id);
+
+ // Access to top context (where the current function object was created).
+ Context* context() { return thread_local_top_.context_; }
+ void set_context(Context* context) {
+ thread_local_top_.context_ = context;
+ }
+ Context** context_address() { return &thread_local_top_.context_; }
+
+ SaveContext* save_context() {return thread_local_top_.save_context_; }
+ void set_save_context(SaveContext* save) {
+ thread_local_top_.save_context_ = save;
+ }
+
+ // Access to current thread id.
+ int thread_id() { return thread_local_top_.thread_id_; }
+ void set_thread_id(int id) { thread_local_top_.thread_id_ = id; }
+
+ // Interface to pending exception.
+ MaybeObject* pending_exception() {
+ ASSERT(has_pending_exception());
+ return thread_local_top_.pending_exception_;
+ }
+ bool external_caught_exception() {
+ return thread_local_top_.external_caught_exception_;
+ }
+ void set_pending_exception(MaybeObject* exception) {
+ thread_local_top_.pending_exception_ = exception;
+ }
+ void clear_pending_exception() {
+ thread_local_top_.pending_exception_ = heap_.the_hole_value();
+ }
+ MaybeObject** pending_exception_address() {
+ return &thread_local_top_.pending_exception_;
+ }
+ bool has_pending_exception() {
+ return !thread_local_top_.pending_exception_->IsTheHole();
+ }
+ void clear_pending_message() {
+ thread_local_top_.has_pending_message_ = false;
+ thread_local_top_.pending_message_ = NULL;
+ thread_local_top_.pending_message_obj_ = heap_.the_hole_value();
+ thread_local_top_.pending_message_script_ = NULL;
+ }
+ v8::TryCatch* try_catch_handler() {
+ return thread_local_top_.TryCatchHandler();
+ }
+ Address try_catch_handler_address() {
+ return thread_local_top_.try_catch_handler_address();
+ }
+ bool* external_caught_exception_address() {
+ return &thread_local_top_.external_caught_exception_;
+ }
+
+ MaybeObject** scheduled_exception_address() {
+ return &thread_local_top_.scheduled_exception_;
+ }
+ MaybeObject* scheduled_exception() {
+ ASSERT(has_scheduled_exception());
+ return thread_local_top_.scheduled_exception_;
+ }
+ bool has_scheduled_exception() {
+ return !thread_local_top_.scheduled_exception_->IsTheHole();
+ }
+ void clear_scheduled_exception() {
+ thread_local_top_.scheduled_exception_ = heap_.the_hole_value();
+ }
+
+ bool IsExternallyCaught();
+
+ bool is_catchable_by_javascript(MaybeObject* exception) {
+ return (exception != Failure::OutOfMemoryException()) &&
+ (exception != heap()->termination_exception());
+ }
+
+ // JS execution stack (see frames.h).
+ static Address c_entry_fp(ThreadLocalTop* thread) {
+ return thread->c_entry_fp_;
+ }
+ static Address handler(ThreadLocalTop* thread) { return thread->handler_; }
+
+ inline Address* c_entry_fp_address() {
+ return &thread_local_top_.c_entry_fp_;
+ }
+ inline Address* handler_address() { return &thread_local_top_.handler_; }
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ // Bottom JS entry (see StackTracer::Trace in log.cc).
+ static Address js_entry_sp(ThreadLocalTop* thread) {
+ return thread->js_entry_sp_;
+ }
+ inline Address* js_entry_sp_address() {
+ return &thread_local_top_.js_entry_sp_;
+ }
+#endif
+
+ // Generated code scratch locations.
+ void* formal_count_address() { return &thread_local_top_.formal_count_; }
+
+ // Returns the global object of the current context. It could be
+ // a builtin object, or a js global object.
+ Handle<GlobalObject> global() {
+ return Handle<GlobalObject>(context()->global());
+ }
+
+ // Returns the global proxy object of the current context.
+ Object* global_proxy() {
+ return context()->global_proxy();
+ }
+
+ Handle<JSBuiltinsObject> js_builtins_object() {
+ return Handle<JSBuiltinsObject>(thread_local_top_.context_->builtins());
+ }
+
+ static int ArchiveSpacePerThread() { return sizeof(ThreadLocalTop); }
+ void FreeThreadResources() { thread_local_top_.Free(); }
+
+ // This method is called by the api after operations that may throw
+ // exceptions. If an exception was thrown and not handled by an external
+ // handler the exception is scheduled to be rethrown when we return to running
+ // JavaScript code. If an exception is scheduled true is returned.
+ bool OptionalRescheduleException(bool is_bottom_call);
+
+ void SetCaptureStackTraceForUncaughtExceptions(
+ bool capture,
+ int frame_limit,
+ StackTrace::StackTraceOptions options);
+
+ // Tells whether the current context has experienced an out of memory
+ // exception.
+ bool is_out_of_memory();
+
+ void PrintCurrentStackTrace(FILE* out);
+ void PrintStackTrace(FILE* out, char* thread_data);
+ void PrintStack(StringStream* accumulator);
+ void PrintStack();
+ Handle<String> StackTraceString();
+ Handle<JSArray> CaptureCurrentStackTrace(
+ int frame_limit,
+ StackTrace::StackTraceOptions options);
+
+ // Returns if the top context may access the given global object. If
+ // the result is false, the pending exception is guaranteed to be
+ // set.
+ bool MayNamedAccess(JSObject* receiver,
+ Object* key,
+ v8::AccessType type);
+ bool MayIndexedAccess(JSObject* receiver,
+ uint32_t index,
+ v8::AccessType type);
+
+ void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
+ void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
+
+ // Exception throwing support. The caller should use the result
+ // of Throw() as its return value.
+ Failure* Throw(Object* exception, MessageLocation* location = NULL);
+ // Re-throw an exception. This involves no error reporting since
+ // error reporting was handled when the exception was thrown
+ // originally.
+ Failure* ReThrow(MaybeObject* exception, MessageLocation* location = NULL);
+ void ScheduleThrow(Object* exception);
+ void ReportPendingMessages();
+ Failure* ThrowIllegalOperation();
+
+ // Promote a scheduled exception to pending. Asserts has_scheduled_exception.
+ Failure* PromoteScheduledException();
+ void DoThrow(MaybeObject* exception,
+ MessageLocation* location,
+ const char* message);
+ // Checks if exception should be reported and finds out if it's
+ // caught externally.
+ bool ShouldReportException(bool* can_be_caught_externally,
+ bool catchable_by_javascript);
+
+ // Attempts to compute the current source location, storing the
+ // result in the target out parameter.
+ void ComputeLocation(MessageLocation* target);
+
+ // Override command line flag.
+ void TraceException(bool flag);
+
+ // Out of resource exception helpers.
+ Failure* StackOverflow();
+ Failure* TerminateExecution();
+
+ // Administration
+ void Iterate(ObjectVisitor* v);
+ void Iterate(ObjectVisitor* v, ThreadLocalTop* t);
+ char* Iterate(ObjectVisitor* v, char* t);
+ void IterateThread(ThreadVisitor* v);
+ void IterateThread(ThreadVisitor* v, char* t);
+
+
+ // Returns the current global context.
+ Handle<Context> global_context();
+
+ // Returns the global context of the calling JavaScript code. That
+ // is, the global context of the top-most JavaScript frame.
+ Handle<Context> GetCallingGlobalContext();
+
+ void RegisterTryCatchHandler(v8::TryCatch* that);
+ void UnregisterTryCatchHandler(v8::TryCatch* that);
+
+ char* ArchiveThread(char* to);
+ char* RestoreThread(char* from);
+
+ static const char* const kStackOverflowMessage;
+
+ static const int kUC16AlphabetSize = 256; // See StringSearchBase.
+ static const int kBMMaxShift = 250; // See StringSearchBase.
+
+ // Accessors.
+#define GLOBAL_ACCESSOR(type, name, initialvalue) \
+ inline type name() const { \
+ ASSERT(OFFSET_OF(Isolate, name##_) == name##_debug_offset_); \
+ return name##_; \
+ } \
+ inline void set_##name(type value) { \
+ ASSERT(OFFSET_OF(Isolate, name##_) == name##_debug_offset_); \
+ name##_ = value; \
+ }
+ ISOLATE_INIT_LIST(GLOBAL_ACCESSOR)
+#undef GLOBAL_ACCESSOR
+
+#define GLOBAL_ARRAY_ACCESSOR(type, name, length) \
+ inline type* name() { \
+ ASSERT(OFFSET_OF(Isolate, name##_) == name##_debug_offset_); \
+ return &(name##_)[0]; \
+ }
+ ISOLATE_INIT_ARRAY_LIST(GLOBAL_ARRAY_ACCESSOR)
+#undef GLOBAL_ARRAY_ACCESSOR
+
+#define GLOBAL_CONTEXT_FIELD_ACCESSOR(index, type, name) \
+ Handle<type> name() { \
+ return Handle<type>(context()->global_context()->name()); \
+ }
+ GLOBAL_CONTEXT_FIELDS(GLOBAL_CONTEXT_FIELD_ACCESSOR)
+#undef GLOBAL_CONTEXT_FIELD_ACCESSOR
+
+ Bootstrapper* bootstrapper() { return bootstrapper_; }
+ Counters* counters() { return counters_; }
+ // TODO(isolates): Having CPU features per isolate is probably too
+ // flexible. We only really need to have the set of currently
+ // enabled features for asserts in DEBUG builds.
+ CpuFeatures* cpu_features() { return cpu_features_; }
+ CodeRange* code_range() { return code_range_; }
+ RuntimeProfiler* runtime_profiler() { return runtime_profiler_; }
+ CompilationCache* compilation_cache() { return compilation_cache_; }
+ Logger* logger() { return logger_; }
+ StackGuard* stack_guard() { return &stack_guard_; }
+ Heap* heap() { return &heap_; }
+ StatsTable* stats_table() { return stats_table_; }
+ StubCache* stub_cache() { return stub_cache_; }
+ DeoptimizerData* deoptimizer_data() { return deoptimizer_data_; }
+ ThreadLocalTop* thread_local_top() { return &thread_local_top_; }
+
+ TranscendentalCache* transcendental_cache() const {
+ return transcendental_cache_;
+ }
+
+ MemoryAllocator* memory_allocator() {
+ return memory_allocator_;
+ }
+
+ KeyedLookupCache* keyed_lookup_cache() {
+ return keyed_lookup_cache_;
+ }
+
+ ContextSlotCache* context_slot_cache() {
+ return context_slot_cache_;
+ }
+
+ DescriptorLookupCache* descriptor_lookup_cache() {
+ return descriptor_lookup_cache_;
+ }
+
+ v8::ImplementationUtilities::HandleScopeData* handle_scope_data() {
+ return &handle_scope_data_;
+ }
+ HandleScopeImplementer* handle_scope_implementer() {
+ ASSERT(handle_scope_implementer_);
+ return handle_scope_implementer_;
+ }
+ Zone* zone() { return &zone_; }
+
+ ScannerConstants* scanner_constants() {
+ return scanner_constants_;
+ }
+
+ PcToCodeCache* pc_to_code_cache() { return pc_to_code_cache_; }
+
+ StringInputBuffer* write_input_buffer() { return write_input_buffer_; }
+
+ GlobalHandles* global_handles() { return global_handles_; }
+
+ ThreadManager* thread_manager() { return thread_manager_; }
+
+ ContextSwitcher* context_switcher() { return context_switcher_; }
+
+ void set_context_switcher(ContextSwitcher* switcher) {
+ context_switcher_ = switcher;
+ }
+
+ StringTracker* string_tracker() { return string_tracker_; }
+
+ unibrow::Mapping<unibrow::Ecma262UnCanonicalize>* jsregexp_uncanonicalize() {
+ return &jsregexp_uncanonicalize_;
+ }
+
+ unibrow::Mapping<unibrow::CanonicalizationRange>* jsregexp_canonrange() {
+ return &jsregexp_canonrange_;
+ }
+
+ StringInputBuffer* objects_string_compare_buffer_a() {
+ return &objects_string_compare_buffer_a_;
+ }
+
+ StringInputBuffer* objects_string_compare_buffer_b() {
+ return &objects_string_compare_buffer_b_;
+ }
+
+ StaticResource<StringInputBuffer>* objects_string_input_buffer() {
+ return &objects_string_input_buffer_;
+ }
+
+ AstSentinels* ast_sentinels() { return ast_sentinels_; }
+
+ RuntimeState* runtime_state() { return &runtime_state_; }
+
+ StringInputBuffer* liveedit_compare_substrings_buf1() {
+ return &liveedit_compare_substrings_buf1_;
+ }
+
+ StringInputBuffer* liveedit_compare_substrings_buf2() {
+ return &liveedit_compare_substrings_buf2_;
+ }
+
+ StaticResource<SafeStringInputBuffer>* compiler_safe_string_input_buffer() {
+ return &compiler_safe_string_input_buffer_;
+ }
+
+ Builtins* builtins() { return &builtins_; }
+
+ unibrow::Mapping<unibrow::Ecma262Canonicalize>*
+ regexp_macro_assembler_canonicalize() {
+ return &regexp_macro_assembler_canonicalize_;
+ }
+
+ RegExpStack* regexp_stack() { return regexp_stack_; }
+
+ unibrow::Mapping<unibrow::Ecma262Canonicalize>*
+ interp_canonicalize_mapping() {
+ return &interp_canonicalize_mapping_;
+ }
+
+ ZoneObjectList* frame_element_constant_list() {
+ return &frame_element_constant_list_;
+ }
+
+ ZoneObjectList* result_constant_list() {
+ return &result_constant_list_;
+ }
+
+ void* PreallocatedStorageNew(size_t size);
+ void PreallocatedStorageDelete(void* p);
+ void PreallocatedStorageInit(size_t size);
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ Debugger* debugger() { return debugger_; }
+ Debug* debug() { return debug_; }
+#endif
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ ProducerHeapProfile* producer_heap_profile() {
+ return producer_heap_profile_;
+ }
+#endif
+
+#ifdef DEBUG
+ HistogramInfo* heap_histograms() { return heap_histograms_; }
+
+ JSObject::SpillInformation* js_spill_information() {
+ return &js_spill_information_;
+ }
+
+ int* code_kind_statistics() { return code_kind_statistics_; }
+#endif
+
+#if defined(V8_TARGET_ARCH_ARM) && !defined(__arm__) || \
+ defined(V8_TARGET_ARCH_MIPS) && !defined(__mips__)
+ bool simulator_initialized() { return simulator_initialized_; }
+ void set_simulator_initialized(bool initialized) {
+ simulator_initialized_ = initialized;
+ }
+
+ HashMap* simulator_i_cache() { return simulator_i_cache_; }
+ void set_simulator_i_cache(HashMap* hash_map) {
+ simulator_i_cache_ = hash_map;
+ }
+
+ Redirection* simulator_redirection() {
+ return simulator_redirection_;
+ }
+ void set_simulator_redirection(Redirection* redirection) {
+ simulator_redirection_ = redirection;
+ }
+#endif
+
+ Factory* factory() { return reinterpret_cast<Factory*>(this); }
+
+ // SerializerDeserializer state.
+ static const int kPartialSnapshotCacheCapacity = 1400;
+
+ static const int kJSRegexpStaticOffsetsVectorSize = 50;
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ Address external_callback() {
+ return thread_local_top_.external_callback_;
+ }
+ void set_external_callback(Address callback) {
+ thread_local_top_.external_callback_ = callback;
+ }
+#endif
+
+#ifdef ENABLE_VMSTATE_TRACKING
+ StateTag current_vm_state() {
+ return thread_local_top_.current_vm_state_;
+ }
+
+ void SetCurrentVMState(StateTag state) {
+ if (RuntimeProfiler::IsEnabled()) {
+ if (state == JS) {
+ // JS or non-JS -> JS transition.
+ RuntimeProfiler::IsolateEnteredJS(this);
+ } else if (thread_local_top_.current_vm_state_ == JS) {
+ // JS -> non-JS transition.
+ ASSERT(RuntimeProfiler::IsSomeIsolateInJS());
+ RuntimeProfiler::IsolateExitedJS(this);
+ }
+ }
+ thread_local_top_.current_vm_state_ = state;
+ }
+#endif
+
+ void ResetEagerOptimizingData();
+
+ private:
+ Isolate();
+
+ // The per-process lock should be acquired before the ThreadDataTable is
+ // modified.
+ class ThreadDataTable {
+ public:
+ ThreadDataTable();
+ ~ThreadDataTable();
+
+ PerIsolateThreadData* Lookup(Isolate* isolate, ThreadId thread_id);
+ void Insert(PerIsolateThreadData* data);
+ void Remove(Isolate* isolate, ThreadId thread_id);
+ void Remove(PerIsolateThreadData* data);
+
+ private:
+ PerIsolateThreadData* list_;
+ };
+
+ // These items form a stack synchronously with threads Enter'ing and Exit'ing
+ // the Isolate. The top of the stack points to a thread which is currently
+ // running the Isolate. When the stack is empty, the Isolate is considered
+ // not entered by any thread and can be Disposed.
+ // If the same thread enters the Isolate more then once, the entry_count_
+ // is incremented rather then a new item pushed to the stack.
+ class EntryStackItem {
+ public:
+ EntryStackItem(PerIsolateThreadData* previous_thread_data,
+ Isolate* previous_isolate,
+ EntryStackItem* previous_item)
+ : entry_count(1),
+ previous_thread_data(previous_thread_data),
+ previous_isolate(previous_isolate),
+ previous_item(previous_item) { }
+
+ int entry_count;
+ PerIsolateThreadData* previous_thread_data;
+ Isolate* previous_isolate;
+ EntryStackItem* previous_item;
+
+ DISALLOW_COPY_AND_ASSIGN(EntryStackItem);
+ };
+
+ // This mutex protects highest_thread_id_, thread_data_table_ and
+ // default_isolate_.
+ static Mutex* process_wide_mutex_;
+
+ static Thread::LocalStorageKey per_isolate_thread_data_key_;
+ static Thread::LocalStorageKey isolate_key_;
+ static Thread::LocalStorageKey thread_id_key_;
+ static Isolate* default_isolate_;
+ static ThreadDataTable* thread_data_table_;
+ static ThreadId highest_thread_id_;
+
+ bool PreInit();
+
+ void Deinit();
+
+ static void SetIsolateThreadLocals(Isolate* isolate,
+ PerIsolateThreadData* data);
+
+ enum State {
+ UNINITIALIZED, // Some components may not have been allocated.
+ PREINITIALIZED, // Components have been allocated but not initialized.
+ INITIALIZED // All components are fully initialized.
+ };
+
+ State state_;
+ EntryStackItem* entry_stack_;
+
+ // Allocate and insert PerIsolateThreadData into the ThreadDataTable
+ // (regardless of whether such data already exists).
+ PerIsolateThreadData* AllocatePerIsolateThreadData(ThreadId thread_id);
+
+ // Find the PerThread for this particular (isolate, thread) combination.
+ // If one does not yet exist, allocate a new one.
+ PerIsolateThreadData* FindOrAllocatePerThreadDataForThisThread();
+
+ // PreInits and returns a default isolate. Needed when a new thread tries
+ // to create a Locker for the first time (the lock itself is in the isolate).
+ static Isolate* GetDefaultIsolateForLocking();
+
+ // Initializes the current thread to run this Isolate.
+ // Not thread-safe. Multiple threads should not Enter/Exit the same isolate
+ // at the same time, this should be prevented using external locking.
+ void Enter();
+
+ // Exits the current thread. The previosuly entered Isolate is restored
+ // for the thread.
+ // Not thread-safe. Multiple threads should not Enter/Exit the same isolate
+ // at the same time, this should be prevented using external locking.
+ void Exit();
+
+ void PreallocatedMemoryThreadStart();
+ void PreallocatedMemoryThreadStop();
+ void InitializeThreadLocal();
+
+ void PrintStackTrace(FILE* out, ThreadLocalTop* thread);
+ void MarkCompactPrologue(bool is_compacting,
+ ThreadLocalTop* archived_thread_data);
+ void MarkCompactEpilogue(bool is_compacting,
+ ThreadLocalTop* archived_thread_data);
+
+ void FillCache();
+
+ int stack_trace_nesting_level_;
+ StringStream* incomplete_message_;
+ // The preallocated memory thread singleton.
+ PreallocatedMemoryThread* preallocated_memory_thread_;
+ Address isolate_addresses_[k_isolate_address_count + 1]; // NOLINT
+ NoAllocationStringAllocator* preallocated_message_space_;
+
+ Bootstrapper* bootstrapper_;
+ RuntimeProfiler* runtime_profiler_;
+ CompilationCache* compilation_cache_;
+ Counters* counters_;
+ CpuFeatures* cpu_features_;
+ CodeRange* code_range_;
+ Mutex* break_access_;
+ Heap heap_;
+ Logger* logger_;
+ StackGuard stack_guard_;
+ StatsTable* stats_table_;
+ StubCache* stub_cache_;
+ DeoptimizerData* deoptimizer_data_;
+ ThreadLocalTop thread_local_top_;
+ bool capture_stack_trace_for_uncaught_exceptions_;
+ int stack_trace_for_uncaught_exceptions_frame_limit_;
+ StackTrace::StackTraceOptions stack_trace_for_uncaught_exceptions_options_;
+ TranscendentalCache* transcendental_cache_;
+ MemoryAllocator* memory_allocator_;
+ KeyedLookupCache* keyed_lookup_cache_;
+ ContextSlotCache* context_slot_cache_;
+ DescriptorLookupCache* descriptor_lookup_cache_;
+ v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
+ HandleScopeImplementer* handle_scope_implementer_;
+ ScannerConstants* scanner_constants_;
+ Zone zone_;
+ PreallocatedStorage in_use_list_;
+ PreallocatedStorage free_list_;
+ bool preallocated_storage_preallocated_;
+ PcToCodeCache* pc_to_code_cache_;
+ StringInputBuffer* write_input_buffer_;
+ GlobalHandles* global_handles_;
+ ContextSwitcher* context_switcher_;
+ ThreadManager* thread_manager_;
+ AstSentinels* ast_sentinels_;
+ RuntimeState runtime_state_;
+ StringInputBuffer liveedit_compare_substrings_buf1_;
+ StringInputBuffer liveedit_compare_substrings_buf2_;
+ StaticResource<SafeStringInputBuffer> compiler_safe_string_input_buffer_;
+ Builtins builtins_;
+ StringTracker* string_tracker_;
+ unibrow::Mapping<unibrow::Ecma262UnCanonicalize> jsregexp_uncanonicalize_;
+ unibrow::Mapping<unibrow::CanonicalizationRange> jsregexp_canonrange_;
+ StringInputBuffer objects_string_compare_buffer_a_;
+ StringInputBuffer objects_string_compare_buffer_b_;
+ StaticResource<StringInputBuffer> objects_string_input_buffer_;
+ unibrow::Mapping<unibrow::Ecma262Canonicalize>
+ regexp_macro_assembler_canonicalize_;
+ RegExpStack* regexp_stack_;
+ unibrow::Mapping<unibrow::Ecma262Canonicalize> interp_canonicalize_mapping_;
+ ZoneObjectList frame_element_constant_list_;
+ ZoneObjectList result_constant_list_;
+
+#if defined(V8_TARGET_ARCH_ARM) && !defined(__arm__) || \
+ defined(V8_TARGET_ARCH_MIPS) && !defined(__mips__)
+ bool simulator_initialized_;
+ HashMap* simulator_i_cache_;
+ Redirection* simulator_redirection_;
+#endif
+
+#ifdef DEBUG
+ // A static array of histogram info for each type.
+ HistogramInfo heap_histograms_[LAST_TYPE + 1];
+ JSObject::SpillInformation js_spill_information_;
+ int code_kind_statistics_[Code::NUMBER_OF_KINDS];
+#endif
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ Debugger* debugger_;
+ Debug* debug_;
+#endif
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ ProducerHeapProfile* producer_heap_profile_;
+#endif
+
+#define GLOBAL_BACKING_STORE(type, name, initialvalue) \
+ type name##_;
+ ISOLATE_INIT_LIST(GLOBAL_BACKING_STORE)
+#undef GLOBAL_BACKING_STORE
+
+#define GLOBAL_ARRAY_BACKING_STORE(type, name, length) \
+ type name##_[length];
+ ISOLATE_INIT_ARRAY_LIST(GLOBAL_ARRAY_BACKING_STORE)
+#undef GLOBAL_ARRAY_BACKING_STORE
+
+#ifdef DEBUG
+ // This class is huge and has a number of fields controlled by
+ // preprocessor defines. Make sure the offsets of these fields agree
+ // between compilation units.
+#define ISOLATE_FIELD_OFFSET(type, name, ignored) \
+ static const intptr_t name##_debug_offset_;
+ ISOLATE_INIT_LIST(ISOLATE_FIELD_OFFSET)
+ ISOLATE_INIT_ARRAY_LIST(ISOLATE_FIELD_OFFSET)
+#undef ISOLATE_FIELD_OFFSET
+#endif
+
+ friend class ExecutionAccess;
+ friend class IsolateInitializer;
+ friend class v8::Isolate;
+ friend class v8::Locker;
+
+ DISALLOW_COPY_AND_ASSIGN(Isolate);
+};
+
+
+// If the GCC version is 4.1.x or 4.2.x an additional field is added to the
+// class as a work around for a bug in the generated code found with these
+// versions of GCC. See V8 issue 122 for details.
+class SaveContext BASE_EMBEDDED {
+ public:
+ explicit SaveContext(Isolate* isolate) : prev_(isolate->save_context()) {
+ if (isolate->context() != NULL) {
+ context_ = Handle<Context>(isolate->context());
+#if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300
+ dummy_ = Handle<Context>(isolate->context());
+#endif
+ }
+ isolate->set_save_context(this);
+
+ // If there is no JS frame under the current C frame, use the value 0.
+ JavaScriptFrameIterator it;
+ js_sp_ = it.done() ? 0 : it.frame()->sp();
+ }
+
+ ~SaveContext() {
+ if (context_.is_null()) {
+ Isolate* isolate = Isolate::Current();
+ isolate->set_context(NULL);
+ isolate->set_save_context(prev_);
+ } else {
+ Isolate* isolate = context_->GetIsolate();
+ isolate->set_context(*context_);
+ isolate->set_save_context(prev_);
+ }
+ }
+
+ Handle<Context> context() { return context_; }
+ SaveContext* prev() { return prev_; }
+
+ // Returns true if this save context is below a given JavaScript frame.
+ bool below(JavaScriptFrame* frame) {
+ return (js_sp_ == 0) || (frame->sp() < js_sp_);
+ }
+
+ private:
+ Handle<Context> context_;
+#if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300
+ Handle<Context> dummy_;
+#endif
+ SaveContext* prev_;
+ Address js_sp_; // The top JS frame's sp when saving context.
+};
+
+
+class AssertNoContextChange BASE_EMBEDDED {
+#ifdef DEBUG
+ public:
+ AssertNoContextChange() :
+ scope_(Isolate::Current()),
+ context_(Isolate::Current()->context(), Isolate::Current()) {
+ }
+
+ ~AssertNoContextChange() {
+ ASSERT(Isolate::Current()->context() == *context_);
+ }
+
+ private:
+ HandleScope scope_;
+ Handle<Context> context_;
+#else
+ public:
+ AssertNoContextChange() { }
+#endif
+};
+
+
+class ExecutionAccess BASE_EMBEDDED {
+ public:
+ explicit ExecutionAccess(Isolate* isolate) : isolate_(isolate) {
+ Lock(isolate);
+ }
+ ~ExecutionAccess() { Unlock(isolate_); }
+
+ static void Lock(Isolate* isolate) { isolate->break_access_->Lock(); }
+ static void Unlock(Isolate* isolate) { isolate->break_access_->Unlock(); }
+
+ static bool TryLock(Isolate* isolate) {
+ return isolate->break_access_->TryLock();
+ }
+
+ private:
+ Isolate* isolate_;
+};
+
+
+// Support for checking for stack-overflows in C++ code.
+class StackLimitCheck BASE_EMBEDDED {
+ public:
+ explicit StackLimitCheck(Isolate* isolate) : isolate_(isolate) { }
+
+ bool HasOverflowed() const {
+ StackGuard* stack_guard = isolate_->stack_guard();
+ // Stack has overflowed in C++ code only if stack pointer exceeds the C++
+ // stack guard and the limits are not set to interrupt values.
+ // TODO(214): Stack overflows are ignored if a interrupt is pending. This
+ // code should probably always use the initial C++ limit.
+ return (reinterpret_cast<uintptr_t>(this) < stack_guard->climit()) &&
+ stack_guard->IsStackOverflow();
+ }
+ private:
+ Isolate* isolate_;
+};
+
+
+// Support for temporarily postponing interrupts. When the outermost
+// postpone scope is left the interrupts will be re-enabled and any
+// interrupts that occurred while in the scope will be taken into
+// account.
+class PostponeInterruptsScope BASE_EMBEDDED {
+ public:
+ explicit PostponeInterruptsScope(Isolate* isolate)
+ : stack_guard_(isolate->stack_guard()) {
+ stack_guard_->thread_local_.postpone_interrupts_nesting_++;
+ stack_guard_->DisableInterrupts();
+ }
+
+ ~PostponeInterruptsScope() {
+ if (--stack_guard_->thread_local_.postpone_interrupts_nesting_ == 0) {
+ stack_guard_->EnableInterrupts();
+ }
+ }
+ private:
+ StackGuard* stack_guard_;
+};
+
+
+// Temporary macros for accessing current isolate and its subobjects.
+// They provide better readability, especially when used a lot in the code.
+#define HEAP (v8::internal::Isolate::Current()->heap())
+#define FACTORY (v8::internal::Isolate::Current()->factory())
+#define ISOLATE (v8::internal::Isolate::Current())
+#define ZONE (v8::internal::Isolate::Current()->zone())
+#define LOGGER (v8::internal::Isolate::Current()->logger())
+
+
+// Tells whether the global context is marked with out of memory.
+inline bool Context::has_out_of_memory() {
+ return global_context()->out_of_memory()->IsTrue();
+}
+
+
+// Mark the global context with out of memory.
+inline void Context::mark_out_of_memory() {
+ global_context()->set_out_of_memory(HEAP->true_value());
+}
+
+
+// Temporary macro to be used to flag definitions that are indeed static
+// and not per-isolate. (It would be great to be able to grep for [static]!)
+#define RLYSTC static
+
+
+// Temporary macro to be used to flag classes that should be static.
+#define STATIC_CLASS class
+
+
+// Temporary macro to be used to flag classes that are completely converted
+// to be isolate-friendly. Their mix of static/nonstatic methods/fields is
+// correct.
+#define ISOLATED_CLASS class
+
+} } // namespace v8::internal
+
+// TODO(isolates): Get rid of these -inl.h includes and place them only where
+// they're needed.
+#include "allocation-inl.h"
+#include "zone-inl.h"
+#include "frames-inl.h"
+
+#endif // V8_ISOLATE_H_
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index b271b027..06aae352 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -35,7 +35,6 @@
#include "platform.h"
#include "string-search.h"
#include "runtime.h"
-#include "top.h"
#include "compilation-cache.h"
#include "string-stream.h"
#include "parser.h"
@@ -51,6 +50,8 @@
#include "x64/regexp-macro-assembler-x64.h"
#elif V8_TARGET_ARCH_ARM
#include "arm/regexp-macro-assembler-arm.h"
+#elif V8_TARGET_ARCH_MIPS
+#include "mips/regexp-macro-assembler-mips.h"
#else
#error Unsupported target architecture.
#endif
@@ -62,7 +63,6 @@
namespace v8 {
namespace internal {
-
Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor,
Handle<String> pattern,
Handle<String> flags,
@@ -97,12 +97,14 @@ static inline void ThrowRegExpException(Handle<JSRegExp> re,
Handle<String> pattern,
Handle<String> error_text,
const char* message) {
- Handle<FixedArray> elements = Factory::NewFixedArray(2);
+ Isolate* isolate = re->GetIsolate();
+ Factory* factory = isolate->factory();
+ Handle<FixedArray> elements = factory->NewFixedArray(2);
elements->set(0, *pattern);
elements->set(1, *error_text);
- Handle<JSArray> array = Factory::NewJSArrayWithElements(elements);
- Handle<Object> regexp_err = Factory::NewSyntaxError(message, array);
- Top::Throw(*regexp_err);
+ Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
+ Handle<Object> regexp_err = factory->NewSyntaxError(message, array);
+ isolate->Throw(*regexp_err);
}
@@ -112,10 +114,12 @@ static inline void ThrowRegExpException(Handle<JSRegExp> re,
Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
Handle<String> pattern,
Handle<String> flag_str) {
+ Isolate* isolate = re->GetIsolate();
JSRegExp::Flags flags = RegExpFlagsFromString(flag_str);
- Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags);
+ CompilationCache* compilation_cache = isolate->compilation_cache();
+ Handle<FixedArray> cached = compilation_cache->LookupRegExp(pattern, flags);
bool in_cache = !cached.is_null();
- LOG(RegExpCompileEvent(re, in_cache));
+ LOG(isolate, RegExpCompileEvent(re, in_cache));
Handle<Object> result;
if (in_cache) {
@@ -124,9 +128,9 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
}
pattern = FlattenGetString(pattern);
CompilationZoneScope zone_scope(DELETE_ON_EXIT);
- PostponeInterruptsScope postpone;
+ PostponeInterruptsScope postpone(isolate);
RegExpCompileData parse_result;
- FlatStringReader reader(pattern);
+ FlatStringReader reader(isolate, pattern);
if (!RegExpParser::ParseRegExp(&reader, flags.is_multiline(),
&parse_result)) {
// Throw an exception if we fail to parse the pattern.
@@ -145,7 +149,8 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
parse_result.capture_count == 0) {
RegExpAtom* atom = parse_result.tree->AsAtom();
Vector<const uc16> atom_pattern = atom->data();
- Handle<String> atom_string = Factory::NewStringFromTwoByte(atom_pattern);
+ Handle<String> atom_string =
+ isolate->factory()->NewStringFromTwoByte(atom_pattern);
AtomCompile(re, pattern, flags, atom_string);
} else {
IrregexpInitialize(re, pattern, flags, parse_result.capture_count);
@@ -154,7 +159,7 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
// Compilation succeeded so the data is set on the regexp
// and we can store it in the cache.
Handle<FixedArray> data(FixedArray::cast(re->data()));
- CompilationCache::PutRegExp(pattern, flags, data);
+ compilation_cache->PutRegExp(pattern, flags, data);
return re;
}
@@ -170,7 +175,7 @@ Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp,
case JSRegExp::IRREGEXP: {
Handle<Object> result =
IrregexpExec(regexp, subject, index, last_match_info);
- ASSERT(!result.is_null() || Top::has_pending_exception());
+ ASSERT(!result.is_null() || Isolate::Current()->has_pending_exception());
return result;
}
default:
@@ -187,11 +192,11 @@ void RegExpImpl::AtomCompile(Handle<JSRegExp> re,
Handle<String> pattern,
JSRegExp::Flags flags,
Handle<String> match_pattern) {
- Factory::SetRegExpAtomData(re,
- JSRegExp::ATOM,
- pattern,
- flags,
- match_pattern);
+ re->GetIsolate()->factory()->SetRegExpAtomData(re,
+ JSRegExp::ATOM,
+ pattern,
+ flags,
+ match_pattern);
}
@@ -224,6 +229,8 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
Handle<String> subject,
int index,
Handle<JSArray> last_match_info) {
+ Isolate* isolate = re->GetIsolate();
+
ASSERT(0 <= index);
ASSERT(index <= subject->length());
@@ -237,24 +244,30 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
int needle_len = needle->length();
if (needle_len != 0) {
- if (index + needle_len > subject->length()) return Factory::null_value();
+ if (index + needle_len > subject->length())
+ return isolate->factory()->null_value();
+
// dispatch on type of strings
index = (needle->IsAsciiRepresentation()
? (seq_sub->IsAsciiRepresentation()
- ? SearchString(seq_sub->ToAsciiVector(),
+ ? SearchString(isolate,
+ seq_sub->ToAsciiVector(),
needle->ToAsciiVector(),
index)
- : SearchString(seq_sub->ToUC16Vector(),
+ : SearchString(isolate,
+ seq_sub->ToUC16Vector(),
needle->ToAsciiVector(),
index))
: (seq_sub->IsAsciiRepresentation()
- ? SearchString(seq_sub->ToAsciiVector(),
+ ? SearchString(isolate,
+ seq_sub->ToAsciiVector(),
needle->ToUC16Vector(),
index)
- : SearchString(seq_sub->ToUC16Vector(),
+ : SearchString(isolate,
+ seq_sub->ToUC16Vector(),
needle->ToUC16Vector(),
index)));
- if (index == -1) return Factory::null_value();
+ if (index == -1) return FACTORY->null_value();
}
ASSERT(last_match_info->HasFastElements());
@@ -288,13 +301,14 @@ bool RegExpImpl::EnsureCompiledIrregexp(Handle<JSRegExp> re, bool is_ascii) {
bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) {
// Compile the RegExp.
+ Isolate* isolate = re->GetIsolate();
CompilationZoneScope zone_scope(DELETE_ON_EXIT);
- PostponeInterruptsScope postpone;
+ PostponeInterruptsScope postpone(isolate);
Object* entry = re->DataAt(JSRegExp::code_index(is_ascii));
if (entry->IsJSObject()) {
// If it's a JSObject, a previous compilation failed and threw this object.
// Re-throw the object without trying again.
- Top::Throw(entry);
+ isolate->Throw(entry);
return false;
}
ASSERT(entry->IsTheHole());
@@ -307,7 +321,7 @@ bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) {
}
RegExpCompileData compile_data;
- FlatStringReader reader(pattern);
+ FlatStringReader reader(isolate, pattern);
if (!RegExpParser::ParseRegExp(&reader, flags.is_multiline(),
&compile_data)) {
// Throw an exception if we fail to parse the pattern.
@@ -326,15 +340,16 @@ bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) {
is_ascii);
if (result.error_message != NULL) {
// Unable to compile regexp.
- Handle<FixedArray> elements = Factory::NewFixedArray(2);
+ Factory* factory = isolate->factory();
+ Handle<FixedArray> elements = factory->NewFixedArray(2);
elements->set(0, *pattern);
Handle<String> error_message =
- Factory::NewStringFromUtf8(CStrVector(result.error_message));
+ factory->NewStringFromUtf8(CStrVector(result.error_message));
elements->set(1, *error_message);
- Handle<JSArray> array = Factory::NewJSArrayWithElements(elements);
+ Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
Handle<Object> regexp_err =
- Factory::NewSyntaxError("malformed_regexp", array);
- Top::Throw(*regexp_err);
+ factory->NewSyntaxError("malformed_regexp", array);
+ isolate->Throw(*regexp_err);
re->SetDataAt(JSRegExp::code_index(is_ascii), *regexp_err);
return false;
}
@@ -386,11 +401,11 @@ void RegExpImpl::IrregexpInitialize(Handle<JSRegExp> re,
JSRegExp::Flags flags,
int capture_count) {
// Initialize compiled code entries to null.
- Factory::SetRegExpIrregexpData(re,
- JSRegExp::IRREGEXP,
- pattern,
- flags,
- capture_count);
+ re->GetIsolate()->factory()->SetRegExpIrregexpData(re,
+ JSRegExp::IRREGEXP,
+ pattern,
+ flags,
+ capture_count);
}
@@ -428,7 +443,9 @@ RegExpImpl::IrregexpResult RegExpImpl::IrregexpExecOnce(
Handle<String> subject,
int index,
Vector<int> output) {
- Handle<FixedArray> irregexp(FixedArray::cast(regexp->data()));
+ Isolate* isolate = regexp->GetIsolate();
+
+ Handle<FixedArray> irregexp(FixedArray::cast(regexp->data()), isolate);
ASSERT(index >= 0);
ASSERT(index <= subject->length());
@@ -436,24 +453,24 @@ RegExpImpl::IrregexpResult RegExpImpl::IrregexpExecOnce(
// A flat ASCII string might have a two-byte first part.
if (subject->IsConsString()) {
- subject = Handle<String>(ConsString::cast(*subject)->first());
+ subject = Handle<String>(ConsString::cast(*subject)->first(), isolate);
}
#ifndef V8_INTERPRETED_REGEXP
- ASSERT(output.length() >=
- (IrregexpNumberOfCaptures(*irregexp) + 1) * 2);
+ ASSERT(output.length() >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2);
do {
bool is_ascii = subject->IsAsciiRepresentation();
- Handle<Code> code(IrregexpNativeCode(*irregexp, is_ascii));
+ Handle<Code> code(IrregexpNativeCode(*irregexp, is_ascii), isolate);
NativeRegExpMacroAssembler::Result res =
NativeRegExpMacroAssembler::Match(code,
subject,
output.start(),
output.length(),
- index);
+ index,
+ isolate);
if (res != NativeRegExpMacroAssembler::RETRY) {
ASSERT(res != NativeRegExpMacroAssembler::EXCEPTION ||
- Top::has_pending_exception());
+ isolate->has_pending_exception());
STATIC_ASSERT(
static_cast<int>(NativeRegExpMacroAssembler::SUCCESS) == RE_SUCCESS);
STATIC_ASSERT(
@@ -484,9 +501,10 @@ RegExpImpl::IrregexpResult RegExpImpl::IrregexpExecOnce(
for (int i = number_of_capture_registers - 1; i >= 0; i--) {
register_vector[i] = -1;
}
- Handle<ByteArray> byte_codes(IrregexpByteCode(*irregexp, is_ascii));
+ Handle<ByteArray> byte_codes(IrregexpByteCode(*irregexp, is_ascii), isolate);
- if (IrregexpInterpreter::Match(byte_codes,
+ if (IrregexpInterpreter::Match(isolate,
+ byte_codes,
subject,
register_vector,
index)) {
@@ -516,7 +534,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
int required_registers = RegExpImpl::IrregexpPrepare(jsregexp, subject);
if (required_registers < 0) {
// Compiling failed with an exception.
- ASSERT(Top::has_pending_exception());
+ ASSERT(Isolate::Current()->has_pending_exception());
return Handle<Object>::null();
}
@@ -542,11 +560,11 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
return last_match_info;
}
if (res == RE_EXCEPTION) {
- ASSERT(Top::has_pending_exception());
+ ASSERT(Isolate::Current()->has_pending_exception());
return Handle<Object>::null();
}
ASSERT(res == RE_FAILURE);
- return Factory::null_value();
+ return Isolate::Current()->factory()->null_value();
}
@@ -860,9 +878,11 @@ RegExpEngine::CompilationResult RegExpCompiler::Assemble(
if (reg_exp_too_big_) return IrregexpRegExpTooBig();
Handle<Object> code = macro_assembler_->GetCode(pattern);
-
work_list_ = NULL;
#ifdef DEBUG
+ if (FLAG_print_code) {
+ Handle<Code>::cast(code)->Disassemble(*pattern->ToCString());
+ }
if (FLAG_trace_regexp_assembler) {
delete macro_assembler_;
}
@@ -1304,16 +1324,14 @@ void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler,
}
-static unibrow::Mapping<unibrow::Ecma262UnCanonicalize> uncanonicalize;
-static unibrow::Mapping<unibrow::CanonicalizationRange> canonrange;
-
-
// Returns the number of characters in the equivalence class, omitting those
// that cannot occur in the source string because it is ASCII.
-static int GetCaseIndependentLetters(uc16 character,
+static int GetCaseIndependentLetters(Isolate* isolate,
+ uc16 character,
bool ascii_subject,
unibrow::uchar* letters) {
- int length = uncanonicalize.get(character, '\0', letters);
+ int length =
+ isolate->jsregexp_uncanonicalize()->get(character, '\0', letters);
// Unibrow returns 0 or 1 for characters where case independence is
// trivial.
if (length == 0) {
@@ -1329,7 +1347,8 @@ static int GetCaseIndependentLetters(uc16 character,
}
-static inline bool EmitSimpleCharacter(RegExpCompiler* compiler,
+static inline bool EmitSimpleCharacter(Isolate* isolate,
+ RegExpCompiler* compiler,
uc16 c,
Label* on_failure,
int cp_offset,
@@ -1351,7 +1370,8 @@ static inline bool EmitSimpleCharacter(RegExpCompiler* compiler,
// Only emits non-letters (things that don't have case). Only used for case
// independent matches.
-static inline bool EmitAtomNonLetter(RegExpCompiler* compiler,
+static inline bool EmitAtomNonLetter(Isolate* isolate,
+ RegExpCompiler* compiler,
uc16 c,
Label* on_failure,
int cp_offset,
@@ -1360,7 +1380,7 @@ static inline bool EmitAtomNonLetter(RegExpCompiler* compiler,
RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
bool ascii = compiler->ascii();
unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
- int length = GetCaseIndependentLetters(c, ascii, chars);
+ int length = GetCaseIndependentLetters(isolate, c, ascii, chars);
if (length < 1) {
// This can't match. Must be an ASCII subject and a non-ASCII character.
// We do not need to do anything since the ASCII pass already handled this.
@@ -1422,7 +1442,8 @@ static bool ShortCutEmitCharacterPair(RegExpMacroAssembler* macro_assembler,
}
-typedef bool EmitCharacterFunction(RegExpCompiler* compiler,
+typedef bool EmitCharacterFunction(Isolate* isolate,
+ RegExpCompiler* compiler,
uc16 c,
Label* on_failure,
int cp_offset,
@@ -1431,7 +1452,8 @@ typedef bool EmitCharacterFunction(RegExpCompiler* compiler,
// Only emits letters (things that have case). Only used for case independent
// matches.
-static inline bool EmitAtomLetter(RegExpCompiler* compiler,
+static inline bool EmitAtomLetter(Isolate* isolate,
+ RegExpCompiler* compiler,
uc16 c,
Label* on_failure,
int cp_offset,
@@ -1440,7 +1462,7 @@ static inline bool EmitAtomLetter(RegExpCompiler* compiler,
RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
bool ascii = compiler->ascii();
unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
- int length = GetCaseIndependentLetters(c, ascii, chars);
+ int length = GetCaseIndependentLetters(isolate, c, ascii, chars);
if (length <= 1) return false;
// We may not need to check against the end of the input string
// if this character lies before a character that matched.
@@ -1878,6 +1900,7 @@ void TextNode::GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start) {
+ Isolate* isolate = Isolate::Current();
ASSERT(characters_filled_in < details->characters());
int characters = details->characters();
int char_mask;
@@ -1908,7 +1931,8 @@ void TextNode::GetQuickCheckDetails(QuickCheckDetails* details,
}
if (compiler->ignore_case()) {
unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
- int length = GetCaseIndependentLetters(c, compiler->ascii(), chars);
+ int length = GetCaseIndependentLetters(isolate, c, compiler->ascii(),
+ chars);
ASSERT(length != 0); // Can only happen if c > char_mask (see above).
if (length == 1) {
// This letter has no case equivalents, so it's nice and simple
@@ -2408,6 +2432,7 @@ void TextNode::TextEmitPass(RegExpCompiler* compiler,
Trace* trace,
bool first_element_checked,
int* checked_up_to) {
+ Isolate* isolate = Isolate::Current();
RegExpMacroAssembler* assembler = compiler->macro_assembler();
bool ascii = compiler->ascii();
Label* backtrack = trace->backtrack();
@@ -2443,7 +2468,8 @@ void TextNode::TextEmitPass(RegExpCompiler* compiler,
break;
}
if (emit_function != NULL) {
- bool bound_checked = emit_function(compiler,
+ bool bound_checked = emit_function(isolate,
+ compiler,
quarks[j],
backtrack,
cp_offset + j,
@@ -4083,13 +4109,15 @@ void CharacterRange::Split(ZoneList<CharacterRange>* base,
}
-static void AddUncanonicals(ZoneList<CharacterRange>* ranges,
+static void AddUncanonicals(Isolate* isolate,
+ ZoneList<CharacterRange>* ranges,
int bottom,
int top);
void CharacterRange::AddCaseEquivalents(ZoneList<CharacterRange>* ranges,
bool is_ascii) {
+ Isolate* isolate = Isolate::Current();
uc16 bottom = from();
uc16 top = to();
if (is_ascii) {
@@ -4099,7 +4127,7 @@ void CharacterRange::AddCaseEquivalents(ZoneList<CharacterRange>* ranges,
unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
if (top == bottom) {
// If this is a singleton we just expand the one character.
- int length = uncanonicalize.get(bottom, '\0', chars);
+ int length = isolate->jsregexp_uncanonicalize()->get(bottom, '\0', chars);
for (int i = 0; i < length; i++) {
uc32 chr = chars[i];
if (chr != bottom) {
@@ -4128,7 +4156,7 @@ void CharacterRange::AddCaseEquivalents(ZoneList<CharacterRange>* ranges,
unibrow::uchar range[unibrow::Ecma262UnCanonicalize::kMaxWidth];
int pos = bottom;
while (pos < top) {
- int length = canonrange.get(pos, '\0', range);
+ int length = isolate->jsregexp_canonrange()->get(pos, '\0', range);
uc16 block_end;
if (length == 0) {
block_end = pos;
@@ -4137,7 +4165,7 @@ void CharacterRange::AddCaseEquivalents(ZoneList<CharacterRange>* ranges,
block_end = range[0];
}
int end = (block_end > top) ? top : block_end;
- length = uncanonicalize.get(block_end, '\0', range);
+ length = isolate->jsregexp_uncanonicalize()->get(block_end, '\0', range);
for (int i = 0; i < length; i++) {
uc32 c = range[i];
uc16 range_from = c - (block_end - pos);
@@ -4247,7 +4275,8 @@ SetRelation CharacterRange::WordCharacterRelation(
}
-static void AddUncanonicals(ZoneList<CharacterRange>* ranges,
+static void AddUncanonicals(Isolate* isolate,
+ ZoneList<CharacterRange>* ranges,
int bottom,
int top) {
unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
@@ -4279,8 +4308,8 @@ static void AddUncanonicals(ZoneList<CharacterRange>* ranges,
// case mappings.
for (int i = 0; i < boundary_count; i++) {
if (bottom < boundaries[i] && top >= boundaries[i]) {
- AddUncanonicals(ranges, bottom, boundaries[i] - 1);
- AddUncanonicals(ranges, boundaries[i], top);
+ AddUncanonicals(isolate, ranges, bottom, boundaries[i] - 1);
+ AddUncanonicals(isolate, ranges, boundaries[i], top);
return;
}
}
@@ -4291,7 +4320,8 @@ static void AddUncanonicals(ZoneList<CharacterRange>* ranges,
#ifdef DEBUG
for (int j = bottom; j <= top; j++) {
unsigned current_char = j;
- int length = uncanonicalize.get(current_char, '\0', chars);
+ int length = isolate->jsregexp_uncanonicalize()->get(current_char,
+ '\0', chars);
for (int k = 0; k < length; k++) {
ASSERT(chars[k] == current_char);
}
@@ -4304,7 +4334,7 @@ static void AddUncanonicals(ZoneList<CharacterRange>* ranges,
// Step through the range finding equivalent characters.
ZoneList<unibrow::uchar> *characters = new ZoneList<unibrow::uchar>(100);
for (int i = bottom; i <= top; i++) {
- int length = uncanonicalize.get(i, '\0', chars);
+ int length = isolate->jsregexp_uncanonicalize()->get(i, '\0', chars);
for (int j = 0; j < length; j++) {
uc32 chr = chars[j];
if (chr != i && (chr < bottom || chr > top)) {
@@ -4826,7 +4856,7 @@ OutSet* DispatchTable::Get(uc16 value) {
void Analysis::EnsureAnalyzed(RegExpNode* that) {
- StackLimitCheck check;
+ StackLimitCheck check(Isolate::Current());
if (check.HasOverflowed()) {
fail("Stack overflow");
return;
@@ -5312,6 +5342,8 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data,
RegExpMacroAssemblerX64 macro_assembler(mode, (data->capture_count + 1) * 2);
#elif V8_TARGET_ARCH_ARM
RegExpMacroAssemblerARM macro_assembler(mode, (data->capture_count + 1) * 2);
+#elif V8_TARGET_ARCH_MIPS
+ RegExpMacroAssemblerMIPS macro_assembler(mode, (data->capture_count + 1) * 2);
#endif
#else // V8_INTERPRETED_REGEXP
@@ -5336,7 +5368,4 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data,
}
-int OffsetsVector::static_offsets_vector_[
- OffsetsVector::kStaticOffsetsVectorSize];
-
}} // namespace v8::internal
diff --git a/src/jsregexp.h b/src/jsregexp.h
index af28a872..3ed5a7e4 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -1424,7 +1424,7 @@ class RegExpEngine: public AllStatic {
struct CompilationResult {
explicit CompilationResult(const char* error_message)
: error_message(error_message),
- code(Heap::the_hole_value()),
+ code(HEAP->the_hole_value()),
num_registers(0) {}
CompilationResult(Object* code, int registers)
: error_message(NULL),
@@ -1449,14 +1449,14 @@ class OffsetsVector {
public:
inline OffsetsVector(int num_registers)
: offsets_vector_length_(num_registers) {
- if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
+ if (offsets_vector_length_ > Isolate::kJSRegexpStaticOffsetsVectorSize) {
vector_ = NewArray<int>(offsets_vector_length_);
} else {
- vector_ = static_offsets_vector_;
+ vector_ = Isolate::Current()->jsregexp_static_offsets_vector();
}
}
inline ~OffsetsVector() {
- if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
+ if (offsets_vector_length_ > Isolate::kJSRegexpStaticOffsetsVectorSize) {
DeleteArray(vector_);
vector_ = NULL;
}
@@ -1467,13 +1467,12 @@ class OffsetsVector {
static const int kStaticOffsetsVectorSize = 50;
private:
- static Address static_offsets_vector_address() {
- return reinterpret_cast<Address>(&static_offsets_vector_);
+ static Address static_offsets_vector_address(Isolate* isolate) {
+ return reinterpret_cast<Address>(isolate->jsregexp_static_offsets_vector());
}
int* vector_;
int offsets_vector_length_;
- static int static_offsets_vector_[kStaticOffsetsVectorSize];
friend class ExternalReference;
};
diff --git a/src/jump-target-heavy.cc b/src/jump-target-heavy.cc
index c3c22f1a..f73e0275 100644
--- a/src/jump-target-heavy.cc
+++ b/src/jump-target-heavy.cc
@@ -35,9 +35,6 @@ namespace v8 {
namespace internal {
-bool JumpTarget::compiling_deferred_code_ = false;
-
-
void JumpTarget::Jump(Result* arg) {
ASSERT(cgen()->has_valid_frame());
@@ -143,9 +140,9 @@ void JumpTarget::ComputeEntryFrame() {
// the directionality of the block. Compute: an entry frame for the
// block.
- Counters::compute_entry_frame.Increment();
+ Isolate::Current()->counters()->compute_entry_frame()->Increment();
#ifdef DEBUG
- if (compiling_deferred_code_) {
+ if (Isolate::Current()->jump_target_compiling_deferred_code()) {
ASSERT(reaching_frames_.length() > 1);
VirtualFrame* frame = reaching_frames_[0];
bool all_identical = true;
@@ -413,15 +410,15 @@ void BreakTarget::Branch(Condition cc, Hint hint) {
DeferredCode::DeferredCode()
- : masm_(CodeGeneratorScope::Current()->masm()),
+ : masm_(CodeGeneratorScope::Current(Isolate::Current())->masm()),
statement_position_(masm_->positions_recorder()->
current_statement_position()),
position_(masm_->positions_recorder()->current_position()),
- frame_state_(CodeGeneratorScope::Current()->frame()) {
+ frame_state_(CodeGeneratorScope::Current(Isolate::Current())->frame()) {
ASSERT(statement_position_ != RelocInfo::kNoPosition);
ASSERT(position_ != RelocInfo::kNoPosition);
- CodeGeneratorScope::Current()->AddDeferred(this);
+ CodeGeneratorScope::Current(Isolate::Current())->AddDeferred(this);
#ifdef DEBUG
comment_ = "";
#endif
diff --git a/src/jump-target-heavy.h b/src/jump-target-heavy.h
index 8cec8692..bf977563 100644
--- a/src/jump-target-heavy.h
+++ b/src/jump-target-heavy.h
@@ -135,10 +135,6 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
// after the call is the same as the frame before the call.
void Call();
- static void set_compiling_deferred_code(bool flag) {
- compiling_deferred_code_ = flag;
- }
-
protected:
// Directionality flag set at initialization time.
Directionality direction_;
@@ -164,8 +160,6 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
void DoBind();
private:
- static bool compiling_deferred_code_;
-
// Add a virtual frame reaching this labeled block via a forward jump,
// and a corresponding merge code label.
void AddReachingFrame(VirtualFrame* frame);
diff --git a/src/jump-target-inl.h b/src/jump-target-inl.h
index 4c9ee5bc..545328c4 100644
--- a/src/jump-target-inl.h
+++ b/src/jump-target-inl.h
@@ -40,7 +40,7 @@ namespace v8 {
namespace internal {
CodeGenerator* JumpTarget::cgen() {
- return CodeGeneratorScope::Current();
+ return CodeGeneratorScope::Current(Isolate::Current());
}
} } // namespace v8::internal
diff --git a/src/jump-target-light.cc b/src/jump-target-light.cc
index 36dc176b..1d894745 100644
--- a/src/jump-target-light.cc
+++ b/src/jump-target-light.cc
@@ -35,15 +35,15 @@ namespace internal {
DeferredCode::DeferredCode()
- : masm_(CodeGeneratorScope::Current()->masm()),
+ : masm_(CodeGeneratorScope::Current(Isolate::Current())->masm()),
statement_position_(masm_->positions_recorder()->
current_statement_position()),
position_(masm_->positions_recorder()->current_position()),
- frame_state_(*CodeGeneratorScope::Current()->frame()) {
+ frame_state_(*CodeGeneratorScope::Current(Isolate::Current())->frame()) {
ASSERT(statement_position_ != RelocInfo::kNoPosition);
ASSERT(position_ != RelocInfo::kNoPosition);
- CodeGeneratorScope::Current()->AddDeferred(this);
+ CodeGeneratorScope::Current(Isolate::Current())->AddDeferred(this);
#ifdef DEBUG
comment_ = "";
diff --git a/src/lithium-allocator-inl.h b/src/lithium-allocator-inl.h
index 84c5bbdc..c0beaafa 100644
--- a/src/lithium-allocator-inl.h
+++ b/src/lithium-allocator-inl.h
@@ -36,6 +36,8 @@
#include "x64/lithium-x64.h"
#elif V8_TARGET_ARCH_ARM
#include "arm/lithium-arm.h"
+#elif V8_TARGET_ARCH_MIPS
+#include "mips/lithium-mips.h"
#else
#error "Unknown architecture."
#endif
diff --git a/src/lithium-allocator.cc b/src/lithium-allocator.cc
index 5755bb2d..f62a7dbc 100644
--- a/src/lithium-allocator.cc
+++ b/src/lithium-allocator.cc
@@ -25,6 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "v8.h"
#include "lithium-allocator-inl.h"
#include "hydrogen.h"
@@ -36,6 +37,8 @@
#include "x64/lithium-x64.h"
#elif V8_TARGET_ARCH_ARM
#include "arm/lithium-arm.h"
+#elif V8_TARGET_ARCH_MIPS
+#include "mips/lithium-mips.h"
#else
#error "Unknown architecture."
#endif
@@ -44,13 +47,18 @@ namespace v8 {
namespace internal {
-#define DEFINE_OPERAND_CACHE(name, type) \
- name name::cache[name::kNumCachedOperands]; \
- void name::SetupCache() { \
- for (int i = 0; i < kNumCachedOperands; i++) { \
- cache[i].ConvertTo(type, i); \
- } \
- }
+#define DEFINE_OPERAND_CACHE(name, type) \
+ name name::cache[name::kNumCachedOperands]; \
+ void name::SetupCache() { \
+ for (int i = 0; i < kNumCachedOperands; i++) { \
+ cache[i].ConvertTo(type, i); \
+ } \
+ } \
+ static bool name##_initialize() { \
+ name::SetupCache(); \
+ return true; \
+ } \
+ static bool name##_cache_initialized = name##_initialize();
DEFINE_OPERAND_CACHE(LConstantOperand, CONSTANT_OPERAND)
DEFINE_OPERAND_CACHE(LStackSlot, STACK_SLOT)
@@ -525,6 +533,24 @@ LifetimePosition LiveRange::FirstIntersection(LiveRange* other) {
}
+LAllocator::LAllocator(int num_values, HGraph* graph)
+ : chunk_(NULL),
+ live_in_sets_(graph->blocks()->length()),
+ live_ranges_(num_values * 2),
+ fixed_live_ranges_(NULL),
+ fixed_double_live_ranges_(NULL),
+ unhandled_live_ranges_(num_values * 2),
+ active_live_ranges_(8),
+ inactive_live_ranges_(8),
+ reusable_slots_(8),
+ next_virtual_register_(num_values),
+ first_artificial_register_(num_values),
+ mode_(NONE),
+ num_registers_(-1),
+ graph_(graph),
+ has_osr_entry_(false) {}
+
+
void LAllocator::InitializeLivenessAnalysis() {
// Initialize the live_in sets for each block to NULL.
int block_count = graph_->blocks()->length();
@@ -618,11 +644,7 @@ LOperand* LAllocator::AllocateFixed(LUnallocated* operand,
LiveRange* LAllocator::FixedLiveRangeFor(int index) {
- if (index >= fixed_live_ranges_.length()) {
- fixed_live_ranges_.AddBlock(NULL,
- index - fixed_live_ranges_.length() + 1);
- }
-
+ ASSERT(index < Register::kNumAllocatableRegisters);
LiveRange* result = fixed_live_ranges_[index];
if (result == NULL) {
result = new LiveRange(FixedLiveRangeID(index));
@@ -635,11 +657,7 @@ LiveRange* LAllocator::FixedLiveRangeFor(int index) {
LiveRange* LAllocator::FixedDoubleLiveRangeFor(int index) {
- if (index >= fixed_double_live_ranges_.length()) {
- fixed_double_live_ranges_.AddBlock(NULL,
- index - fixed_double_live_ranges_.length() + 1);
- }
-
+ ASSERT(index < DoubleRegister::kNumAllocatableRegisters);
LiveRange* result = fixed_double_live_ranges_[index];
if (result == NULL) {
result = new LiveRange(FixedDoubleLiveRangeID(index));
@@ -650,6 +668,7 @@ LiveRange* LAllocator::FixedDoubleLiveRangeFor(int index) {
return result;
}
+
LiveRange* LAllocator::LiveRangeFor(int index) {
if (index >= live_ranges_.length()) {
live_ranges_.AddBlock(NULL, index - live_ranges_.length() + 1);
@@ -1436,7 +1455,7 @@ void LAllocator::AllocateDoubleRegisters() {
void LAllocator::AllocateRegisters() {
ASSERT(mode_ != NONE);
- reusable_slots_.Clear();
+ ASSERT(unhandled_live_ranges_.is_empty());
for (int i = 0; i < live_ranges_.length(); ++i) {
if (live_ranges_[i] != NULL) {
@@ -1448,6 +1467,7 @@ void LAllocator::AllocateRegisters() {
SortUnhandled();
ASSERT(UnhandledIsSorted());
+ ASSERT(reusable_slots_.is_empty());
ASSERT(active_live_ranges_.is_empty());
ASSERT(inactive_live_ranges_.is_empty());
@@ -1532,17 +1552,9 @@ void LAllocator::AllocateRegisters() {
}
}
- active_live_ranges_.Clear();
- inactive_live_ranges_.Clear();
-}
-
-
-void LAllocator::Setup() {
- LConstantOperand::SetupCache();
- LStackSlot::SetupCache();
- LDoubleStackSlot::SetupCache();
- LRegister::SetupCache();
- LDoubleRegister::SetupCache();
+ reusable_slots_.Rewind(0);
+ active_live_ranges_.Rewind(0);
+ inactive_live_ranges_.Rewind(0);
}
diff --git a/src/lithium-allocator.h b/src/lithium-allocator.h
index d53ea787..f109c454 100644
--- a/src/lithium-allocator.h
+++ b/src/lithium-allocator.h
@@ -428,24 +428,8 @@ class GrowableBitVector BASE_EMBEDDED {
class LAllocator BASE_EMBEDDED {
public:
- explicit LAllocator(int first_virtual_register, HGraph* graph)
- : chunk_(NULL),
- live_in_sets_(0),
- live_ranges_(16),
- fixed_live_ranges_(8),
- fixed_double_live_ranges_(8),
- unhandled_live_ranges_(8),
- active_live_ranges_(8),
- inactive_live_ranges_(8),
- reusable_slots_(8),
- next_virtual_register_(first_virtual_register),
- first_artificial_register_(first_virtual_register),
- mode_(NONE),
- num_registers_(-1),
- graph_(graph),
- has_osr_entry_(false) {}
-
- static void Setup();
+ LAllocator(int first_virtual_register, HGraph* graph);
+
static void TraceAlloc(const char* msg, ...);
// Lithium translation support.
@@ -468,10 +452,10 @@ class LAllocator BASE_EMBEDDED {
void Allocate(LChunk* chunk);
const ZoneList<LiveRange*>* live_ranges() const { return &live_ranges_; }
- const ZoneList<LiveRange*>* fixed_live_ranges() const {
+ const Vector<LiveRange*>* fixed_live_ranges() const {
return &fixed_live_ranges_;
}
- const ZoneList<LiveRange*>* fixed_double_live_ranges() const {
+ const Vector<LiveRange*>* fixed_double_live_ranges() const {
return &fixed_double_live_ranges_;
}
@@ -616,8 +600,10 @@ class LAllocator BASE_EMBEDDED {
ZoneList<LiveRange*> live_ranges_;
// Lists of live ranges
- ZoneList<LiveRange*> fixed_live_ranges_;
- ZoneList<LiveRange*> fixed_double_live_ranges_;
+ EmbeddedVector<LiveRange*, Register::kNumAllocatableRegisters>
+ fixed_live_ranges_;
+ EmbeddedVector<LiveRange*, DoubleRegister::kNumAllocatableRegisters>
+ fixed_double_live_ranges_;
ZoneList<LiveRange*> unhandled_live_ranges_;
ZoneList<LiveRange*> active_live_ranges_;
ZoneList<LiveRange*> inactive_live_ranges_;
diff --git a/src/lithium.cc b/src/lithium.cc
index e829f2f0..aeac2db5 100644
--- a/src/lithium.cc
+++ b/src/lithium.cc
@@ -25,6 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "v8.h"
#include "lithium.h"
namespace v8 {
diff --git a/src/liveedit.cc b/src/liveedit.cc
index 744ed49d..dbcf5efa 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -35,10 +35,10 @@
#include "debug.h"
#include "deoptimizer.h"
#include "global-handles.h"
-#include "memory.h"
#include "parser.h"
#include "scopeinfo.h"
#include "scopes.h"
+#include "v8memory.h"
namespace v8 {
namespace internal {
@@ -47,6 +47,18 @@ namespace internal {
#ifdef ENABLE_DEBUGGER_SUPPORT
+void SetElementNonStrict(Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value) {
+ // Ignore return value from SetElement. It can only be a failure if there
+ // are element setters causing exceptions and the debugger context has none
+ // of these.
+ Handle<Object> no_failure;
+ no_failure = SetElement(object, index, value, kNonStrictMode);
+ ASSERT(!no_failure.is_null());
+ USE(no_failure);
+}
+
// A simple implementation of dynamic programming algorithm. It solves
// the problem of finding the difference of 2 arrays. It uses a table of results
// of subproblems. Each cell contains a number together with 2-bit flag
@@ -256,10 +268,10 @@ void Comparator::CalculateDifference(Comparator::Input* input,
}
-static bool CompareSubstrings(Handle<String> s1, int pos1,
+static bool CompareSubstrings(Isolate* isolate, Handle<String> s1, int pos1,
Handle<String> s2, int pos2, int len) {
- static StringInputBuffer buf1;
- static StringInputBuffer buf2;
+ StringInputBuffer& buf1 = *isolate->liveedit_compare_substrings_buf1();
+ StringInputBuffer& buf2 = *isolate->liveedit_compare_substrings_buf2();
buf1.Reset(*s1);
buf1.Seek(pos1);
buf2.Reset(*s2);
@@ -279,25 +291,22 @@ static bool CompareSubstrings(Handle<String> s1, int pos1,
class CompareOutputArrayWriter {
public:
CompareOutputArrayWriter()
- : array_(Factory::NewJSArray(10)), current_size_(0) {}
+ : array_(FACTORY->NewJSArray(10)), current_size_(0) {}
Handle<JSArray> GetResult() {
return array_;
}
void WriteChunk(int char_pos1, int char_pos2, int char_len1, int char_len2) {
- SetElement(array_,
- current_size_,
- Handle<Object>(Smi::FromInt(char_pos1)),
- kNonStrictMode);
- SetElement(array_,
- current_size_ + 1,
- Handle<Object>(Smi::FromInt(char_pos1 + char_len1)),
- kNonStrictMode);
- SetElement(array_,
- current_size_ + 2,
- Handle<Object>(Smi::FromInt(char_pos2 + char_len2)),
- kNonStrictMode);
+ SetElementNonStrict(array_,
+ current_size_,
+ Handle<Object>(Smi::FromInt(char_pos1)));
+ SetElementNonStrict(array_,
+ current_size_ + 1,
+ Handle<Object>(Smi::FromInt(char_pos1 + char_len1)));
+ SetElementNonStrict(array_,
+ current_size_ + 2,
+ Handle<Object>(Smi::FromInt(char_pos2 + char_len2)));
current_size_ += 3;
}
@@ -401,9 +410,10 @@ class LineEndsWrapper {
// Represents 2 strings as 2 arrays of lines.
class LineArrayCompareInput : public Comparator::Input {
public:
- LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
+ LineArrayCompareInput(Isolate* isolate, Handle<String> s1, Handle<String> s2,
LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
- : s1_(s1), s2_(s2), line_ends1_(line_ends1), line_ends2_(line_ends2) {
+ : isolate_(isolate), s1_(s1), s2_(s2), line_ends1_(line_ends1),
+ line_ends2_(line_ends2) {
}
int getLength1() {
return line_ends1_.length();
@@ -421,10 +431,12 @@ class LineArrayCompareInput : public Comparator::Input {
if (len1 != len2) {
return false;
}
- return CompareSubstrings(s1_, line_start1, s2_, line_start2, len1);
+ return CompareSubstrings(isolate_, s1_, line_start1, s2_, line_start2,
+ len1);
}
private:
+ Isolate* isolate_;
Handle<String> s1_;
Handle<String> s2_;
LineEndsWrapper line_ends1_;
@@ -483,7 +495,8 @@ Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
LineEndsWrapper line_ends1(s1);
LineEndsWrapper line_ends2(s2);
- LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
+ LineArrayCompareInput
+ input(Isolate::Current(), s1, s2, line_ends1, line_ends2);
TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2);
Comparator::CalculateDifference(&input, &output);
@@ -492,21 +505,21 @@ Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
}
-static void CompileScriptForTracker(Handle<Script> script) {
+static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) {
// TODO(635): support extensions.
- PostponeInterruptsScope postpone;
+ PostponeInterruptsScope postpone(isolate);
// Build AST.
CompilationInfo info(script);
info.MarkAsGlobal();
if (ParserApi::Parse(&info)) {
// Compile the code.
- LiveEditFunctionTracker tracker(info.function());
+ LiveEditFunctionTracker tracker(info.isolate(), info.function());
if (Compiler::MakeCodeForLiveEdit(&info)) {
ASSERT(!info.code().is_null());
tracker.RecordRootFunctionInfo(info.code());
} else {
- Top::StackOverflow();
+ info.isolate()->StackOverflow();
}
}
}
@@ -521,9 +534,10 @@ static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
// Wraps any object into a OpaqueReference, that will hide the object
// from JavaScript.
static Handle<JSValue> WrapInJSValue(Object* object) {
- Handle<JSFunction> constructor = Top::opaque_reference_function();
+ Handle<JSFunction> constructor =
+ Isolate::Current()->opaque_reference_function();
Handle<JSValue> result =
- Handle<JSValue>::cast(Factory::NewJSObject(constructor));
+ Handle<JSValue>::cast(FACTORY->NewJSObject(constructor));
result->set_value(object);
return result;
}
@@ -536,7 +550,7 @@ template<typename S>
class JSArrayBasedStruct {
public:
static S Create() {
- Handle<JSArray> array = Factory::NewJSArray(S::kSize_);
+ Handle<JSArray> array = FACTORY->NewJSArray(S::kSize_);
return S(array);
}
static S cast(Object* object) {
@@ -552,13 +566,12 @@ class JSArrayBasedStruct {
protected:
void SetField(int field_position, Handle<Object> value) {
- SetElement(array_, field_position, value, kNonStrictMode);
+ SetElementNonStrict(array_, field_position, value);
}
void SetSmiValueField(int field_position, int value) {
- SetElement(array_,
- field_position,
- Handle<Smi>(Smi::FromInt(value)),
- kNonStrictMode);
+ SetElementNonStrict(array_,
+ field_position,
+ Handle<Smi>(Smi::FromInt(value)));
}
Object* GetField(int field_position) {
return array_->GetElementNoExceptionThrown(field_position);
@@ -687,7 +700,7 @@ class FunctionInfoListener {
FunctionInfoListener() {
current_parent_index_ = -1;
len_ = 0;
- result_ = Factory::NewJSArray(10);
+ result_ = FACTORY->NewJSArray(10);
}
void FunctionStarted(FunctionLiteral* fun) {
@@ -697,7 +710,7 @@ class FunctionInfoListener {
fun->end_position(), fun->num_parameters(),
current_parent_index_);
current_parent_index_ = len_;
- SetElement(result_, len_, info.GetJSArray(), kNonStrictMode);
+ SetElementNonStrict(result_, len_, info.GetJSArray());
len_++;
}
@@ -715,7 +728,7 @@ class FunctionInfoListener {
FunctionInfoWrapper info =
FunctionInfoWrapper::cast(
result_->GetElementNoExceptionThrown(current_parent_index_));
- info.SetFunctionCode(function_code, Handle<Object>(Heap::null_value()));
+ info.SetFunctionCode(function_code, Handle<Object>(HEAP->null_value()));
}
// Saves full information about a function: its code, its scope info
@@ -741,7 +754,7 @@ class FunctionInfoListener {
Object* SerializeFunctionScope(Scope* scope) {
HandleScope handle_scope;
- Handle<JSArray> scope_info_list = Factory::NewJSArray(10);
+ Handle<JSArray> scope_info_list = FACTORY->NewJSArray(10);
int scope_info_length = 0;
// Saves some description of scope. It stores name and indexes of
@@ -749,7 +762,7 @@ class FunctionInfoListener {
// scopes of this chain.
Scope* outer_scope = scope->outer_scope();
if (outer_scope == NULL) {
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
do {
ZoneList<Variable*> list(10);
@@ -777,16 +790,19 @@ class FunctionInfoListener {
list[k] = list[l];
}
for (int i = 0; i < j; i++) {
- SetElement(scope_info_list, scope_info_length,
- list[i]->name(), kNonStrictMode);
+ SetElementNonStrict(scope_info_list,
+ scope_info_length,
+ list[i]->name());
scope_info_length++;
- SetElement(scope_info_list, scope_info_length,
- Handle<Smi>(Smi::FromInt(list[i]->AsSlot()->index())),
- kNonStrictMode);
+ SetElementNonStrict(
+ scope_info_list,
+ scope_info_length,
+ Handle<Smi>(Smi::FromInt(list[i]->AsSlot()->index())));
scope_info_length++;
}
- SetElement(scope_info_list, scope_info_length,
- Handle<Object>(Heap::null_value()), kNonStrictMode);
+ SetElementNonStrict(scope_info_list,
+ scope_info_length,
+ Handle<Object>(HEAP->null_value()));
scope_info_length++;
outer_scope = outer_scope->outer_scope();
@@ -801,18 +817,17 @@ class FunctionInfoListener {
};
-static FunctionInfoListener* active_function_info_listener = NULL;
-
JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
Handle<String> source) {
+ Isolate* isolate = Isolate::Current();
CompilationZoneScope zone_scope(DELETE_ON_EXIT);
FunctionInfoListener listener;
Handle<Object> original_source = Handle<Object>(script->source());
script->set_source(*source);
- active_function_info_listener = &listener;
- CompileScriptForTracker(script);
- active_function_info_listener = NULL;
+ isolate->set_active_function_info_listener(&listener);
+ CompileScriptForTracker(isolate, script);
+ isolate->set_active_function_info_listener(NULL);
script->set_source(*original_source);
return *(listener.GetResult());
@@ -829,7 +844,7 @@ void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
Handle<String> name_handle(String::cast(info->name()));
info_wrapper.SetProperties(name_handle, info->start_position(),
info->end_position(), info);
- SetElement(array, i, info_wrapper.GetJSArray(), kNonStrictMode);
+ SetElementNonStrict(array, i, info_wrapper.GetJSArray());
}
}
@@ -894,7 +909,7 @@ class ReferenceCollectorVisitor : public ObjectVisitor {
// Finds all references to original and replaces them with substitution.
static void ReplaceCodeObject(Code* original, Code* substitution) {
- ASSERT(!Heap::InNewSpace(substitution));
+ ASSERT(!HEAP->InNewSpace(substitution));
AssertNoAllocation no_allocations_please;
@@ -907,7 +922,7 @@ static void ReplaceCodeObject(Code* original, Code* substitution) {
// so temporary replace the pointers with offset numbers
// in prologue/epilogue.
{
- Heap::IterateStrongRoots(&visitor, VISIT_ALL);
+ HEAP->IterateStrongRoots(&visitor, VISIT_ALL);
}
// Now iterate over all pointers of all objects, including code_target
@@ -937,7 +952,7 @@ static bool IsInlined(JSFunction* function, SharedFunctionInfo* candidate) {
DeoptimizationInputData* data =
DeoptimizationInputData::cast(function->code()->deoptimization_data());
- if (data == Heap::empty_fixed_array()) return false;
+ if (data == HEAP->empty_fixed_array()) return false;
FixedArray* literals = data->LiteralArray();
@@ -989,7 +1004,7 @@ MaybeObject* LiveEdit::ReplaceFunctionCode(
HandleScope scope;
if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
- return Top::ThrowIllegalOperation();
+ return Isolate::Current()->ThrowIllegalOperation();
}
FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
@@ -1009,7 +1024,7 @@ MaybeObject* LiveEdit::ReplaceFunctionCode(
if (shared_info->debug_info()->IsDebugInfo()) {
Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info()));
Handle<Code> new_original_code =
- Factory::CopyCode(compile_info_wrapper.GetFunctionCode());
+ FACTORY->CopyCode(compile_info_wrapper.GetFunctionCode());
debug_info->set_original_code(*new_original_code);
}
@@ -1017,12 +1032,13 @@ MaybeObject* LiveEdit::ReplaceFunctionCode(
shared_info->set_end_position(compile_info_wrapper.GetEndPosition());
shared_info->set_construct_stub(
- Builtins::builtin(Builtins::JSConstructStubGeneric));
+ Isolate::Current()->builtins()->builtin(
+ Builtins::kJSConstructStubGeneric));
DeoptimizeDependentFunctions(*shared_info);
- CompilationCache::Remove(shared_info);
+ Isolate::Current()->compilation_cache()->Remove(shared_info);
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
@@ -1031,16 +1047,16 @@ MaybeObject* LiveEdit::FunctionSourceUpdated(
HandleScope scope;
if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
- return Top::ThrowIllegalOperation();
+ return Isolate::Current()->ThrowIllegalOperation();
}
SharedInfoWrapper shared_info_wrapper(shared_info_array);
Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
DeoptimizeDependentFunctions(*shared_info);
- CompilationCache::Remove(shared_info);
+ Isolate::Current()->compilation_cache()->Remove(shared_info);
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
@@ -1050,7 +1066,7 @@ void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper));
shared_info->set_script(*script_handle);
- CompilationCache::Remove(shared_info);
+ Isolate::Current()->compilation_cache()->Remove(shared_info);
}
@@ -1198,7 +1214,7 @@ static Handle<Code> PatchPositionsInCode(Handle<Code> code,
// Relocation info section now has different size. We cannot simply
// rewrite it inside code object. Instead we have to create a new
// code object.
- Handle<Code> result(Factory::CopyCode(code, buffer));
+ Handle<Code> result(FACTORY->CopyCode(code, buffer));
return result;
}
}
@@ -1208,7 +1224,7 @@ MaybeObject* LiveEdit::PatchFunctionPositions(
Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
- return Top::ThrowIllegalOperation();
+ return Isolate::Current()->ThrowIllegalOperation();
}
SharedInfoWrapper shared_info_wrapper(shared_info_array);
@@ -1239,14 +1255,14 @@ MaybeObject* LiveEdit::PatchFunctionPositions(
}
}
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
static Handle<Script> CreateScriptCopy(Handle<Script> original) {
Handle<String> original_source(String::cast(original->source()));
- Handle<Script> copy = Factory::NewScript(original_source);
+ Handle<Script> copy = FACTORY->NewScript(original_source);
copy->set_name(original->name());
copy->set_line_offset(original->line_offset());
@@ -1271,15 +1287,16 @@ Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
Handle<Script> old_script = CreateScriptCopy(original_script);
old_script->set_name(String::cast(*old_script_name));
old_script_object = old_script;
- Debugger::OnAfterCompile(old_script, Debugger::SEND_WHEN_DEBUGGING);
+ Isolate::Current()->debugger()->OnAfterCompile(
+ old_script, Debugger::SEND_WHEN_DEBUGGING);
} else {
- old_script_object = Handle<Object>(Heap::null_value());
+ old_script_object = Handle<Object>(HEAP->null_value());
}
original_script->set_source(*new_source);
// Drop line ends so that they will be recalculated.
- original_script->set_line_ends(Heap::undefined_value());
+ original_script->set_line_ends(HEAP->undefined_value());
return *old_script_object;
}
@@ -1327,7 +1344,7 @@ static bool CheckActivation(Handle<JSArray> shared_info_array,
SharedFunctionInfo::cast(wrapper->value()));
if (function->shared() == *shared || IsInlined(*function, *shared)) {
- SetElement(result, i, Handle<Smi>(Smi::FromInt(status)), kNonStrictMode);
+ SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status)));
return true;
}
}
@@ -1340,7 +1357,8 @@ static bool CheckActivation(Handle<JSArray> shared_info_array,
static bool FixTryCatchHandler(StackFrame* top_frame,
StackFrame* bottom_frame) {
Address* pointer_address =
- &Memory::Address_at(Top::get_address_from_id(Top::k_handler_address));
+ &Memory::Address_at(Isolate::Current()->get_address_from_id(
+ Isolate::k_handler_address));
while (*pointer_address < top_frame->sp()) {
pointer_address = &Memory::Address_at(*pointer_address);
@@ -1375,19 +1393,22 @@ static const char* DropFrames(Vector<StackFrame*> frames,
ASSERT(bottom_js_frame->is_java_script());
// Check the nature of the top frame.
- if (pre_top_frame->code()->is_inline_cache_stub() &&
- pre_top_frame->code()->ic_state() == DEBUG_BREAK) {
+ Code* pre_top_frame_code = pre_top_frame->LookupCode(Isolate::Current());
+ if (pre_top_frame_code->is_inline_cache_stub() &&
+ pre_top_frame_code->ic_state() == DEBUG_BREAK) {
// OK, we can drop inline cache calls.
*mode = Debug::FRAME_DROPPED_IN_IC_CALL;
- } else if (pre_top_frame->code() == Debug::debug_break_slot()) {
+ } else if (pre_top_frame_code ==
+ Isolate::Current()->debug()->debug_break_slot()) {
// OK, we can drop debug break slot.
*mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
- } else if (pre_top_frame->code() ==
- Builtins::builtin(Builtins::FrameDropper_LiveEdit)) {
+ } else if (pre_top_frame_code ==
+ Isolate::Current()->builtins()->builtin(
+ Builtins::kFrameDropper_LiveEdit)) {
// OK, we can drop our own code.
*mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
- } else if (pre_top_frame->code()->kind() == Code::STUB &&
- pre_top_frame->code()->major_key()) {
+ } else if (pre_top_frame_code->kind() == Code::STUB &&
+ pre_top_frame_code->major_key()) {
// Entry from our unit tests, it's fine, we support this case.
*mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
} else {
@@ -1409,7 +1430,7 @@ static const char* DropFrames(Vector<StackFrame*> frames,
// Make sure FixTryCatchHandler is idempotent.
ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
- Handle<Code> code(Builtins::builtin(Builtins::FrameDropper_LiveEdit));
+ Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
top_frame->set_pc(code->entry());
pre_top_frame->SetCallerFp(bottom_js_frame->fp());
@@ -1436,7 +1457,7 @@ static bool IsDropableFrame(StackFrame* frame) {
// removing all listed function if possible and if do_drop is true.
static const char* DropActivationsInActiveThread(
Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) {
-
+ Debug* debug = Isolate::Current()->debug();
ZoneScope scope(DELETE_ON_EXIT);
Vector<StackFrame*> frames = CreateStackMap();
@@ -1446,7 +1467,7 @@ static const char* DropActivationsInActiveThread(
int frame_index = 0;
for (; frame_index < frames.length(); frame_index++) {
StackFrame* frame = frames[frame_index];
- if (frame->id() == Debug::break_frame_id()) {
+ if (frame->id() == debug->break_frame_id()) {
top_frame_index = frame_index;
break;
}
@@ -1523,7 +1544,7 @@ static const char* DropActivationsInActiveThread(
break;
}
}
- Debug::FramesHaveBeenDropped(new_id, drop_mode,
+ debug->FramesHaveBeenDropped(new_id, drop_mode,
restarter_frame_function_pointer);
// Replace "blocked on active" with "replaced on active" status.
@@ -1532,7 +1553,7 @@ static const char* DropActivationsInActiveThread(
Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
Handle<Object> replaced(
Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK));
- SetElement(result, i, replaced, kNonStrictMode);
+ SetElementNonStrict(result, i, replaced);
}
}
return NULL;
@@ -1568,20 +1589,22 @@ Handle<JSArray> LiveEdit::CheckAndDropActivations(
Handle<JSArray> shared_info_array, bool do_drop) {
int len = Smi::cast(shared_info_array->length())->value();
- Handle<JSArray> result = Factory::NewJSArray(len);
+ Handle<JSArray> result = FACTORY->NewJSArray(len);
// Fill the default values.
for (int i = 0; i < len; i++) {
- SetElement(result, i,
- Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH)),
- kNonStrictMode);
+ SetElementNonStrict(
+ result,
+ i,
+ Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH)));
}
// First check inactive threads. Fail if some functions are blocked there.
InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
result);
- ThreadManager::IterateArchivedThreads(&inactive_threads_checker);
+ Isolate::Current()->thread_manager()->IterateArchivedThreads(
+ &inactive_threads_checker);
if (inactive_threads_checker.HasBlockedFunctions()) {
return result;
}
@@ -1592,42 +1615,44 @@ Handle<JSArray> LiveEdit::CheckAndDropActivations(
if (error_message != NULL) {
// Add error message as an array extra element.
Vector<const char> vector_message(error_message, StrLength(error_message));
- Handle<String> str = Factory::NewStringFromAscii(vector_message);
- SetElement(result, len, str, kNonStrictMode);
+ Handle<String> str = FACTORY->NewStringFromAscii(vector_message);
+ SetElementNonStrict(result, len, str);
}
return result;
}
-LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) {
- if (active_function_info_listener != NULL) {
- active_function_info_listener->FunctionStarted(fun);
+LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
+ FunctionLiteral* fun)
+ : isolate_(isolate) {
+ if (isolate_->active_function_info_listener() != NULL) {
+ isolate_->active_function_info_listener()->FunctionStarted(fun);
}
}
LiveEditFunctionTracker::~LiveEditFunctionTracker() {
- if (active_function_info_listener != NULL) {
- active_function_info_listener->FunctionDone();
+ if (isolate_->active_function_info_listener() != NULL) {
+ isolate_->active_function_info_listener()->FunctionDone();
}
}
void LiveEditFunctionTracker::RecordFunctionInfo(
Handle<SharedFunctionInfo> info, FunctionLiteral* lit) {
- if (active_function_info_listener != NULL) {
- active_function_info_listener->FunctionInfo(info, lit->scope());
+ if (isolate_->active_function_info_listener() != NULL) {
+ isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope());
}
}
void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
- active_function_info_listener->FunctionCode(code);
+ isolate_->active_function_info_listener()->FunctionCode(code);
}
-bool LiveEditFunctionTracker::IsActive() {
- return active_function_info_listener != NULL;
+bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
+ return isolate->active_function_info_listener() != NULL;
}
@@ -1635,7 +1660,8 @@ bool LiveEditFunctionTracker::IsActive() {
// This ifdef-else-endif section provides working or stub implementation of
// LiveEditFunctionTracker.
-LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) {
+LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
+ FunctionLiteral* fun) {
}
diff --git a/src/liveedit.h b/src/liveedit.h
index 5f2c99c3..36c2c760 100644
--- a/src/liveedit.h
+++ b/src/liveedit.h
@@ -65,13 +65,18 @@ namespace internal {
// also collects compiled function codes.
class LiveEditFunctionTracker {
public:
- explicit LiveEditFunctionTracker(FunctionLiteral* fun);
+ explicit LiveEditFunctionTracker(Isolate* isolate, FunctionLiteral* fun);
~LiveEditFunctionTracker();
void RecordFunctionInfo(Handle<SharedFunctionInfo> info,
FunctionLiteral* lit);
void RecordRootFunctionInfo(Handle<Code> code);
- static bool IsActive();
+ static bool IsActive(Isolate* isolate);
+
+ private:
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ Isolate* isolate_;
+#endif
};
#ifdef ENABLE_DEBUGGER_SUPPORT
diff --git a/src/liveobjectlist.h b/src/liveobjectlist.h
index 423f8f0d..23e418d6 100644
--- a/src/liveobjectlist.h
+++ b/src/liveobjectlist.h
@@ -273,28 +273,28 @@ class LiveObjectList {
inline static void ProcessNonLive(HeapObject* obj) {}
inline static void UpdateReferencesForScavengeGC() {}
- inline static MaybeObject* Capture() { return Heap::undefined_value(); }
+ inline static MaybeObject* Capture() { return HEAP->undefined_value(); }
inline static bool Delete(int id) { return false; }
inline static MaybeObject* Dump(int id1,
int id2,
int start_idx,
int dump_limit,
Handle<JSObject> filter_obj) {
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
inline static MaybeObject* Info(int start_idx, int dump_limit) {
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
inline static MaybeObject* Summarize(int id1,
int id2,
Handle<JSObject> filter_obj) {
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
inline static void Reset() {}
- inline static Object* GetObj(int obj_id) { return Heap::undefined_value(); }
+ inline static Object* GetObj(int obj_id) { return HEAP->undefined_value(); }
inline static Object* GetObjId(Handle<String> address) {
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
inline static MaybeObject* GetObjRetainers(int obj_id,
Handle<JSObject> instance_filter,
@@ -302,15 +302,15 @@ class LiveObjectList {
int start,
int count,
Handle<JSObject> filter_obj) {
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
inline static Object* GetPath(int obj_id1,
int obj_id2,
Handle<JSObject> instance_filter) {
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
- inline static Object* PrintObj(int obj_id) { return Heap::undefined_value(); }
+ inline static Object* PrintObj(int obj_id) { return HEAP->undefined_value(); }
};
diff --git a/src/log-utils.cc b/src/log-utils.cc
index 9a498ec0..a854ade0 100644
--- a/src/log-utils.cc
+++ b/src/log-utils.cc
@@ -28,6 +28,7 @@
#include "v8.h"
#include "log-utils.h"
+#include "string-stream.h"
namespace v8 {
namespace internal {
@@ -118,29 +119,117 @@ int LogDynamicBuffer::WriteInternal(const char* data, int data_size) {
return data_size;
}
-
-bool Log::is_stopped_ = false;
-Log::WritePtr Log::Write = NULL;
-FILE* Log::output_handle_ = NULL;
-FILE* Log::output_code_handle_ = NULL;
-LogDynamicBuffer* Log::output_buffer_ = NULL;
// Must be the same message as in Logger::PauseProfiler.
-const char* Log::kDynamicBufferSeal = "profiler,\"pause\"\n";
-Mutex* Log::mutex_ = NULL;
-char* Log::message_buffer_ = NULL;
+const char* const Log::kDynamicBufferSeal = "profiler,\"pause\"\n";
+
+Log::Log(Logger* logger)
+ : write_to_file_(false),
+ is_stopped_(false),
+ output_handle_(NULL),
+ output_code_handle_(NULL),
+ output_buffer_(NULL),
+ mutex_(NULL),
+ message_buffer_(NULL),
+ logger_(logger) {
+}
+
+
+static void AddIsolateIdIfNeeded(StringStream* stream) {
+ Isolate* isolate = Isolate::Current();
+ if (isolate->IsDefaultIsolate()) return;
+ stream->Add("isolate-%p-", isolate);
+}
-void Log::Init() {
+void Log::Initialize() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
mutex_ = OS::CreateMutex();
message_buffer_ = NewArray<char>(kMessageBufferSize);
+
+ // --log-all enables all the log flags.
+ if (FLAG_log_all) {
+ FLAG_log_runtime = true;
+ FLAG_log_api = true;
+ FLAG_log_code = true;
+ FLAG_log_gc = true;
+ FLAG_log_suspect = true;
+ FLAG_log_handles = true;
+ FLAG_log_regexp = true;
+ }
+
+ // --prof implies --log-code.
+ if (FLAG_prof) FLAG_log_code = true;
+
+ // --prof_lazy controls --log-code, implies --noprof_auto.
+ if (FLAG_prof_lazy) {
+ FLAG_log_code = false;
+ FLAG_prof_auto = false;
+ }
+
+ bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api
+ || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
+ || FLAG_log_regexp || FLAG_log_state_changes;
+
+ bool open_log_file = start_logging || FLAG_prof_lazy;
+
+ // If we're logging anything, we need to open the log file.
+ if (open_log_file) {
+ if (strcmp(FLAG_logfile, "-") == 0) {
+ OpenStdout();
+ } else if (strcmp(FLAG_logfile, "*") == 0) {
+ OpenMemoryBuffer();
+ } else {
+ if (strchr(FLAG_logfile, '%') != NULL ||
+ !Isolate::Current()->IsDefaultIsolate()) {
+ // If there's a '%' in the log file name we have to expand
+ // placeholders.
+ HeapStringAllocator allocator;
+ StringStream stream(&allocator);
+ AddIsolateIdIfNeeded(&stream);
+ for (const char* p = FLAG_logfile; *p; p++) {
+ if (*p == '%') {
+ p++;
+ switch (*p) {
+ case '\0':
+ // If there's a % at the end of the string we back up
+ // one character so we can escape the loop properly.
+ p--;
+ break;
+ case 't': {
+ // %t expands to the current time in milliseconds.
+ double time = OS::TimeCurrentMillis();
+ stream.Add("%.0f", FmtElm(time));
+ break;
+ }
+ case '%':
+ // %% expands (contracts really) to %.
+ stream.Put('%');
+ break;
+ default:
+ // All other %'s expand to themselves.
+ stream.Put('%');
+ stream.Put(*p);
+ break;
+ }
+ } else {
+ stream.Put(*p);
+ }
+ }
+ SmartPointer<const char> expanded = stream.ToCString();
+ OpenFile(*expanded);
+ } else {
+ OpenFile(FLAG_logfile);
+ }
+ }
+ }
+#endif
}
void Log::OpenStdout() {
ASSERT(!IsEnabled());
output_handle_ = stdout;
- Write = WriteToFile;
- Init();
+ write_to_file_ = true;
}
@@ -150,6 +239,7 @@ static const char kCodeLogExt[] = ".code";
void Log::OpenFile(const char* name) {
ASSERT(!IsEnabled());
output_handle_ = OS::FOpen(name, OS::LogFileOpenMode);
+ write_to_file_ = true;
if (FLAG_ll_prof) {
// Open a file for logging the contents of code objects so that
// they can be disassembled later.
@@ -160,8 +250,6 @@ void Log::OpenFile(const char* name) {
memcpy(code_name.start() + name_len, kCodeLogExt, sizeof(kCodeLogExt));
output_code_handle_ = OS::FOpen(code_name.start(), OS::LogFileOpenMode);
}
- Write = WriteToFile;
- Init();
}
@@ -170,24 +258,20 @@ void Log::OpenMemoryBuffer() {
output_buffer_ = new LogDynamicBuffer(
kDynamicBufferBlockSize, kMaxDynamicBufferSize,
kDynamicBufferSeal, StrLength(kDynamicBufferSeal));
- Write = WriteToMemory;
- Init();
+ write_to_file_ = false;
}
void Log::Close() {
- if (Write == WriteToFile) {
+ if (write_to_file_) {
if (output_handle_ != NULL) fclose(output_handle_);
output_handle_ = NULL;
if (output_code_handle_ != NULL) fclose(output_code_handle_);
output_code_handle_ = NULL;
- } else if (Write == WriteToMemory) {
+ } else {
delete output_buffer_;
output_buffer_ = NULL;
- } else {
- ASSERT(Write == NULL);
}
- Write = NULL;
DeleteArray(message_buffer_);
message_buffer_ = NULL;
@@ -200,7 +284,7 @@ void Log::Close() {
int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) {
- if (Write != WriteToMemory) return 0;
+ if (write_to_file_) return 0;
ASSERT(output_buffer_ != NULL);
ASSERT(from_pos >= 0);
ASSERT(max_size >= 0);
@@ -220,17 +304,16 @@ int Log::GetLogLines(int from_pos, char* dest_buf, int max_size) {
}
-LogMessageBuilder::WriteFailureHandler
- LogMessageBuilder::write_failure_handler = NULL;
-
-
-LogMessageBuilder::LogMessageBuilder(): sl(Log::mutex_), pos_(0) {
- ASSERT(Log::message_buffer_ != NULL);
+LogMessageBuilder::LogMessageBuilder(Logger* logger)
+ : log_(logger->log_),
+ sl(log_->mutex_),
+ pos_(0) {
+ ASSERT(log_->message_buffer_ != NULL);
}
void LogMessageBuilder::Append(const char* format, ...) {
- Vector<char> buf(Log::message_buffer_ + pos_,
+ Vector<char> buf(log_->message_buffer_ + pos_,
Log::kMessageBufferSize - pos_);
va_list args;
va_start(args, format);
@@ -241,7 +324,7 @@ void LogMessageBuilder::Append(const char* format, ...) {
void LogMessageBuilder::AppendVA(const char* format, va_list args) {
- Vector<char> buf(Log::message_buffer_ + pos_,
+ Vector<char> buf(log_->message_buffer_ + pos_,
Log::kMessageBufferSize - pos_);
int result = v8::internal::OS::VSNPrintF(buf, format, args);
@@ -257,7 +340,7 @@ void LogMessageBuilder::AppendVA(const char* format, va_list args) {
void LogMessageBuilder::Append(const char c) {
if (pos_ < Log::kMessageBufferSize) {
- Log::message_buffer_[pos_++] = c;
+ log_->message_buffer_[pos_++] = c;
}
ASSERT(pos_ <= Log::kMessageBufferSize);
}
@@ -315,7 +398,7 @@ void LogMessageBuilder::AppendStringPart(const char* str, int len) {
ASSERT(len >= 0);
if (len == 0) return;
}
- Vector<char> buf(Log::message_buffer_ + pos_,
+ Vector<char> buf(log_->message_buffer_ + pos_,
Log::kMessageBufferSize - pos_);
OS::StrNCpy(buf, str, len);
pos_ += len;
@@ -325,12 +408,16 @@ void LogMessageBuilder::AppendStringPart(const char* str, int len) {
void LogMessageBuilder::WriteToLogFile() {
ASSERT(pos_ <= Log::kMessageBufferSize);
- const int written = Log::Write(Log::message_buffer_, pos_);
- if (written != pos_ && write_failure_handler != NULL) {
- write_failure_handler();
+ const int written = log_->write_to_file_ ?
+ log_->WriteToFile(log_->message_buffer_, pos_) :
+ log_->WriteToMemory(log_->message_buffer_, pos_);
+ if (written != pos_) {
+ log_->stop();
+ log_->logger_->LogFailure();
}
}
+
#endif // ENABLE_LOGGING_AND_PROFILING
} } // namespace v8::internal
diff --git a/src/log-utils.h b/src/log-utils.h
index 719d3703..255c73c9 100644
--- a/src/log-utils.h
+++ b/src/log-utils.h
@@ -33,6 +33,8 @@ namespace internal {
#ifdef ENABLE_LOGGING_AND_PROFILING
+class Logger;
+
// A memory buffer that increments its size as you write in it. Size
// is incremented with 'block_size' steps, never exceeding 'max_size'.
// During growth, memory contents are never copied. At the end of the
@@ -89,28 +91,23 @@ class LogDynamicBuffer {
// Functions and data for performing output of log messages.
-class Log : public AllStatic {
+class Log {
public:
- // Opens stdout for logging.
- static void OpenStdout();
- // Opens file for logging.
- static void OpenFile(const char* name);
-
- // Opens memory buffer for logging.
- static void OpenMemoryBuffer();
+ // Performs process-wide initialization.
+ void Initialize();
// Disables logging, but preserves acquired resources.
- static void stop() { is_stopped_ = true; }
+ void stop() { is_stopped_ = true; }
- // Frees all resources acquired in Open... functions.
- static void Close();
+ // Frees all resources acquired in Initialize and Open... functions.
+ void Close();
// See description in include/v8.h.
- static int GetLogLines(int from_pos, char* dest_buf, int max_size);
+ int GetLogLines(int from_pos, char* dest_buf, int max_size);
// Returns whether logging is enabled.
- static bool IsEnabled() {
+ bool IsEnabled() {
return !is_stopped_ && (output_handle_ != NULL || output_buffer_ != NULL);
}
@@ -118,16 +115,19 @@ class Log : public AllStatic {
static const int kMessageBufferSize = v8::V8::kMinimumSizeForLogLinesBuffer;
private:
- typedef int (*WritePtr)(const char* msg, int length);
+ explicit Log(Logger* logger);
+
+ // Opens stdout for logging.
+ void OpenStdout();
- // Initialization function called from Open... functions.
- static void Init();
+ // Opens file for logging.
+ void OpenFile(const char* name);
- // Write functions assume that mutex_ is acquired by the caller.
- static WritePtr Write;
+ // Opens memory buffer for logging.
+ void OpenMemoryBuffer();
// Implementation of writing to a log file.
- static int WriteToFile(const char* msg, int length) {
+ int WriteToFile(const char* msg, int length) {
ASSERT(output_handle_ != NULL);
size_t rv = fwrite(msg, 1, length, output_handle_);
ASSERT(static_cast<size_t>(length) == rv);
@@ -137,25 +137,27 @@ class Log : public AllStatic {
}
// Implementation of writing to a memory buffer.
- static int WriteToMemory(const char* msg, int length) {
+ int WriteToMemory(const char* msg, int length) {
ASSERT(output_buffer_ != NULL);
return output_buffer_->Write(msg, length);
}
+ bool write_to_file_;
+
// Whether logging is stopped (e.g. due to insufficient resources).
- static bool is_stopped_;
+ bool is_stopped_;
// When logging is active, either output_handle_ or output_buffer_ is used
// to store a pointer to log destination. If logging was opened via OpenStdout
// or OpenFile, then output_handle_ is used. If logging was opened
// via OpenMemoryBuffer, then output_buffer_ is used.
// mutex_ should be acquired before using output_handle_ or output_buffer_.
- static FILE* output_handle_;
+ FILE* output_handle_;
// Used when low-level profiling is active to save code object contents.
- static FILE* output_code_handle_;
+ FILE* output_code_handle_;
- static LogDynamicBuffer* output_buffer_;
+ LogDynamicBuffer* output_buffer_;
// Size of dynamic buffer block (and dynamic buffer initial size).
static const int kDynamicBufferBlockSize = 65536;
@@ -164,15 +166,17 @@ class Log : public AllStatic {
static const int kMaxDynamicBufferSize = 50 * 1024 * 1024;
// Message to "seal" dynamic buffer with.
- static const char* kDynamicBufferSeal;
+ static const char* const kDynamicBufferSeal;
// mutex_ is a Mutex used for enforcing exclusive
// access to the formatting buffer and the log file or log memory buffer.
- static Mutex* mutex_;
+ Mutex* mutex_;
// Buffer used for formatting log messages. This is a singleton buffer and
// mutex_ should be acquired before using it.
- static char* message_buffer_;
+ char* message_buffer_;
+
+ Logger* logger_;
friend class Logger;
friend class LogMessageBuilder;
@@ -185,7 +189,7 @@ class LogMessageBuilder BASE_EMBEDDED {
public:
// Create a message builder starting from position 0. This acquires the mutex
// in the log as well.
- explicit LogMessageBuilder();
+ explicit LogMessageBuilder(Logger* logger);
~LogMessageBuilder() { }
// Append string data to the log message.
@@ -211,16 +215,9 @@ class LogMessageBuilder BASE_EMBEDDED {
// Write the log message to the log file currently opened.
void WriteToLogFile();
- // A handler that is called when Log::Write fails.
- typedef void (*WriteFailureHandler)();
-
- static void set_write_failure_handler(WriteFailureHandler handler) {
- write_failure_handler = handler;
- }
-
private:
- static WriteFailureHandler write_failure_handler;
+ Log* log_;
ScopedLock sl;
int pos_;
};
diff --git a/src/log.cc b/src/log.cc
index 16aeadb0..6991f3d5 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -52,24 +52,25 @@ namespace internal {
//
class SlidingStateWindow {
public:
- SlidingStateWindow();
+ explicit SlidingStateWindow(Isolate* isolate);
~SlidingStateWindow();
void AddState(StateTag state);
private:
static const int kBufferSize = 256;
+ Counters* counters_;
int current_index_;
bool is_full_;
byte buffer_[kBufferSize];
void IncrementStateCounter(StateTag state) {
- Counters::state_counters[state].Increment();
+ counters_->state_counters(state)->Increment();
}
void DecrementStateCounter(StateTag state) {
- Counters::state_counters[state].Decrement();
+ counters_->state_counters(state)->Decrement();
}
};
@@ -82,7 +83,7 @@ class SlidingStateWindow {
//
class Profiler: public Thread {
public:
- Profiler();
+ explicit Profiler(Isolate* isolate);
void Engage();
void Disengage();
@@ -113,9 +114,9 @@ class Profiler: public Thread {
void Run();
// Pause and Resume TickSample data collection.
- static bool paused() { return paused_; }
- static void pause() { paused_ = true; }
- static void resume() { paused_ = false; }
+ bool paused() const { return paused_; }
+ void pause() { paused_ = true; }
+ void resume() { paused_ = false; }
private:
// Returns the next index in the cyclic buffer.
@@ -137,43 +138,44 @@ class Profiler: public Thread {
bool running_;
// Tells whether we are currently recording tick samples.
- static bool paused_;
+ bool paused_;
};
-bool Profiler::paused_ = false;
-
//
// StackTracer implementation
//
-void StackTracer::Trace(TickSample* sample) {
+void StackTracer::Trace(Isolate* isolate, TickSample* sample) {
+ ASSERT(isolate->IsInitialized());
+
sample->tos = NULL;
sample->frames_count = 0;
// Avoid collecting traces while doing GC.
if (sample->state == GC) return;
- const Address js_entry_sp = Top::js_entry_sp(Top::GetCurrentThread());
+ const Address js_entry_sp =
+ Isolate::js_entry_sp(isolate->thread_local_top());
if (js_entry_sp == 0) {
// Not executing JS now.
return;
}
- // Sample potential return address value for frameless invocation of
- // stubs (we'll figure out later, if this value makes sense).
- sample->tos = Memory::Address_at(sample->sp);
-
- int i = 0;
- const Address callback = Top::external_callback();
- // Surprisingly, PC can point _exactly_ to callback start, with good
- // probability, and this will result in reporting fake nested
- // callback call.
- if (callback != NULL && callback != sample->pc) {
- sample->stack[i++] = callback;
+ const Address callback = isolate->external_callback();
+ if (callback != NULL) {
+ sample->external_callback = callback;
+ sample->has_external_callback = true;
+ } else {
+ // Sample potential return address value for frameless invocation of
+ // stubs (we'll figure out later, if this value makes sense).
+ sample->tos = Memory::Address_at(sample->sp);
+ sample->has_external_callback = false;
}
- SafeStackTraceFrameIterator it(sample->fp, sample->sp,
+ SafeStackTraceFrameIterator it(isolate,
+ sample->fp, sample->sp,
sample->sp, js_entry_sp);
+ int i = 0;
while (!it.done() && i < TickSample::kMaxFramesCount) {
sample->stack[i++] = it.frame()->pc();
it.Advance();
@@ -188,8 +190,8 @@ void StackTracer::Trace(TickSample* sample) {
//
class Ticker: public Sampler {
public:
- explicit Ticker(int interval) :
- Sampler(interval),
+ explicit Ticker(Isolate* isolate, int interval):
+ Sampler(isolate, interval),
window_(NULL),
profiler_(NULL) {}
@@ -225,7 +227,7 @@ class Ticker: public Sampler {
protected:
virtual void DoSampleStack(TickSample* sample) {
- StackTracer::Trace(sample);
+ StackTracer::Trace(isolate(), sample);
}
private:
@@ -237,16 +239,17 @@ class Ticker: public Sampler {
//
// SlidingStateWindow implementation.
//
-SlidingStateWindow::SlidingStateWindow(): current_index_(0), is_full_(false) {
+SlidingStateWindow::SlidingStateWindow(Isolate* isolate)
+ : counters_(isolate->counters()), current_index_(0), is_full_(false) {
for (int i = 0; i < kBufferSize; i++) {
buffer_[i] = static_cast<byte>(OTHER);
}
- Logger::ticker_->SetWindow(this);
+ isolate->logger()->ticker_->SetWindow(this);
}
SlidingStateWindow::~SlidingStateWindow() {
- Logger::ticker_->ClearWindow();
+ LOGGER->ticker_->ClearWindow();
}
@@ -266,14 +269,15 @@ void SlidingStateWindow::AddState(StateTag state) {
//
// Profiler implementation.
//
-Profiler::Profiler()
- : Thread("v8:Profiler"),
+Profiler::Profiler(Isolate* isolate)
+ : Thread(isolate, "v8:Profiler"),
head_(0),
tail_(0),
overflow_(false),
buffer_semaphore_(OS::CreateSemaphore(0)),
engaged_(false),
- running_(false) {
+ running_(false),
+ paused_(false) {
}
@@ -292,9 +296,9 @@ void Profiler::Engage() {
Start();
// Register to get ticks.
- Logger::ticker_->SetProfiler(this);
+ LOGGER->ticker_->SetProfiler(this);
- Logger::ProfilerBeginEvent();
+ LOGGER->ProfilerBeginEvent();
}
@@ -302,7 +306,7 @@ void Profiler::Disengage() {
if (!engaged_) return;
// Stop receiving ticks.
- Logger::ticker_->ClearProfiler();
+ LOGGER->ticker_->ClearProfiler();
// Terminate the worker thread by setting running_ to false,
// inserting a fake element in the queue and then wait for
@@ -314,15 +318,16 @@ void Profiler::Disengage() {
Insert(&sample);
Join();
- LOG(UncheckedStringEvent("profiler", "end"));
+ LOG(ISOLATE, UncheckedStringEvent("profiler", "end"));
}
void Profiler::Run() {
TickSample sample;
bool overflow = Remove(&sample);
+ i::Isolate* isolate = ISOLATE;
while (running_) {
- LOG(TickEvent(&sample, overflow));
+ LOG(isolate, TickEvent(&sample, overflow));
overflow = Remove(&sample);
}
}
@@ -331,23 +336,38 @@ void Profiler::Run() {
//
// Logger class implementation.
//
-Ticker* Logger::ticker_ = NULL;
-Profiler* Logger::profiler_ = NULL;
-SlidingStateWindow* Logger::sliding_state_window_ = NULL;
-int Logger::logging_nesting_ = 0;
-int Logger::cpu_profiler_nesting_ = 0;
-int Logger::heap_profiler_nesting_ = 0;
+
+Logger::Logger()
+ : ticker_(NULL),
+ profiler_(NULL),
+ sliding_state_window_(NULL),
+ log_events_(NULL),
+ logging_nesting_(0),
+ cpu_profiler_nesting_(0),
+ heap_profiler_nesting_(0),
+ log_(new Log(this)),
+ is_initialized_(false),
+ last_address_(NULL),
+ prev_sp_(NULL),
+ prev_function_(NULL),
+ prev_to_(NULL),
+ prev_code_(NULL) {
+}
+
+Logger::~Logger() {
+ delete log_;
+}
#define DECLARE_EVENT(ignore1, name) name,
-const char* kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
+static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
};
#undef DECLARE_EVENT
void Logger::ProfilerBeginEvent() {
- if (!Log::IsEnabled()) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled()) return;
+ LogMessageBuilder msg(this);
msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
msg.WriteToLogFile();
}
@@ -364,8 +384,8 @@ void Logger::StringEvent(const char* name, const char* value) {
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::UncheckedStringEvent(const char* name, const char* value) {
- if (!Log::IsEnabled()) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled()) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,\"%s\"\n", name, value);
msg.WriteToLogFile();
}
@@ -388,8 +408,8 @@ void Logger::IntPtrTEvent(const char* name, intptr_t value) {
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::UncheckedIntEvent(const char* name, int value) {
- if (!Log::IsEnabled()) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled()) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,%d\n", name, value);
msg.WriteToLogFile();
}
@@ -398,8 +418,8 @@ void Logger::UncheckedIntEvent(const char* name, int value) {
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
- if (!Log::IsEnabled()) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled()) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value);
msg.WriteToLogFile();
}
@@ -408,8 +428,8 @@ void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
void Logger::HandleEvent(const char* name, Object** location) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_handles) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_handles) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,0x%" V8PRIxPTR "\n", name, location);
msg.WriteToLogFile();
#endif
@@ -421,8 +441,8 @@ void Logger::HandleEvent(const char* name, Object** location) {
// caller's responsibility to ensure that log is enabled and that
// FLAG_log_api is true.
void Logger::ApiEvent(const char* format, ...) {
- ASSERT(Log::IsEnabled() && FLAG_log_api);
- LogMessageBuilder msg;
+ ASSERT(log_->IsEnabled() && FLAG_log_api);
+ LogMessageBuilder msg(this);
va_list ap;
va_start(ap, format);
msg.AppendVA(format, ap);
@@ -434,7 +454,7 @@ void Logger::ApiEvent(const char* format, ...) {
void Logger::ApiNamedSecurityCheck(Object* key) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_api) return;
+ if (!log_->IsEnabled() || !FLAG_log_api) return;
if (key->IsString()) {
SmartPointer<char> str =
String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
@@ -452,8 +472,8 @@ void Logger::SharedLibraryEvent(const char* library_path,
uintptr_t start,
uintptr_t end) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_prof) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_prof) return;
+ LogMessageBuilder msg(this);
msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
library_path,
start,
@@ -467,8 +487,8 @@ void Logger::SharedLibraryEvent(const wchar_t* library_path,
uintptr_t start,
uintptr_t end) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_prof) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_prof) return;
+ LogMessageBuilder msg(this);
msg.Append("shared-library,\"%ls\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
library_path,
start,
@@ -482,7 +502,7 @@ void Logger::SharedLibraryEvent(const wchar_t* library_path,
void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
// Prints "/" + re.source + "/" +
// (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
- LogMessageBuilder msg;
+ LogMessageBuilder msg(this);
Handle<Object> source = GetProperty(regexp, "source");
if (!source->IsString()) {
@@ -524,8 +544,8 @@ void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_regexp) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_regexp) return;
+ LogMessageBuilder msg(this);
msg.Append("regexp-compile,");
LogRegExpSource(regexp);
msg.Append(in_cache ? ",hit\n" : ",miss\n");
@@ -536,9 +556,9 @@ void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
void Logger::LogRuntime(Vector<const char> format, JSArray* args) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_runtime) return;
+ if (!log_->IsEnabled() || !FLAG_log_runtime) return;
HandleScope scope;
- LogMessageBuilder msg;
+ LogMessageBuilder msg(this);
for (int i = 0; i < format.length(); i++) {
char c = format[i];
if (c == '%' && i <= format.length() - 2) {
@@ -582,7 +602,7 @@ void Logger::LogRuntime(Vector<const char> format, JSArray* args) {
void Logger::ApiIndexedSecurityCheck(uint32_t index) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_api) return;
+ if (!log_->IsEnabled() || !FLAG_log_api) return;
ApiEvent("api,check-security,%u\n", index);
#endif
}
@@ -593,13 +613,13 @@ void Logger::ApiNamedPropertyAccess(const char* tag,
Object* name) {
#ifdef ENABLE_LOGGING_AND_PROFILING
ASSERT(name->IsString());
- if (!Log::IsEnabled() || !FLAG_log_api) return;
+ if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = holder->class_name();
SmartPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
SmartPointer<char> property_name =
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- Logger::ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
+ ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
#endif
}
@@ -607,37 +627,37 @@ void Logger::ApiIndexedPropertyAccess(const char* tag,
JSObject* holder,
uint32_t index) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_api) return;
+ if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = holder->class_name();
SmartPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- Logger::ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
+ ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
#endif
}
void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_api) return;
+ if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = object->class_name();
SmartPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- Logger::ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
+ ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
#endif
}
void Logger::ApiEntryCall(const char* name) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_api) return;
- Logger::ApiEvent("api,%s\n", name);
+ if (!log_->IsEnabled() || !FLAG_log_api) return;
+ ApiEvent("api,%s\n", name);
#endif
}
void Logger::NewEvent(const char* name, void* object, size_t size) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log) return;
+ LogMessageBuilder msg(this);
msg.Append("new,%s,0x%" V8PRIxPTR ",%u\n", name, object,
static_cast<unsigned int>(size));
msg.WriteToLogFile();
@@ -647,19 +667,28 @@ void Logger::NewEvent(const char* name, void* object, size_t size) {
void Logger::DeleteEvent(const char* name, void* object) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log) return;
+ LogMessageBuilder msg(this);
msg.Append("delete,%s,0x%" V8PRIxPTR "\n", name, object);
msg.WriteToLogFile();
#endif
}
+void Logger::NewEventStatic(const char* name, void* object, size_t size) {
+ LOGGER->NewEvent(name, object, size);
+}
+
+
+void Logger::DeleteEventStatic(const char* name, void* object) {
+ LOGGER->DeleteEvent(name, object);
+}
+
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::CallbackEventInternal(const char* prefix, const char* name,
Address entry_point) {
- if (!Log::IsEnabled() || !FLAG_log_code) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[CALLBACK_TAG]);
@@ -673,7 +702,7 @@ void Logger::CallbackEventInternal(const char* prefix, const char* name,
void Logger::CallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code) return;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("", *str, entry_point);
@@ -683,7 +712,7 @@ void Logger::CallbackEvent(String* name, Address entry_point) {
void Logger::GetterCallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code) return;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("get ", *str, entry_point);
@@ -693,7 +722,7 @@ void Logger::GetterCallbackEvent(String* name, Address entry_point) {
void Logger::SetterCallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code) return;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("set ", *str, entry_point);
@@ -705,8 +734,8 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
Code* code,
const char* comment) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[tag]);
@@ -758,9 +787,12 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
SharedFunctionInfo* shared,
String* name) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code) return;
- if (code == Builtins::builtin(Builtins::LazyCompile)) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
+ if (code == Isolate::Current()->builtins()->builtin(
+ Builtins::kLazyCompile))
+ return;
+
+ LogMessageBuilder msg(this);
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("%s,%s,",
@@ -785,8 +817,8 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
SharedFunctionInfo* shared,
String* source, int line) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
+ LogMessageBuilder msg(this);
SmartPointer<char> name =
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
SmartPointer<char> sourcestr =
@@ -811,8 +843,8 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[tag]);
@@ -827,8 +859,8 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) {
void Logger::CodeMovingGCEvent() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
+ LogMessageBuilder msg(this);
msg.Append("%s\n", kLogEventsNames[CODE_MOVING_GC]);
msg.WriteToLogFile();
OS::SignalCodeMovingGC();
@@ -838,8 +870,8 @@ void Logger::CodeMovingGCEvent() {
void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[REG_EXP_TAG]);
@@ -870,8 +902,8 @@ void Logger::CodeDeleteEvent(Address from) {
void Logger::SnapshotPositionEvent(Address addr, int pos) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_snapshot_positions) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_snapshot_positions) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
msg.AppendAddress(addr);
msg.Append(",%d", pos);
@@ -881,9 +913,9 @@ void Logger::SnapshotPositionEvent(Address addr, int pos) {
}
-void Logger::SFIMoveEvent(Address from, Address to) {
+void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- MoveEventInternal(SFI_MOVE_EVENT, from, to);
+ MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
#endif
}
@@ -892,8 +924,8 @@ void Logger::SFIMoveEvent(Address from, Address to) {
void Logger::MoveEventInternal(LogEventsAndTags event,
Address from,
Address to) {
- if (!Log::IsEnabled() || !FLAG_log_code) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,", kLogEventsNames[event]);
msg.AppendAddress(from);
msg.Append(',');
@@ -906,8 +938,8 @@ void Logger::MoveEventInternal(LogEventsAndTags event,
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::DeleteEventInternal(LogEventsAndTags event, Address from) {
- if (!Log::IsEnabled() || !FLAG_log_code) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_code) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,", kLogEventsNames[event]);
msg.AppendAddress(from);
msg.Append('\n');
@@ -918,8 +950,8 @@ void Logger::DeleteEventInternal(LogEventsAndTags event, Address from) {
void Logger::ResourceEvent(const char* name, const char* tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,%s,", name, tag);
uint32_t sec, usec;
@@ -936,11 +968,11 @@ void Logger::ResourceEvent(const char* name, const char* tag) {
void Logger::SuspectReadEvent(String* name, Object* obj) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_suspect) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_suspect) return;
+ LogMessageBuilder msg(this);
String* class_name = obj->IsJSObject()
? JSObject::cast(obj)->class_name()
- : Heap::empty_string();
+ : HEAP->empty_string();
msg.Append("suspect-read,");
msg.Append(class_name);
msg.Append(',');
@@ -955,8 +987,8 @@ void Logger::SuspectReadEvent(String* name, Object* obj) {
void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_gc) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_gc) return;
+ LogMessageBuilder msg(this);
// Using non-relative system time in order to be able to synchronize with
// external memory profiling events (e.g. DOM memory size).
msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
@@ -969,8 +1001,8 @@ void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
void Logger::HeapSampleStats(const char* space, const char* kind,
intptr_t capacity, intptr_t used) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_gc) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_gc) return;
+ LogMessageBuilder msg(this);
msg.Append("heap-sample-stats,\"%s\",\"%s\","
"%" V8_PTR_PREFIX "d,%" V8_PTR_PREFIX "d\n",
space, kind, capacity, used);
@@ -981,8 +1013,8 @@ void Logger::HeapSampleStats(const char* space, const char* kind,
void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_gc) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_gc) return;
+ LogMessageBuilder msg(this);
msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind);
msg.WriteToLogFile();
#endif
@@ -991,8 +1023,8 @@ void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_gc) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_gc) return;
+ LogMessageBuilder msg(this);
msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes);
msg.WriteToLogFile();
#endif
@@ -1002,32 +1034,32 @@ void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
void Logger::HeapSampleJSConstructorEvent(const char* constructor,
int number, int bytes) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_gc) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_gc) return;
+ LogMessageBuilder msg(this);
msg.Append("heap-js-cons-item,%s,%d,%d\n", constructor, number, bytes);
msg.WriteToLogFile();
#endif
}
+// Event starts with comma, so we don't have it in the format string.
+static const char kEventText[] = "heap-js-ret-item,%s";
+// We take placeholder strings into account, but it's OK to be conservative.
+static const int kEventTextLen = sizeof(kEventText)/sizeof(kEventText[0]);
void Logger::HeapSampleJSRetainersEvent(
const char* constructor, const char* event) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_gc) return;
- // Event starts with comma, so we don't have it in the format string.
- static const char* event_text = "heap-js-ret-item,%s";
- // We take placeholder strings into account, but it's OK to be conservative.
- static const int event_text_len = StrLength(event_text);
+ if (!log_->IsEnabled() || !FLAG_log_gc) return;
const int cons_len = StrLength(constructor);
const int event_len = StrLength(event);
int pos = 0;
// Retainer lists can be long. We may need to split them into multiple events.
do {
- LogMessageBuilder msg;
- msg.Append(event_text, constructor);
+ LogMessageBuilder msg(this);
+ msg.Append(kEventText, constructor);
int to_write = event_len - pos;
- if (to_write > Log::kMessageBufferSize - (cons_len + event_text_len)) {
- int cut_pos = pos + Log::kMessageBufferSize - (cons_len + event_text_len);
+ if (to_write > Log::kMessageBufferSize - (cons_len + kEventTextLen)) {
+ int cut_pos = pos + Log::kMessageBufferSize - (cons_len + kEventTextLen);
ASSERT(cut_pos < event_len);
while (cut_pos > pos && event[cut_pos] != ',') --cut_pos;
if (event[cut_pos] != ',') {
@@ -1053,8 +1085,8 @@ void Logger::HeapSampleJSRetainersEvent(
void Logger::HeapSampleJSProducerEvent(const char* constructor,
Address* stack) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_gc) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log_gc) return;
+ LogMessageBuilder msg(this);
msg.Append("heap-js-prod-item,%s", constructor);
while (*stack != NULL) {
msg.Append(",0x%" V8PRIxPTR, *stack++);
@@ -1067,8 +1099,8 @@ void Logger::HeapSampleJSProducerEvent(const char* constructor,
void Logger::DebugTag(const char* call_site_tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_log) return;
+ LogMessageBuilder msg(this);
msg.Append("debug-tag,%s\n", call_site_tag);
msg.WriteToLogFile();
#endif
@@ -1077,13 +1109,13 @@ void Logger::DebugTag(const char* call_site_tag) {
void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log) return;
+ if (!log_->IsEnabled() || !FLAG_log) return;
StringBuilder s(parameter.length() + 1);
for (int i = 0; i < parameter.length(); ++i) {
s.AddCharacter(static_cast<char>(parameter[i]));
}
char* parameter_string = s.Finalize();
- LogMessageBuilder msg;
+ LogMessageBuilder msg(this);
msg.Append("debug-queue-event,%s,%15.3f,%s\n",
event_type,
OS::TimeCurrentMillis(),
@@ -1096,14 +1128,19 @@ void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::TickEvent(TickSample* sample, bool overflow) {
- if (!Log::IsEnabled() || !FLAG_prof) return;
- LogMessageBuilder msg;
+ if (!log_->IsEnabled() || !FLAG_prof) return;
+ LogMessageBuilder msg(this);
msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
msg.AppendAddress(sample->pc);
msg.Append(',');
msg.AppendAddress(sample->sp);
- msg.Append(',');
- msg.AppendAddress(sample->tos);
+ if (sample->has_external_callback) {
+ msg.Append(",1,");
+ msg.AppendAddress(sample->external_callback);
+ } else {
+ msg.Append(",0,");
+ msg.AppendAddress(sample->tos);
+ }
msg.Append(",%d", static_cast<int>(sample->state));
if (overflow) {
msg.Append(",overflow");
@@ -1130,7 +1167,7 @@ int Logger::GetActiveProfilerModules() {
void Logger::PauseProfiler(int flags, int tag) {
- if (!Log::IsEnabled()) return;
+ if (!log_->IsEnabled()) return;
if (profiler_ != NULL && (flags & PROFILER_MODULE_CPU)) {
// It is OK to have negative nesting.
if (--cpu_profiler_nesting_ == 0) {
@@ -1141,7 +1178,7 @@ void Logger::PauseProfiler(int flags, int tag) {
}
FLAG_log_code = false;
// Must be the same message as Log::kDynamicBufferSeal.
- LOG(UncheckedStringEvent("profiler", "pause"));
+ LOG(ISOLATE, UncheckedStringEvent("profiler", "pause"));
}
--logging_nesting_;
}
@@ -1160,7 +1197,7 @@ void Logger::PauseProfiler(int flags, int tag) {
void Logger::ResumeProfiler(int flags, int tag) {
- if (!Log::IsEnabled()) return;
+ if (!log_->IsEnabled()) return;
if (tag != 0) {
UncheckedIntEvent("open-tag", tag);
}
@@ -1169,7 +1206,7 @@ void Logger::ResumeProfiler(int flags, int tag) {
++logging_nesting_;
if (FLAG_prof_lazy) {
profiler_->Engage();
- LOG(UncheckedStringEvent("profiler", "resume"));
+ LOG(ISOLATE, UncheckedStringEvent("profiler", "resume"));
FLAG_log_code = true;
LogCompiledFunctions();
LogAccessorCallbacks();
@@ -1192,8 +1229,7 @@ void Logger::ResumeProfiler(int flags, int tag) {
// This function can be called when Log's mutex is acquired,
// either from main or Profiler's thread.
-void Logger::StopLoggingAndProfiling() {
- Log::stop();
+void Logger::LogFailure() {
PauseProfiler(PROFILER_MODULE_CPU, 0);
}
@@ -1204,7 +1240,7 @@ bool Logger::IsProfilerSamplerActive() {
int Logger::GetLogLines(int from_pos, char* dest_buf, int max_size) {
- return Log::GetLogLines(from_pos, dest_buf, max_size);
+ return log_->GetLogLines(from_pos, dest_buf, max_size);
}
@@ -1297,6 +1333,10 @@ void Logger::LogCodeObject(Object* object) {
description = "A keyed load IC from the snapshot";
tag = Logger::KEYED_LOAD_IC_TAG;
break;
+ case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC:
+ description = "A keyed external array load IC from the snapshot";
+ tag = Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG;
+ break;
case Code::LOAD_IC:
description = "A load IC from the snapshot";
tag = Logger::LOAD_IC_TAG;
@@ -1309,6 +1349,10 @@ void Logger::LogCodeObject(Object* object) {
description = "A keyed store IC from the snapshot";
tag = Logger::KEYED_STORE_IC_TAG;
break;
+ case Code::KEYED_EXTERNAL_ARRAY_STORE_IC:
+ description = "A keyed external array store IC from the snapshot";
+ tag = Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG;
+ break;
case Code::CALL_IC:
description = "A call IC from the snapshot";
tag = Logger::CALL_IC_TAG;
@@ -1318,14 +1362,14 @@ void Logger::LogCodeObject(Object* object) {
tag = Logger::KEYED_CALL_IC_TAG;
break;
}
- PROFILE(CodeCreateEvent(tag, code_object, description));
+ PROFILE(ISOLATE, CodeCreateEvent(tag, code_object, description));
}
}
void Logger::LogCodeInfo() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
+ if (!log_->IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
#if V8_TARGET_ARCH_IA32
const char arch[] = "ia32";
#elif V8_TARGET_ARCH_X64
@@ -1335,7 +1379,7 @@ void Logger::LogCodeInfo() {
#else
const char arch[] = "unknown";
#endif
- LogMessageBuilder msg;
+ LogMessageBuilder msg(this);
msg.Append("code-info,%s,%d\n", arch, Code::kHeaderSize);
msg.WriteToLogFile();
#endif // ENABLE_LOGGING_AND_PROFILING
@@ -1343,10 +1387,10 @@ void Logger::LogCodeInfo() {
void Logger::LowLevelCodeCreateEvent(Code* code, LogMessageBuilder* msg) {
- if (!FLAG_ll_prof || Log::output_code_handle_ == NULL) return;
- int pos = static_cast<int>(ftell(Log::output_code_handle_));
+ if (!FLAG_ll_prof || log_->output_code_handle_ == NULL) return;
+ int pos = static_cast<int>(ftell(log_->output_code_handle_));
size_t rv = fwrite(code->instruction_start(), 1, code->instruction_size(),
- Log::output_code_handle_);
+ log_->output_code_handle_);
ASSERT(static_cast<size_t>(code->instruction_size()) == rv);
USE(rv);
msg->Append(",%d", pos);
@@ -1372,7 +1416,9 @@ void Logger::LogCompiledFunctions() {
// During iteration, there can be heap allocation due to
// GetScriptLineNumber call.
for (int i = 0; i < compiled_funcs_count; ++i) {
- if (*code_objects[i] == Builtins::builtin(Builtins::LazyCompile)) continue;
+ if (*code_objects[i] == Isolate::Current()->builtins()->builtin(
+ Builtins::kLazyCompile))
+ continue;
Handle<SharedFunctionInfo> shared = sfis[i];
Handle<String> func_name(shared->DebugName());
if (shared->script()->IsScript()) {
@@ -1381,20 +1427,23 @@ void Logger::LogCompiledFunctions() {
Handle<String> script_name(String::cast(script->name()));
int line_num = GetScriptLineNumber(script, shared->start_position());
if (line_num > 0) {
- PROFILE(CodeCreateEvent(
- Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code_objects[i], *shared,
- *script_name, line_num + 1));
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+ *code_objects[i], *shared,
+ *script_name, line_num + 1));
} else {
// Can't distinguish eval and script here, so always use Script.
- PROFILE(CodeCreateEvent(
- Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
- *code_objects[i], *shared, *script_name));
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+ *code_objects[i], *shared, *script_name));
}
} else {
- PROFILE(CodeCreateEvent(
- Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code_objects[i], *shared, *func_name));
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+ *code_objects[i], *shared, *func_name));
}
} else if (shared->IsApiFunction()) {
// API function.
@@ -1404,11 +1453,13 @@ void Logger::LogCompiledFunctions() {
CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
Object* callback_obj = call_data->callback();
Address entry_point = v8::ToCData<Address>(callback_obj);
- PROFILE(CallbackEvent(*func_name, entry_point));
+ PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
}
} else {
- PROFILE(CodeCreateEvent(
- Logger::LAZY_COMPILE_TAG, *code_objects[i], *shared, *func_name));
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::LAZY_COMPILE_TAG, *code_objects[i],
+ *shared, *func_name));
}
}
}
@@ -1417,6 +1468,7 @@ void Logger::LogCompiledFunctions() {
void Logger::LogAccessorCallbacks() {
AssertNoAllocation no_alloc;
HeapIterator iterator;
+ i::Isolate* isolate = ISOLATE;
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
if (!obj->IsAccessorInfo()) continue;
AccessorInfo* ai = AccessorInfo::cast(obj);
@@ -1424,11 +1476,11 @@ void Logger::LogAccessorCallbacks() {
String* name = String::cast(ai->name());
Address getter_entry = v8::ToCData<Address>(ai->getter());
if (getter_entry != 0) {
- PROFILE(GetterCallbackEvent(name, getter_entry));
+ PROFILE(isolate, GetterCallbackEvent(name, getter_entry));
}
Address setter_entry = v8::ToCData<Address>(ai->setter());
if (setter_entry != 0) {
- PROFILE(SetterCallbackEvent(name, setter_entry));
+ PROFILE(isolate, SetterCallbackEvent(name, setter_entry));
}
}
}
@@ -1438,19 +1490,9 @@ void Logger::LogAccessorCallbacks() {
bool Logger::Setup() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- // --log-all enables all the log flags.
- if (FLAG_log_all) {
- FLAG_log_runtime = true;
- FLAG_log_api = true;
- FLAG_log_code = true;
- FLAG_log_gc = true;
- FLAG_log_suspect = true;
- FLAG_log_handles = true;
- FLAG_log_regexp = true;
- }
-
- // --prof implies --log-code.
- if (FLAG_prof) FLAG_log_code = true;
+ // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
+ if (is_initialized_) return true;
+ is_initialized_ = true;
// --ll-prof implies --log-code and --log-snapshot-positions.
if (FLAG_ll_prof) {
@@ -1464,73 +1506,31 @@ bool Logger::Setup() {
FLAG_prof_auto = false;
}
- bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api
- || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
- || FLAG_log_regexp || FLAG_log_state_changes;
-
- bool open_log_file = start_logging || FLAG_prof_lazy;
-
- // If we're logging anything, we need to open the log file.
- if (open_log_file) {
- if (strcmp(FLAG_logfile, "-") == 0) {
- Log::OpenStdout();
- } else if (strcmp(FLAG_logfile, "*") == 0) {
- Log::OpenMemoryBuffer();
- } else if (strchr(FLAG_logfile, '%') != NULL) {
- // If there's a '%' in the log file name we have to expand
- // placeholders.
- HeapStringAllocator allocator;
- StringStream stream(&allocator);
- for (const char* p = FLAG_logfile; *p; p++) {
- if (*p == '%') {
- p++;
- switch (*p) {
- case '\0':
- // If there's a % at the end of the string we back up
- // one character so we can escape the loop properly.
- p--;
- break;
- case 't': {
- // %t expands to the current time in milliseconds.
- double time = OS::TimeCurrentMillis();
- stream.Add("%.0f", FmtElm(time));
- break;
- }
- case '%':
- // %% expands (contracts really) to %.
- stream.Put('%');
- break;
- default:
- // All other %'s expand to themselves.
- stream.Put('%');
- stream.Put(*p);
- break;
- }
- } else {
- stream.Put(*p);
- }
- }
- SmartPointer<const char> expanded = stream.ToCString();
- Log::OpenFile(*expanded);
- } else {
- Log::OpenFile(FLAG_logfile);
- }
- }
+ // TODO(isolates): this assert introduces cyclic dependency (logger
+ // -> thread local top -> heap -> logger).
+ // ASSERT(VMState::is_outermost_external());
+
+ log_->Initialize();
if (FLAG_ll_prof) LogCodeInfo();
- ticker_ = new Ticker(kSamplingIntervalMs);
+ ticker_ = new Ticker(Isolate::Current(), kSamplingIntervalMs);
+ Isolate* isolate = Isolate::Current();
if (FLAG_sliding_state_window && sliding_state_window_ == NULL) {
- sliding_state_window_ = new SlidingStateWindow();
+ sliding_state_window_ = new SlidingStateWindow(isolate);
}
+ bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api
+ || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
+ || FLAG_log_regexp || FLAG_log_state_changes;
+
if (start_logging) {
logging_nesting_ = 1;
}
if (FLAG_prof) {
- profiler_ = new Profiler();
+ profiler_ = new Profiler(isolate);
if (!FLAG_prof_auto) {
profiler_->pause();
} else {
@@ -1541,7 +1541,6 @@ bool Logger::Setup() {
}
}
- LogMessageBuilder::set_write_failure_handler(StopLoggingAndProfiling);
return true;
#else
@@ -1550,6 +1549,11 @@ bool Logger::Setup() {
}
+Sampler* Logger::sampler() {
+ return ticker_;
+}
+
+
void Logger::EnsureTickerStarted() {
#ifdef ENABLE_LOGGING_AND_PROFILING
ASSERT(ticker_ != NULL);
@@ -1567,7 +1571,8 @@ void Logger::EnsureTickerStopped() {
void Logger::TearDown() {
#ifdef ENABLE_LOGGING_AND_PROFILING
- LogMessageBuilder::set_write_failure_handler(NULL);
+ if (!is_initialized_) return;
+ is_initialized_ = false;
// Stop the profiler before closing the file.
if (profiler_ != NULL) {
@@ -1582,7 +1587,7 @@ void Logger::TearDown() {
delete ticker_;
ticker_ = NULL;
- Log::Close();
+ log_->Close();
#endif
}
@@ -1600,9 +1605,61 @@ void Logger::EnableSlidingStateWindow() {
// Otherwise, if the sliding state window computation has not been
// started we do it now.
if (sliding_state_window_ == NULL) {
- sliding_state_window_ = new SlidingStateWindow();
+ sliding_state_window_ = new SlidingStateWindow(Isolate::Current());
}
#endif
}
+
+Mutex* SamplerRegistry::mutex_ = OS::CreateMutex();
+List<Sampler*>* SamplerRegistry::active_samplers_ = NULL;
+
+
+bool SamplerRegistry::IterateActiveSamplers(VisitSampler func, void* param) {
+ ScopedLock lock(mutex_);
+ for (int i = 0;
+ ActiveSamplersExist() && i < active_samplers_->length();
+ ++i) {
+ func(active_samplers_->at(i), param);
+ }
+ return ActiveSamplersExist();
+}
+
+
+static void ComputeCpuProfiling(Sampler* sampler, void* flag_ptr) {
+ bool* flag = reinterpret_cast<bool*>(flag_ptr);
+ *flag |= sampler->IsProfiling();
+}
+
+
+SamplerRegistry::State SamplerRegistry::GetState() {
+ bool flag = false;
+ if (!IterateActiveSamplers(&ComputeCpuProfiling, &flag)) {
+ return HAS_NO_SAMPLERS;
+ }
+ return flag ? HAS_CPU_PROFILING_SAMPLERS : HAS_SAMPLERS;
+}
+
+
+void SamplerRegistry::AddActiveSampler(Sampler* sampler) {
+ ASSERT(sampler->IsActive());
+ ScopedLock lock(mutex_);
+ if (active_samplers_ == NULL) {
+ active_samplers_ = new List<Sampler*>;
+ } else {
+ ASSERT(!active_samplers_->Contains(sampler));
+ }
+ active_samplers_->Add(sampler);
+}
+
+
+void SamplerRegistry::RemoveActiveSampler(Sampler* sampler) {
+ ASSERT(sampler->IsActive());
+ ScopedLock lock(mutex_);
+ ASSERT(active_samplers_ != NULL);
+ bool removed = active_samplers_->RemoveElement(sampler);
+ ASSERT(removed);
+ USE(removed);
+}
+
} } // namespace v8::internal
diff --git a/src/log.h b/src/log.h
index a808cd1d..4fb0e230 100644
--- a/src/log.h
+++ b/src/log.h
@@ -77,13 +77,15 @@ class LogMessageBuilder;
#undef LOG
#ifdef ENABLE_LOGGING_AND_PROFILING
-#define LOG(Call) \
- do { \
- if (v8::internal::Logger::is_logging()) \
- v8::internal::Logger::Call; \
+#define LOG(isolate, Call) \
+ do { \
+ v8::internal::Logger* logger = \
+ (isolate)->logger(); \
+ if (logger->is_logging()) \
+ logger->Call; \
} while (false)
#else
-#define LOG(Call) ((void) 0)
+#define LOG(isolate, Call) ((void) 0)
#endif
#define LOG_EVENTS_AND_TAGS_LIST(V) \
@@ -91,7 +93,7 @@ class LogMessageBuilder;
V(CODE_MOVE_EVENT, "code-move") \
V(CODE_DELETE_EVENT, "code-delete") \
V(CODE_MOVING_GC, "code-moving-gc") \
- V(SFI_MOVE_EVENT, "sfi-move") \
+ V(SHARED_FUNC_MOVE_EVENT, "sfi-move") \
V(SNAPSHOT_POSITION_EVENT, "snapshot-pos") \
V(TICK_EVENT, "tick") \
V(REPEAT_META_EVENT, "repeat") \
@@ -117,7 +119,9 @@ class LogMessageBuilder;
V(EVAL_TAG, "Eval") \
V(FUNCTION_TAG, "Function") \
V(KEYED_LOAD_IC_TAG, "KeyedLoadIC") \
+ V(KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG, "KeyedExternalArrayLoadIC") \
V(KEYED_STORE_IC_TAG, "KeyedStoreIC") \
+ V(KEYED_EXTERNAL_ARRAY_STORE_IC_TAG, "KeyedExternalArrayStoreIC")\
V(LAZY_COMPILE_TAG, "LazyCompile") \
V(LOAD_IC_TAG, "LoadIC") \
V(REG_EXP_TAG, "RegExp") \
@@ -131,6 +135,9 @@ class LogMessageBuilder;
// original tags when writing to the log.
+class Sampler;
+
+
class Logger {
public:
#define DECLARE_ENUM(enum_item, ignore) enum_item,
@@ -141,142 +148,147 @@ class Logger {
#undef DECLARE_ENUM
// Acquires resources for logging if the right flags are set.
- static bool Setup();
+ bool Setup();
- static void EnsureTickerStarted();
- static void EnsureTickerStopped();
+ void EnsureTickerStarted();
+ void EnsureTickerStopped();
+
+ Sampler* sampler();
// Frees resources acquired in Setup.
- static void TearDown();
+ void TearDown();
// Enable the computation of a sliding window of states.
- static void EnableSlidingStateWindow();
+ void EnableSlidingStateWindow();
// Emits an event with a string value -> (name, value).
- static void StringEvent(const char* name, const char* value);
+ void StringEvent(const char* name, const char* value);
// Emits an event with an int value -> (name, value).
- static void IntEvent(const char* name, int value);
- static void IntPtrTEvent(const char* name, intptr_t value);
+ void IntEvent(const char* name, int value);
+ void IntPtrTEvent(const char* name, intptr_t value);
// Emits an event with an handle value -> (name, location).
- static void HandleEvent(const char* name, Object** location);
+ void HandleEvent(const char* name, Object** location);
// Emits memory management events for C allocated structures.
- static void NewEvent(const char* name, void* object, size_t size);
- static void DeleteEvent(const char* name, void* object);
+ void NewEvent(const char* name, void* object, size_t size);
+ void DeleteEvent(const char* name, void* object);
+
+ // Static versions of the above, operate on current isolate's logger.
+ // Used in TRACK_MEMORY(TypeName) defined in globals.h
+ static void NewEventStatic(const char* name, void* object, size_t size);
+ static void DeleteEventStatic(const char* name, void* object);
// Emits an event with a tag, and some resource usage information.
// -> (name, tag, <rusage information>).
// Currently, the resource usage information is a process time stamp
// and a real time timestamp.
- static void ResourceEvent(const char* name, const char* tag);
+ void ResourceEvent(const char* name, const char* tag);
// Emits an event that an undefined property was read from an
// object.
- static void SuspectReadEvent(String* name, Object* obj);
+ void SuspectReadEvent(String* name, Object* obj);
// Emits an event when a message is put on or read from a debugging queue.
// DebugTag lets us put a call-site specific label on the event.
- static void DebugTag(const char* call_site_tag);
- static void DebugEvent(const char* event_type, Vector<uint16_t> parameter);
+ void DebugTag(const char* call_site_tag);
+ void DebugEvent(const char* event_type, Vector<uint16_t> parameter);
// ==== Events logged by --log-api. ====
- static void ApiNamedSecurityCheck(Object* key);
- static void ApiIndexedSecurityCheck(uint32_t index);
- static void ApiNamedPropertyAccess(const char* tag,
- JSObject* holder,
- Object* name);
- static void ApiIndexedPropertyAccess(const char* tag,
- JSObject* holder,
- uint32_t index);
- static void ApiObjectAccess(const char* tag, JSObject* obj);
- static void ApiEntryCall(const char* name);
+ void ApiNamedSecurityCheck(Object* key);
+ void ApiIndexedSecurityCheck(uint32_t index);
+ void ApiNamedPropertyAccess(const char* tag, JSObject* holder, Object* name);
+ void ApiIndexedPropertyAccess(const char* tag,
+ JSObject* holder,
+ uint32_t index);
+ void ApiObjectAccess(const char* tag, JSObject* obj);
+ void ApiEntryCall(const char* name);
// ==== Events logged by --log-code. ====
// Emits a code event for a callback function.
- static void CallbackEvent(String* name, Address entry_point);
- static void GetterCallbackEvent(String* name, Address entry_point);
- static void SetterCallbackEvent(String* name, Address entry_point);
+ void CallbackEvent(String* name, Address entry_point);
+ void GetterCallbackEvent(String* name, Address entry_point);
+ void SetterCallbackEvent(String* name, Address entry_point);
// Emits a code create event.
- static void CodeCreateEvent(LogEventsAndTags tag,
- Code* code, const char* source);
- static void CodeCreateEvent(LogEventsAndTags tag,
- Code* code, String* name);
- static void CodeCreateEvent(LogEventsAndTags tag,
- Code* code,
- SharedFunctionInfo* shared,
- String* name);
- static void CodeCreateEvent(LogEventsAndTags tag,
- Code* code,
- SharedFunctionInfo* shared,
- String* source, int line);
- static void CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count);
- static void CodeMovingGCEvent();
+ void CodeCreateEvent(LogEventsAndTags tag,
+ Code* code, const char* source);
+ void CodeCreateEvent(LogEventsAndTags tag,
+ Code* code, String* name);
+ void CodeCreateEvent(LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ String* name);
+ void CodeCreateEvent(LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ String* source, int line);
+ void CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count);
+ void CodeMovingGCEvent();
// Emits a code create event for a RegExp.
- static void RegExpCodeCreateEvent(Code* code, String* source);
+ void RegExpCodeCreateEvent(Code* code, String* source);
// Emits a code move event.
- static void CodeMoveEvent(Address from, Address to);
+ void CodeMoveEvent(Address from, Address to);
// Emits a code delete event.
- static void CodeDeleteEvent(Address from);
+ void CodeDeleteEvent(Address from);
- static void SFIMoveEvent(Address from, Address to);
+ void SharedFunctionInfoMoveEvent(Address from, Address to);
- static void SnapshotPositionEvent(Address addr, int pos);
+ void SnapshotPositionEvent(Address addr, int pos);
// ==== Events logged by --log-gc. ====
// Heap sampling events: start, end, and individual types.
- static void HeapSampleBeginEvent(const char* space, const char* kind);
- static void HeapSampleEndEvent(const char* space, const char* kind);
- static void HeapSampleItemEvent(const char* type, int number, int bytes);
- static void HeapSampleJSConstructorEvent(const char* constructor,
- int number, int bytes);
- static void HeapSampleJSRetainersEvent(const char* constructor,
+ void HeapSampleBeginEvent(const char* space, const char* kind);
+ void HeapSampleEndEvent(const char* space, const char* kind);
+ void HeapSampleItemEvent(const char* type, int number, int bytes);
+ void HeapSampleJSConstructorEvent(const char* constructor,
+ int number, int bytes);
+ void HeapSampleJSRetainersEvent(const char* constructor,
const char* event);
- static void HeapSampleJSProducerEvent(const char* constructor,
- Address* stack);
- static void HeapSampleStats(const char* space, const char* kind,
- intptr_t capacity, intptr_t used);
-
- static void SharedLibraryEvent(const char* library_path,
- uintptr_t start,
- uintptr_t end);
- static void SharedLibraryEvent(const wchar_t* library_path,
- uintptr_t start,
- uintptr_t end);
+ void HeapSampleJSProducerEvent(const char* constructor,
+ Address* stack);
+ void HeapSampleStats(const char* space, const char* kind,
+ intptr_t capacity, intptr_t used);
+
+ void SharedLibraryEvent(const char* library_path,
+ uintptr_t start,
+ uintptr_t end);
+ void SharedLibraryEvent(const wchar_t* library_path,
+ uintptr_t start,
+ uintptr_t end);
// ==== Events logged by --log-regexp ====
// Regexp compilation and execution events.
- static void RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache);
+ void RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache);
// Log an event reported from generated code
- static void LogRuntime(Vector<const char> format, JSArray* args);
+ void LogRuntime(Vector<const char> format, JSArray* args);
#ifdef ENABLE_LOGGING_AND_PROFILING
- static bool is_logging() {
+ bool is_logging() {
return logging_nesting_ > 0;
}
// Pause/Resume collection of profiling data.
// When data collection is paused, CPU Tick events are discarded until
// data collection is Resumed.
- static void PauseProfiler(int flags, int tag);
- static void ResumeProfiler(int flags, int tag);
- static int GetActiveProfilerModules();
+ void PauseProfiler(int flags, int tag);
+ void ResumeProfiler(int flags, int tag);
+ int GetActiveProfilerModules();
// If logging is performed into a memory buffer, allows to
// retrieve previously written messages. See v8.h.
- static int GetLogLines(int from_pos, char* dest_buf, int max_size);
+ int GetLogLines(int from_pos, char* dest_buf, int max_size);
// Logs all compiled functions found in the heap.
- static void LogCompiledFunctions();
+ void LogCompiledFunctions();
// Logs all accessor callbacks found in the heap.
- static void LogAccessorCallbacks();
+ void LogAccessorCallbacks();
// Used for logging stubs found in the snapshot.
- static void LogCodeObjects();
+ void LogCodeObjects();
// Converts tag to a corresponding NATIVE_... if the script is native.
INLINE(static LogEventsAndTags ToNativeByScript(LogEventsAndTags, Script*));
@@ -284,70 +296,74 @@ class Logger {
// Profiler's sampling interval (in milliseconds).
static const int kSamplingIntervalMs = 1;
+ // Callback from Log, stops profiling in case of insufficient resources.
+ void LogFailure();
+
private:
+ Logger();
+ ~Logger();
// Emits the profiler's first message.
- static void ProfilerBeginEvent();
+ void ProfilerBeginEvent();
// Emits callback event messages.
- static void CallbackEventInternal(const char* prefix,
- const char* name,
- Address entry_point);
+ void CallbackEventInternal(const char* prefix,
+ const char* name,
+ Address entry_point);
// Internal configurable move event.
- static void MoveEventInternal(LogEventsAndTags event,
- Address from,
- Address to);
+ void MoveEventInternal(LogEventsAndTags event, Address from, Address to);
// Internal configurable move event.
- static void DeleteEventInternal(LogEventsAndTags event,
- Address from);
+ void DeleteEventInternal(LogEventsAndTags event, Address from);
// Emits the source code of a regexp. Used by regexp events.
- static void LogRegExpSource(Handle<JSRegExp> regexp);
+ void LogRegExpSource(Handle<JSRegExp> regexp);
// Used for logging stubs found in the snapshot.
- static void LogCodeObject(Object* code_object);
+ void LogCodeObject(Object* code_object);
// Emits general information about generated code.
- static void LogCodeInfo();
+ void LogCodeInfo();
// Handles code creation when low-level profiling is active.
- static void LowLevelCodeCreateEvent(Code* code, LogMessageBuilder* msg);
+ void LowLevelCodeCreateEvent(Code* code, LogMessageBuilder* msg);
// Emits a profiler tick event. Used by the profiler thread.
- static void TickEvent(TickSample* sample, bool overflow);
+ void TickEvent(TickSample* sample, bool overflow);
- static void ApiEvent(const char* name, ...);
+ void ApiEvent(const char* name, ...);
// Logs a StringEvent regardless of whether FLAG_log is true.
- static void UncheckedStringEvent(const char* name, const char* value);
+ void UncheckedStringEvent(const char* name, const char* value);
// Logs an IntEvent regardless of whether FLAG_log is true.
- static void UncheckedIntEvent(const char* name, int value);
- static void UncheckedIntPtrTEvent(const char* name, intptr_t value);
-
- // Stops logging and profiling in case of insufficient resources.
- static void StopLoggingAndProfiling();
+ void UncheckedIntEvent(const char* name, int value);
+ void UncheckedIntPtrTEvent(const char* name, intptr_t value);
// Returns whether profiler's sampler is active.
- static bool IsProfilerSamplerActive();
+ bool IsProfilerSamplerActive();
// The sampler used by the profiler and the sliding state window.
- static Ticker* ticker_;
+ Ticker* ticker_;
// When the statistical profile is active, profiler_
// points to a Profiler, that handles collection
// of samples.
- static Profiler* profiler_;
+ Profiler* profiler_;
// SlidingStateWindow instance keeping a sliding window of the most
// recent VM states.
- static SlidingStateWindow* sliding_state_window_;
+ SlidingStateWindow* sliding_state_window_;
+
+ // An array of log events names.
+ const char* const* log_events_;
// Internal implementation classes with access to
// private members.
friend class EventLog;
+ friend class Isolate;
+ friend class LogMessageBuilder;
friend class TimeLog;
friend class Profiler;
friend class SlidingStateWindow;
@@ -356,21 +372,72 @@ class Logger {
friend class LoggerTestHelper;
- static int logging_nesting_;
- static int cpu_profiler_nesting_;
- static int heap_profiler_nesting_;
+
+ int logging_nesting_;
+ int cpu_profiler_nesting_;
+ int heap_profiler_nesting_;
+
+ Log* log_;
+
+ // Guards against multiple calls to TearDown() that can happen in some tests.
+ // 'true' between Setup() and TearDown().
+ bool is_initialized_;
+
+ // Support for 'incremental addresses' in compressed logs:
+ // LogMessageBuilder::AppendAddress(Address addr)
+ Address last_address_;
+ // Logger::TickEvent(...)
+ Address prev_sp_;
+ Address prev_function_;
+ // Logger::MoveEventInternal(...)
+ Address prev_to_;
+ // Logger::FunctionCreateEvent(...)
+ Address prev_code_;
friend class CpuProfiler;
#else
- static bool is_logging() { return false; }
+ bool is_logging() { return false; }
#endif
};
+// Process wide registry of samplers.
+class SamplerRegistry : public AllStatic {
+ public:
+ enum State {
+ HAS_NO_SAMPLERS,
+ HAS_SAMPLERS,
+ HAS_CPU_PROFILING_SAMPLERS
+ };
+
+ typedef void (*VisitSampler)(Sampler*, void*);
+
+ static State GetState();
+
+ // Iterates over all active samplers keeping the internal lock held.
+ // Returns whether there are any active samplers.
+ static bool IterateActiveSamplers(VisitSampler func, void* param);
+
+ // Adds/Removes an active sampler.
+ static void AddActiveSampler(Sampler* sampler);
+ static void RemoveActiveSampler(Sampler* sampler);
+
+ private:
+ static bool ActiveSamplersExist() {
+ return active_samplers_ != NULL && !active_samplers_->is_empty();
+ }
+
+ static Mutex* mutex_; // Protects the state below.
+ static List<Sampler*>* active_samplers_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SamplerRegistry);
+};
+
+
// Class that extracts stack trace, used for profiling.
class StackTracer : public AllStatic {
public:
- static void Trace(TickSample* sample);
+ static void Trace(Isolate* isolate, TickSample* sample);
};
} } // namespace v8::internal
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index a4c782c5..1f73388f 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -44,28 +44,27 @@ namespace internal {
// -------------------------------------------------------------------------
// MarkCompactCollector
-bool MarkCompactCollector::force_compaction_ = false;
-bool MarkCompactCollector::compacting_collection_ = false;
-bool MarkCompactCollector::compact_on_next_gc_ = false;
-
-int MarkCompactCollector::previous_marked_count_ = 0;
-GCTracer* MarkCompactCollector::tracer_ = NULL;
-
-
+MarkCompactCollector::MarkCompactCollector() : // NOLINT
+#ifdef DEBUG
+ state_(IDLE),
+#endif
+ force_compaction_(false),
+ compacting_collection_(false),
+ compact_on_next_gc_(false),
+ previous_marked_count_(0),
+ tracer_(NULL),
#ifdef DEBUG
-MarkCompactCollector::CollectorState MarkCompactCollector::state_ = IDLE;
-
-// Counters used for debugging the marking phase of mark-compact or mark-sweep
-// collection.
-int MarkCompactCollector::live_bytes_ = 0;
-int MarkCompactCollector::live_young_objects_size_ = 0;
-int MarkCompactCollector::live_old_data_objects_size_ = 0;
-int MarkCompactCollector::live_old_pointer_objects_size_ = 0;
-int MarkCompactCollector::live_code_objects_size_ = 0;
-int MarkCompactCollector::live_map_objects_size_ = 0;
-int MarkCompactCollector::live_cell_objects_size_ = 0;
-int MarkCompactCollector::live_lo_objects_size_ = 0;
+ live_young_objects_size_(0),
+ live_old_pointer_objects_size_(0),
+ live_old_data_objects_size_(0),
+ live_code_objects_size_(0),
+ live_map_objects_size_(0),
+ live_cell_objects_size_(0),
+ live_lo_objects_size_(0),
+ live_bytes_(0),
#endif
+ heap_(NULL),
+ code_flusher_(NULL) { }
void MarkCompactCollector::CollectGarbage() {
@@ -87,15 +86,15 @@ void MarkCompactCollector::CollectGarbage() {
GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_COMPACT);
EncodeForwardingAddresses();
- Heap::MarkMapPointersAsEncoded(true);
+ heap_->MarkMapPointersAsEncoded(true);
UpdatePointers();
- Heap::MarkMapPointersAsEncoded(false);
- PcToCodeCache::FlushPcToCodeCache();
+ heap_->MarkMapPointersAsEncoded(false);
+ heap_->isolate()->pc_to_code_cache()->Flush();
RelocateObjects();
} else {
SweepSpaces();
- PcToCodeCache::FlushPcToCodeCache();
+ heap_->isolate()->pc_to_code_cache()->Flush();
}
Finish();
@@ -124,7 +123,7 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) {
compact_on_next_gc_ = false;
if (FLAG_never_compact) compacting_collection_ = false;
- if (!Heap::map_space()->MapPointersEncodable())
+ if (!HEAP->map_space()->MapPointersEncodable())
compacting_collection_ = false;
if (FLAG_collect_maps) CreateBackPointers();
#ifdef ENABLE_GDB_JIT_INTERFACE
@@ -162,9 +161,9 @@ void MarkCompactCollector::Finish() {
// force lazy re-initialization of it. This must be done after the
// GC, because it relies on the new address of certain old space
// objects (empty string, illegal builtin).
- StubCache::Clear();
+ Isolate::Current()->stub_cache()->Clear();
- ExternalStringTable::CleanUp();
+ heap_->external_string_table_.CleanUp();
// If we've just compacted old space there's no reason to check the
// fragmentation limit. Just return.
@@ -221,17 +220,19 @@ void MarkCompactCollector::Finish() {
// and continue with marking. This process repeats until all reachable
// objects have been marked.
-static MarkingStack marking_stack;
-
-class FlushCode : public AllStatic {
+class CodeFlusher {
public:
- static void AddCandidate(SharedFunctionInfo* shared_info) {
+ explicit CodeFlusher(Isolate* isolate)
+ : isolate_(isolate),
+ jsfunction_candidates_head_(NULL),
+ shared_function_info_candidates_head_(NULL) {}
+
+ void AddCandidate(SharedFunctionInfo* shared_info) {
SetNextCandidate(shared_info, shared_function_info_candidates_head_);
shared_function_info_candidates_head_ = shared_info;
}
-
- static void AddCandidate(JSFunction* function) {
+ void AddCandidate(JSFunction* function) {
ASSERT(function->unchecked_code() ==
function->unchecked_shared()->unchecked_code());
@@ -239,15 +240,14 @@ class FlushCode : public AllStatic {
jsfunction_candidates_head_ = function;
}
-
- static void ProcessCandidates() {
+ void ProcessCandidates() {
ProcessSharedFunctionInfoCandidates();
ProcessJSFunctionCandidates();
}
private:
- static void ProcessJSFunctionCandidates() {
- Code* lazy_compile = Builtins::builtin(Builtins::LazyCompile);
+ void ProcessJSFunctionCandidates() {
+ Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile);
JSFunction* candidate = jsfunction_candidates_head_;
JSFunction* next_candidate;
@@ -271,8 +271,8 @@ class FlushCode : public AllStatic {
}
- static void ProcessSharedFunctionInfoCandidates() {
- Code* lazy_compile = Builtins::builtin(Builtins::LazyCompile);
+ void ProcessSharedFunctionInfoCandidates() {
+ Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile);
SharedFunctionInfo* candidate = shared_function_info_candidates_head_;
SharedFunctionInfo* next_candidate;
@@ -291,27 +291,22 @@ class FlushCode : public AllStatic {
shared_function_info_candidates_head_ = NULL;
}
-
static JSFunction** GetNextCandidateField(JSFunction* candidate) {
return reinterpret_cast<JSFunction**>(
candidate->address() + JSFunction::kCodeEntryOffset);
}
-
static JSFunction* GetNextCandidate(JSFunction* candidate) {
return *GetNextCandidateField(candidate);
}
-
static void SetNextCandidate(JSFunction* candidate,
JSFunction* next_candidate) {
*GetNextCandidateField(candidate) = next_candidate;
}
-
STATIC_ASSERT(kPointerSize <= Code::kHeaderSize - Code::kHeaderPaddingStart);
-
static SharedFunctionInfo** GetNextCandidateField(
SharedFunctionInfo* candidate) {
Code* code = candidate->unchecked_code();
@@ -319,29 +314,34 @@ class FlushCode : public AllStatic {
code->address() + Code::kHeaderPaddingStart);
}
-
static SharedFunctionInfo* GetNextCandidate(SharedFunctionInfo* candidate) {
return *GetNextCandidateField(candidate);
}
-
static void SetNextCandidate(SharedFunctionInfo* candidate,
SharedFunctionInfo* next_candidate) {
*GetNextCandidateField(candidate) = next_candidate;
}
- static JSFunction* jsfunction_candidates_head_;
+ Isolate* isolate_;
+ JSFunction* jsfunction_candidates_head_;
+ SharedFunctionInfo* shared_function_info_candidates_head_;
- static SharedFunctionInfo* shared_function_info_candidates_head_;
+ DISALLOW_COPY_AND_ASSIGN(CodeFlusher);
};
-JSFunction* FlushCode::jsfunction_candidates_head_ = NULL;
-SharedFunctionInfo* FlushCode::shared_function_info_candidates_head_ = NULL;
+MarkCompactCollector::~MarkCompactCollector() {
+ if (code_flusher_ != NULL) {
+ delete code_flusher_;
+ code_flusher_ = NULL;
+ }
+}
+
static inline HeapObject* ShortCircuitConsString(Object** p) {
// Optimization: If the heap object pointed to by p is a non-symbol
- // cons string whose right substring is Heap::empty_string, update
+ // cons string whose right substring is HEAP->empty_string, update
// it in place to its left substring. Return the updated value.
//
// Here we assume that if we change *p, we replace it with a heap object
@@ -349,7 +349,7 @@ static inline HeapObject* ShortCircuitConsString(Object** p) {
//
// The check performed is:
// object->IsConsString() && !object->IsSymbol() &&
- // (ConsString::cast(object)->second() == Heap::empty_string())
+ // (ConsString::cast(object)->second() == HEAP->empty_string())
// except the maps for the object and its possible substrings might be
// marked.
HeapObject* object = HeapObject::cast(*p);
@@ -359,7 +359,8 @@ static inline HeapObject* ShortCircuitConsString(Object** p) {
if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object;
Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second();
- if (second != Heap::raw_unchecked_empty_string()) {
+ Heap* heap = map_word.ToMap()->heap();
+ if (second != heap->raw_unchecked_empty_string()) {
return object;
}
@@ -367,7 +368,7 @@ static inline HeapObject* ShortCircuitConsString(Object** p) {
// page dirty marks. Therefore, we only replace the string with its left
// substring when page dirty marks do not change.
Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first();
- if (!Heap::InNewSpace(object) && Heap::InNewSpace(first)) return object;
+ if (!heap->InNewSpace(object) && heap->InNewSpace(first)) return object;
*p = first;
return HeapObject::cast(first);
@@ -380,19 +381,6 @@ class StaticMarkingVisitor : public StaticVisitorBase {
table_.GetVisitor(map)(map, obj);
}
- static void EnableCodeFlushing(bool enabled) {
- if (enabled) {
- table_.Register(kVisitJSFunction, &VisitJSFunctionAndFlushCode);
- table_.Register(kVisitSharedFunctionInfo,
- &VisitSharedFunctionInfoAndFlushCode);
-
- } else {
- table_.Register(kVisitJSFunction, &VisitJSFunction);
- table_.Register(kVisitSharedFunctionInfo,
- &VisitSharedFunctionInfoGeneric);
- }
- }
-
static void Initialize() {
table_.Register(kVisitShortcutCandidate,
&FixedBodyVisitor<StaticMarkingVisitor,
@@ -454,18 +442,18 @@ class StaticMarkingVisitor : public StaticVisitorBase {
kVisitStructGeneric>();
}
- INLINE(static void VisitPointer(Object** p)) {
- MarkObjectByPointer(p);
+ INLINE(static void VisitPointer(Heap* heap, Object** p)) {
+ MarkObjectByPointer(heap, p);
}
- INLINE(static void VisitPointers(Object** start, Object** end)) {
+ INLINE(static void VisitPointers(Heap* heap, Object** start, Object** end)) {
// Mark all objects pointed to in [start, end).
const int kMinRangeForMarkingRecursion = 64;
if (end - start >= kMinRangeForMarkingRecursion) {
- if (VisitUnmarkedObjects(start, end)) return;
+ if (VisitUnmarkedObjects(heap, start, end)) return;
// We are close to a stack overflow, so just mark the objects.
}
- for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
+ for (Object** p = start; p < end; p++) MarkObjectByPointer(heap, p);
}
static inline void VisitCodeTarget(RelocInfo* rinfo) {
@@ -474,9 +462,9 @@ class StaticMarkingVisitor : public StaticVisitorBase {
if (FLAG_cleanup_ics_at_gc && code->is_inline_cache_stub()) {
IC::Clear(rinfo->pc());
// Please note targets for cleared inline cached do not have to be
- // marked since they are contained in Heap::non_monomorphic_cache().
+ // marked since they are contained in HEAP->non_monomorphic_cache().
} else {
- MarkCompactCollector::MarkObject(code);
+ HEAP->mark_compact_collector()->MarkObject(code);
}
}
@@ -484,7 +472,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
Object* cell = rinfo->target_cell();
Object* old_cell = cell;
- VisitPointer(&cell);
+ VisitPointer(HEAP, &cell);
if (cell != old_cell) {
rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
}
@@ -496,34 +484,38 @@ class StaticMarkingVisitor : public StaticVisitorBase {
(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
rinfo->IsPatchedDebugBreakSlotSequence()));
HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address());
- MarkCompactCollector::MarkObject(code);
+ HEAP->mark_compact_collector()->MarkObject(code);
}
// Mark object pointed to by p.
- INLINE(static void MarkObjectByPointer(Object** p)) {
+ INLINE(static void MarkObjectByPointer(Heap* heap, Object** p)) {
if (!(*p)->IsHeapObject()) return;
HeapObject* object = ShortCircuitConsString(p);
- MarkCompactCollector::MarkObject(object);
+ heap->mark_compact_collector()->MarkObject(object);
}
+
// Visit an unmarked object.
static inline void VisitUnmarkedObject(HeapObject* obj) {
#ifdef DEBUG
- ASSERT(Heap::Contains(obj));
+ ASSERT(HEAP->Contains(obj));
ASSERT(!obj->IsMarked());
#endif
Map* map = obj->map();
- MarkCompactCollector::SetMark(obj);
+ MarkCompactCollector* collector = map->heap()->mark_compact_collector();
+ collector->SetMark(obj);
// Mark the map pointer and the body.
- MarkCompactCollector::MarkObject(map);
+ collector->MarkObject(map);
IterateBody(map, obj);
}
// Visit all unmarked objects pointed to by [start, end).
// Returns false if the operation fails (lack of stack space).
- static inline bool VisitUnmarkedObjects(Object** start, Object** end) {
+ static inline bool VisitUnmarkedObjects(Heap* heap,
+ Object** start,
+ Object** end) {
// Return false is we are close to the stack limit.
- StackLimitCheck check;
+ StackLimitCheck check(heap->isolate());
if (check.HasOverflowed()) return false;
// Visit the unmarked objects.
@@ -559,7 +551,8 @@ class StaticMarkingVisitor : public StaticVisitorBase {
void> StructObjectVisitor;
static void VisitCode(Map* map, HeapObject* object) {
- reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>();
+ reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>(
+ map->heap());
}
// Code flushing support.
@@ -569,21 +562,20 @@ class StaticMarkingVisitor : public StaticVisitorBase {
static const int kCodeAgeThreshold = 5;
inline static bool HasSourceCode(SharedFunctionInfo* info) {
- Object* undefined = Heap::raw_unchecked_undefined_value();
+ Object* undefined = HEAP->raw_unchecked_undefined_value();
return (info->script() != undefined) &&
(reinterpret_cast<Script*>(info->script())->source() != undefined);
}
inline static bool IsCompiled(JSFunction* function) {
- return
- function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile);
+ return function->unchecked_code() !=
+ Isolate::Current()->builtins()->builtin(Builtins::kLazyCompile);
}
-
inline static bool IsCompiled(SharedFunctionInfo* function) {
- return
- function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile);
+ return function->unchecked_code() !=
+ Isolate::Current()->builtins()->builtin(Builtins::kLazyCompile);
}
inline static bool IsFlushable(JSFunction* function) {
@@ -645,7 +637,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
}
- static bool FlushCodeForFunction(JSFunction* function) {
+ static bool FlushCodeForFunction(Heap* heap, JSFunction* function) {
if (!IsFlushable(function)) return false;
// This function's code looks flushable. But we have to postpone the
@@ -653,7 +645,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
// SharedFunctionInfo because some of them might be optimized.
// That would make the nonoptimized version of the code nonflushable,
// because it is required for bailing out from optimized code.
- FlushCode::AddCandidate(function);
+ heap->mark_compact_collector()->code_flusher()->AddCandidate(function);
return true;
}
@@ -676,9 +668,10 @@ class StaticMarkingVisitor : public StaticVisitorBase {
if (!ctx->IsHeapObject()) return false;
Map* map = SafeMap(ctx);
- if (!(map == Heap::raw_unchecked_context_map() ||
- map == Heap::raw_unchecked_catch_context_map() ||
- map == Heap::raw_unchecked_global_context_map())) {
+ Heap* heap = map->heap();
+ if (!(map == heap->raw_unchecked_context_map() ||
+ map == heap->raw_unchecked_catch_context_map() ||
+ map == heap->raw_unchecked_global_context_map())) {
return false;
}
@@ -705,29 +698,37 @@ class StaticMarkingVisitor : public StaticVisitorBase {
static void VisitSharedFunctionInfoAndFlushCode(Map* map,
HeapObject* object) {
+ MarkCompactCollector* collector = map->heap()->mark_compact_collector();
+ if (!collector->is_code_flushing_enabled()) {
+ VisitSharedFunctionInfoGeneric(map, object);
+ return;
+ }
VisitSharedFunctionInfoAndFlushCodeGeneric(map, object, false);
}
static void VisitSharedFunctionInfoAndFlushCodeGeneric(
Map* map, HeapObject* object, bool known_flush_code_candidate) {
+ Heap* heap = map->heap();
SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object);
if (shared->IsInobjectSlackTrackingInProgress()) shared->DetachInitialMap();
if (!known_flush_code_candidate) {
known_flush_code_candidate = IsFlushable(shared);
- if (known_flush_code_candidate) FlushCode::AddCandidate(shared);
+ if (known_flush_code_candidate) {
+ heap->mark_compact_collector()->code_flusher()->AddCandidate(shared);
+ }
}
- VisitSharedFunctionInfoFields(object, known_flush_code_candidate);
+ VisitSharedFunctionInfoFields(heap, object, known_flush_code_candidate);
}
- static void VisitCodeEntry(Address entry_address) {
+ static void VisitCodeEntry(Heap* heap, Address entry_address) {
Object* code = Code::GetObjectFromEntryAddress(entry_address);
Object* old_code = code;
- VisitPointer(&code);
+ VisitPointer(heap, &code);
if (code != old_code) {
Memory::Address_at(entry_address) =
reinterpret_cast<Code*>(code)->entry();
@@ -736,16 +737,22 @@ class StaticMarkingVisitor : public StaticVisitorBase {
static void VisitJSFunctionAndFlushCode(Map* map, HeapObject* object) {
+ Heap* heap = map->heap();
+ MarkCompactCollector* collector = heap->mark_compact_collector();
+ if (!collector->is_code_flushing_enabled()) {
+ VisitJSFunction(map, object);
+ return;
+ }
+
JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object);
// The function must have a valid context and not be a builtin.
bool flush_code_candidate = false;
if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) {
- flush_code_candidate = FlushCodeForFunction(jsfunction);
+ flush_code_candidate = FlushCodeForFunction(heap, jsfunction);
}
if (!flush_code_candidate) {
- MarkCompactCollector::MarkObject(
- jsfunction->unchecked_shared()->unchecked_code());
+ collector->MarkObject(jsfunction->unchecked_shared()->unchecked_code());
if (jsfunction->unchecked_code()->kind() == Code::OPTIMIZED_FUNCTION) {
// For optimized functions we should retain both non-optimized version
@@ -761,8 +768,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
i < count;
i++) {
JSFunction* inlined = reinterpret_cast<JSFunction*>(literals->get(i));
- MarkCompactCollector::MarkObject(
- inlined->unchecked_shared()->unchecked_code());
+ collector->MarkObject(inlined->unchecked_shared()->unchecked_code());
}
}
}
@@ -787,11 +793,15 @@ class StaticMarkingVisitor : public StaticVisitorBase {
static inline void VisitJSFunctionFields(Map* map,
JSFunction* object,
bool flush_code_candidate) {
- VisitPointers(SLOT_ADDR(object, JSFunction::kPropertiesOffset),
+ Heap* heap = map->heap();
+ MarkCompactCollector* collector = heap->mark_compact_collector();
+
+ VisitPointers(heap,
+ SLOT_ADDR(object, JSFunction::kPropertiesOffset),
SLOT_ADDR(object, JSFunction::kCodeEntryOffset));
if (!flush_code_candidate) {
- VisitCodeEntry(object->address() + JSFunction::kCodeEntryOffset);
+ VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset);
} else {
// Don't visit code object.
@@ -800,15 +810,16 @@ class StaticMarkingVisitor : public StaticVisitorBase {
SharedFunctionInfo* shared_info = object->unchecked_shared();
if (!shared_info->IsMarked()) {
Map* shared_info_map = shared_info->map();
- MarkCompactCollector::SetMark(shared_info);
- MarkCompactCollector::MarkObject(shared_info_map);
+ collector->SetMark(shared_info);
+ collector->MarkObject(shared_info_map);
VisitSharedFunctionInfoAndFlushCodeGeneric(shared_info_map,
shared_info,
true);
}
}
- VisitPointers(SLOT_ADDR(object,
+ VisitPointers(heap,
+ SLOT_ADDR(object,
JSFunction::kCodeEntryOffset + kPointerSize),
SLOT_ADDR(object, JSFunction::kNonWeakFieldsEndOffset));
@@ -816,15 +827,17 @@ class StaticMarkingVisitor : public StaticVisitorBase {
}
- static void VisitSharedFunctionInfoFields(HeapObject* object,
+ static void VisitSharedFunctionInfoFields(Heap* heap,
+ HeapObject* object,
bool flush_code_candidate) {
- VisitPointer(SLOT_ADDR(object, SharedFunctionInfo::kNameOffset));
+ VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kNameOffset));
if (!flush_code_candidate) {
- VisitPointer(SLOT_ADDR(object, SharedFunctionInfo::kCodeOffset));
+ VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kCodeOffset));
}
- VisitPointers(SLOT_ADDR(object, SharedFunctionInfo::kScopeInfoOffset),
+ VisitPointers(heap,
+ SLOT_ADDR(object, SharedFunctionInfo::kScopeInfoOffset),
SLOT_ADDR(object, SharedFunctionInfo::kSize));
}
@@ -842,12 +855,14 @@ VisitorDispatchTable<StaticMarkingVisitor::Callback>
class MarkingVisitor : public ObjectVisitor {
public:
+ explicit MarkingVisitor(Heap* heap) : heap_(heap) { }
+
void VisitPointer(Object** p) {
- StaticMarkingVisitor::VisitPointer(p);
+ StaticMarkingVisitor::VisitPointer(heap_, p);
}
void VisitPointers(Object** start, Object** end) {
- StaticMarkingVisitor::VisitPointers(start, end);
+ StaticMarkingVisitor::VisitPointers(heap_, start, end);
}
void VisitCodeTarget(RelocInfo* rinfo) {
@@ -861,21 +876,33 @@ class MarkingVisitor : public ObjectVisitor {
void VisitDebugTarget(RelocInfo* rinfo) {
StaticMarkingVisitor::VisitDebugTarget(rinfo);
}
+
+ private:
+ Heap* heap_;
};
class CodeMarkingVisitor : public ThreadVisitor {
public:
+ explicit CodeMarkingVisitor(MarkCompactCollector* collector)
+ : collector_(collector) {}
+
void VisitThread(ThreadLocalTop* top) {
for (StackFrameIterator it(top); !it.done(); it.Advance()) {
- MarkCompactCollector::MarkObject(it.frame()->unchecked_code());
+ collector_->MarkObject(it.frame()->unchecked_code());
}
}
+
+ private:
+ MarkCompactCollector* collector_;
};
class SharedFunctionInfoMarkingVisitor : public ObjectVisitor {
public:
+ explicit SharedFunctionInfoMarkingVisitor(MarkCompactCollector* collector)
+ : collector_(collector) {}
+
void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) VisitPointer(p);
}
@@ -884,44 +911,52 @@ class SharedFunctionInfoMarkingVisitor : public ObjectVisitor {
Object* obj = *slot;
if (obj->IsSharedFunctionInfo()) {
SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(obj);
- MarkCompactCollector::MarkObject(shared->unchecked_code());
- MarkCompactCollector::MarkObject(shared);
+ collector_->MarkObject(shared->unchecked_code());
+ collector_->MarkObject(shared);
}
}
+
+ private:
+ MarkCompactCollector* collector_;
};
void MarkCompactCollector::PrepareForCodeFlushing() {
+ ASSERT(heap_ == Isolate::Current()->heap());
+
if (!FLAG_flush_code) {
- StaticMarkingVisitor::EnableCodeFlushing(false);
+ EnableCodeFlushing(false);
return;
}
#ifdef ENABLE_DEBUGGER_SUPPORT
- if (Debug::IsLoaded() || Debug::has_break_points()) {
- StaticMarkingVisitor::EnableCodeFlushing(false);
+ if (heap_->isolate()->debug()->IsLoaded() ||
+ heap_->isolate()->debug()->has_break_points()) {
+ EnableCodeFlushing(false);
return;
}
#endif
- StaticMarkingVisitor::EnableCodeFlushing(true);
+ EnableCodeFlushing(true);
// Ensure that empty descriptor array is marked. Method MarkDescriptorArray
// relies on it being marked before any other descriptor array.
- MarkObject(Heap::raw_unchecked_empty_descriptor_array());
+ MarkObject(heap_->raw_unchecked_empty_descriptor_array());
// Make sure we are not referencing the code from the stack.
+ ASSERT(this == heap_->mark_compact_collector());
for (StackFrameIterator it; !it.done(); it.Advance()) {
MarkObject(it.frame()->unchecked_code());
}
// Iterate the archived stacks in all threads to check if
// the code is referenced.
- CodeMarkingVisitor code_marking_visitor;
- ThreadManager::IterateArchivedThreads(&code_marking_visitor);
+ CodeMarkingVisitor code_marking_visitor(this);
+ heap_->isolate()->thread_manager()->IterateArchivedThreads(
+ &code_marking_visitor);
- SharedFunctionInfoMarkingVisitor visitor;
- CompilationCache::IterateFunctions(&visitor);
- HandleScopeImplementer::Iterate(&visitor);
+ SharedFunctionInfoMarkingVisitor visitor(this);
+ heap_->isolate()->compilation_cache()->IterateFunctions(&visitor);
+ heap_->isolate()->handle_scope_implementer()->Iterate(&visitor);
ProcessMarkingStack();
}
@@ -930,6 +965,9 @@ void MarkCompactCollector::PrepareForCodeFlushing() {
// Visitor class for marking heap roots.
class RootMarkingVisitor : public ObjectVisitor {
public:
+ explicit RootMarkingVisitor(Heap* heap)
+ : collector_(heap->mark_compact_collector()) { }
+
void VisitPointer(Object** p) {
MarkObjectByPointer(p);
}
@@ -948,16 +986,18 @@ class RootMarkingVisitor : public ObjectVisitor {
Map* map = object->map();
// Mark the object.
- MarkCompactCollector::SetMark(object);
+ collector_->SetMark(object);
// Mark the map pointer and body, and push them on the marking stack.
- MarkCompactCollector::MarkObject(map);
+ collector_->MarkObject(map);
StaticMarkingVisitor::IterateBody(map, object);
// Mark all the objects reachable from the map and body. May leave
// overflowed objects in the heap.
- MarkCompactCollector::EmptyMarkingStack();
+ collector_->EmptyMarkingStack();
}
+
+ MarkCompactCollector* collector_;
};
@@ -976,10 +1016,10 @@ class SymbolTableCleaner : public ObjectVisitor {
// Since no objects have yet been moved we can safely access the map of
// the object.
if ((*p)->IsExternalString()) {
- Heap::FinalizeExternalString(String::cast(*p));
+ HEAP->FinalizeExternalString(String::cast(*p));
}
// Set the entry to null_value (as deleted).
- *p = Heap::raw_unchecked_null_value();
+ *p = HEAP->raw_unchecked_null_value();
pointers_removed_++;
}
}
@@ -1010,11 +1050,11 @@ class MarkCompactWeakObjectRetainer : public WeakObjectRetainer {
void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) {
ASSERT(!object->IsMarked());
- ASSERT(Heap::Contains(object));
+ ASSERT(HEAP->Contains(object));
if (object->IsMap()) {
Map* map = Map::cast(object);
if (FLAG_cleanup_caches_in_maps_at_gc) {
- map->ClearCodeCache();
+ map->ClearCodeCache(heap_);
}
SetMark(map);
if (FLAG_collect_maps &&
@@ -1022,11 +1062,11 @@ void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) {
map->instance_type() <= JS_FUNCTION_TYPE) {
MarkMapContents(map);
} else {
- marking_stack.Push(map);
+ marking_stack_.Push(map);
}
} else {
SetMark(object);
- marking_stack.Push(object);
+ marking_stack_.Push(object);
}
}
@@ -1043,7 +1083,7 @@ void MarkCompactCollector::MarkMapContents(Map* map) {
Object** end_slot = HeapObject::RawField(map, Map::kPointerFieldsEndOffset);
- StaticMarkingVisitor::VisitPointers(start_slot, end_slot);
+ StaticMarkingVisitor::VisitPointers(map->heap(), start_slot, end_slot);
}
@@ -1051,7 +1091,7 @@ void MarkCompactCollector::MarkDescriptorArray(
DescriptorArray* descriptors) {
if (descriptors->IsMarked()) return;
// Empty descriptor array is marked as a root before any maps are marked.
- ASSERT(descriptors != Heap::raw_unchecked_empty_descriptor_array());
+ ASSERT(descriptors != HEAP->raw_unchecked_empty_descriptor_array());
SetMark(descriptors);
FixedArray* contents = reinterpret_cast<FixedArray*>(
@@ -1061,11 +1101,11 @@ void MarkCompactCollector::MarkDescriptorArray(
ASSERT(contents->IsFixedArray());
ASSERT(contents->length() >= 2);
SetMark(contents);
- // Contents contains (value, details) pairs. If the details say that
- // the type of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION, or
- // NULL_DESCRIPTOR, we don't mark the value as live. Only for
- // MAP_TRANSITION and CONSTANT_TRANSITION is the value an Object* (a
- // Map*).
+ // Contents contains (value, details) pairs. If the details say that the type
+ // of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION,
+ // EXTERNAL_ARRAY_TRANSITION or NULL_DESCRIPTOR, we don't mark the value as
+ // live. Only for MAP_TRANSITION, EXTERNAL_ARRAY_TRANSITION and
+ // CONSTANT_TRANSITION is the value an Object* (a Map*).
for (int i = 0; i < contents->length(); i += 2) {
// If the pair (value, details) at index i, i+1 is not
// a transition or null descriptor, mark the value.
@@ -1074,18 +1114,18 @@ void MarkCompactCollector::MarkDescriptorArray(
HeapObject* object = reinterpret_cast<HeapObject*>(contents->get(i));
if (object->IsHeapObject() && !object->IsMarked()) {
SetMark(object);
- marking_stack.Push(object);
+ marking_stack_.Push(object);
}
}
}
// The DescriptorArray descriptors contains a pointer to its contents array,
// but the contents array is already marked.
- marking_stack.Push(descriptors);
+ marking_stack_.Push(descriptors);
}
void MarkCompactCollector::CreateBackPointers() {
- HeapObjectIterator iterator(Heap::map_space());
+ HeapObjectIterator iterator(HEAP->map_space());
for (HeapObject* next_object = iterator.next();
next_object != NULL; next_object = iterator.next()) {
if (next_object->IsMap()) { // Could also be ByteArray on free list.
@@ -1094,7 +1134,7 @@ void MarkCompactCollector::CreateBackPointers() {
map->instance_type() <= JS_FUNCTION_TYPE) {
map->CreateBackPointers();
} else {
- ASSERT(map->instance_descriptors() == Heap::empty_descriptor_array());
+ ASSERT(map->instance_descriptors() == HEAP->empty_descriptor_array());
}
}
}
@@ -1111,25 +1151,29 @@ static int OverflowObjectSize(HeapObject* obj) {
}
-// Fill the marking stack with overflowed objects returned by the given
-// iterator. Stop when the marking stack is filled or the end of the space
-// is reached, whichever comes first.
-template<class T>
-static void ScanOverflowedObjects(T* it) {
- // The caller should ensure that the marking stack is initially not full,
- // so that we don't waste effort pointlessly scanning for objects.
- ASSERT(!marking_stack.is_full());
-
- for (HeapObject* object = it->next(); object != NULL; object = it->next()) {
- if (object->IsOverflowed()) {
- object->ClearOverflow();
- ASSERT(object->IsMarked());
- ASSERT(Heap::Contains(object));
- marking_stack.Push(object);
- if (marking_stack.is_full()) return;
+class OverflowedObjectsScanner : public AllStatic {
+ public:
+ // Fill the marking stack with overflowed objects returned by the given
+ // iterator. Stop when the marking stack is filled or the end of the space
+ // is reached, whichever comes first.
+ template<class T>
+ static inline void ScanOverflowedObjects(MarkCompactCollector* collector,
+ T* it) {
+ // The caller should ensure that the marking stack is initially not full,
+ // so that we don't waste effort pointlessly scanning for objects.
+ ASSERT(!collector->marking_stack_.is_full());
+
+ for (HeapObject* object = it->next(); object != NULL; object = it->next()) {
+ if (object->IsOverflowed()) {
+ object->ClearOverflow();
+ ASSERT(object->IsMarked());
+ ASSERT(HEAP->Contains(object));
+ collector->marking_stack_.Push(object);
+ if (collector->marking_stack_.is_full()) return;
+ }
}
}
-}
+};
bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) {
@@ -1138,11 +1182,11 @@ bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) {
void MarkCompactCollector::MarkSymbolTable() {
- SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
+ SymbolTable* symbol_table = heap_->raw_unchecked_symbol_table();
// Mark the symbol table itself.
SetMark(symbol_table);
// Explicitly mark the prefix.
- MarkingVisitor marker;
+ MarkingVisitor marker(heap_);
symbol_table->IteratePrefix(&marker);
ProcessMarkingStack();
}
@@ -1151,13 +1195,13 @@ void MarkCompactCollector::MarkSymbolTable() {
void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) {
// Mark the heap roots including global variables, stack variables,
// etc., and all objects reachable from them.
- Heap::IterateStrongRoots(visitor, VISIT_ONLY_STRONG);
+ HEAP->IterateStrongRoots(visitor, VISIT_ONLY_STRONG);
// Handle the symbol table specially.
MarkSymbolTable();
// There may be overflowed objects in the heap. Visit them now.
- while (marking_stack.overflowed()) {
+ while (marking_stack_.overflowed()) {
RefillMarkingStack();
EmptyMarkingStack();
}
@@ -1165,7 +1209,8 @@ void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) {
void MarkCompactCollector::MarkObjectGroups() {
- List<ObjectGroup*>* object_groups = GlobalHandles::ObjectGroups();
+ List<ObjectGroup*>* object_groups =
+ heap_->isolate()->global_handles()->object_groups();
for (int i = 0; i < object_groups->length(); i++) {
ObjectGroup* entry = object_groups->at(i);
@@ -1190,23 +1235,51 @@ void MarkCompactCollector::MarkObjectGroups() {
MarkObject(HeapObject::cast(*objects[j]));
}
}
+
// Once the entire group has been colored gray, set the object group
// to NULL so it won't be processed again.
- delete object_groups->at(i);
+ delete entry;
object_groups->at(i) = NULL;
}
}
+void MarkCompactCollector::MarkImplicitRefGroups() {
+ List<ImplicitRefGroup*>* ref_groups =
+ heap_->isolate()->global_handles()->implicit_ref_groups();
+
+ for (int i = 0; i < ref_groups->length(); i++) {
+ ImplicitRefGroup* entry = ref_groups->at(i);
+ if (entry == NULL) continue;
+
+ if (!entry->parent_->IsMarked()) continue;
+
+ List<Object**>& children = entry->children_;
+ // A parent object is marked, so mark as gray all child white heap
+ // objects.
+ for (int j = 0; j < children.length(); ++j) {
+ if ((*children[j])->IsHeapObject()) {
+ MarkObject(HeapObject::cast(*children[j]));
+ }
+ }
+
+ // Once the entire group has been colored gray, set the group
+ // to NULL so it won't be processed again.
+ delete entry;
+ ref_groups->at(i) = NULL;
+ }
+}
+
+
// Mark all objects reachable from the objects on the marking stack.
// Before: the marking stack contains zero or more heap object pointers.
// After: the marking stack is empty, and all objects reachable from the
// marking stack have been marked, or are overflowed in the heap.
void MarkCompactCollector::EmptyMarkingStack() {
- while (!marking_stack.is_empty()) {
- HeapObject* object = marking_stack.Pop();
+ while (!marking_stack_.is_empty()) {
+ HeapObject* object = marking_stack_.Pop();
ASSERT(object->IsHeapObject());
- ASSERT(Heap::Contains(object));
+ ASSERT(heap_->Contains(object));
ASSERT(object->IsMarked());
ASSERT(!object->IsOverflowed());
@@ -1228,38 +1301,38 @@ void MarkCompactCollector::EmptyMarkingStack() {
// overflowed objects in the heap so the overflow flag on the markings stack
// is cleared.
void MarkCompactCollector::RefillMarkingStack() {
- ASSERT(marking_stack.overflowed());
+ ASSERT(marking_stack_.overflowed());
- SemiSpaceIterator new_it(Heap::new_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&new_it);
- if (marking_stack.is_full()) return;
+ SemiSpaceIterator new_it(HEAP->new_space(), &OverflowObjectSize);
+ OverflowedObjectsScanner::ScanOverflowedObjects(this, &new_it);
+ if (marking_stack_.is_full()) return;
- HeapObjectIterator old_pointer_it(Heap::old_pointer_space(),
+ HeapObjectIterator old_pointer_it(HEAP->old_pointer_space(),
&OverflowObjectSize);
- ScanOverflowedObjects(&old_pointer_it);
- if (marking_stack.is_full()) return;
+ OverflowedObjectsScanner::ScanOverflowedObjects(this, &old_pointer_it);
+ if (marking_stack_.is_full()) return;
- HeapObjectIterator old_data_it(Heap::old_data_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&old_data_it);
- if (marking_stack.is_full()) return;
+ HeapObjectIterator old_data_it(HEAP->old_data_space(), &OverflowObjectSize);
+ OverflowedObjectsScanner::ScanOverflowedObjects(this, &old_data_it);
+ if (marking_stack_.is_full()) return;
- HeapObjectIterator code_it(Heap::code_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&code_it);
- if (marking_stack.is_full()) return;
+ HeapObjectIterator code_it(HEAP->code_space(), &OverflowObjectSize);
+ OverflowedObjectsScanner::ScanOverflowedObjects(this, &code_it);
+ if (marking_stack_.is_full()) return;
- HeapObjectIterator map_it(Heap::map_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&map_it);
- if (marking_stack.is_full()) return;
+ HeapObjectIterator map_it(HEAP->map_space(), &OverflowObjectSize);
+ OverflowedObjectsScanner::ScanOverflowedObjects(this, &map_it);
+ if (marking_stack_.is_full()) return;
- HeapObjectIterator cell_it(Heap::cell_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&cell_it);
- if (marking_stack.is_full()) return;
+ HeapObjectIterator cell_it(HEAP->cell_space(), &OverflowObjectSize);
+ OverflowedObjectsScanner::ScanOverflowedObjects(this, &cell_it);
+ if (marking_stack_.is_full()) return;
- LargeObjectIterator lo_it(Heap::lo_space(), &OverflowObjectSize);
- ScanOverflowedObjects(&lo_it);
- if (marking_stack.is_full()) return;
+ LargeObjectIterator lo_it(HEAP->lo_space(), &OverflowObjectSize);
+ OverflowedObjectsScanner::ScanOverflowedObjects(this, &lo_it);
+ if (marking_stack_.is_full()) return;
- marking_stack.clear_overflowed();
+ marking_stack_.clear_overflowed();
}
@@ -1269,19 +1342,20 @@ void MarkCompactCollector::RefillMarkingStack() {
// objects in the heap.
void MarkCompactCollector::ProcessMarkingStack() {
EmptyMarkingStack();
- while (marking_stack.overflowed()) {
+ while (marking_stack_.overflowed()) {
RefillMarkingStack();
EmptyMarkingStack();
}
}
-void MarkCompactCollector::ProcessObjectGroups() {
+void MarkCompactCollector::ProcessExternalMarking() {
bool work_to_do = true;
- ASSERT(marking_stack.is_empty());
+ ASSERT(marking_stack_.is_empty());
while (work_to_do) {
MarkObjectGroups();
- work_to_do = !marking_stack.is_empty();
+ MarkImplicitRefGroups();
+ work_to_do = !marking_stack_.is_empty();
ProcessMarkingStack();
}
}
@@ -1292,7 +1366,7 @@ void MarkCompactCollector::MarkLiveObjects() {
// The recursive GC marker detects when it is nearing stack overflow,
// and switches to a different marking system. JS interrupts interfere
// with the C stack limit check.
- PostponeInterruptsScope postpone;
+ PostponeInterruptsScope postpone(heap_->isolate());
#ifdef DEBUG
ASSERT(state_ == PREPARE_GC);
@@ -1300,21 +1374,20 @@ void MarkCompactCollector::MarkLiveObjects() {
#endif
// The to space contains live objects, the from space is used as a marking
// stack.
- marking_stack.Initialize(Heap::new_space()->FromSpaceLow(),
- Heap::new_space()->FromSpaceHigh());
+ marking_stack_.Initialize(heap_->new_space()->FromSpaceLow(),
+ heap_->new_space()->FromSpaceHigh());
- ASSERT(!marking_stack.overflowed());
+ ASSERT(!marking_stack_.overflowed());
PrepareForCodeFlushing();
- RootMarkingVisitor root_visitor;
+ RootMarkingVisitor root_visitor(heap_);
MarkRoots(&root_visitor);
// The objects reachable from the roots are marked, yet unreachable
- // objects are unmarked. Mark objects reachable from object groups
- // containing at least one marked object, and continue until no new
- // objects are reachable from the object groups.
- ProcessObjectGroups();
+ // objects are unmarked. Mark objects reachable due to host
+ // application specific logic.
+ ProcessExternalMarking();
// The objects reachable from the roots or object groups are marked,
// yet unreachable objects are unmarked. Mark objects reachable
@@ -1322,61 +1395,65 @@ void MarkCompactCollector::MarkLiveObjects() {
//
// First we identify nonlive weak handles and mark them as pending
// destruction.
- GlobalHandles::IdentifyWeakHandles(&IsUnmarkedHeapObject);
+ heap_->isolate()->global_handles()->IdentifyWeakHandles(
+ &IsUnmarkedHeapObject);
// Then we mark the objects and process the transitive closure.
- GlobalHandles::IterateWeakRoots(&root_visitor);
- while (marking_stack.overflowed()) {
+ heap_->isolate()->global_handles()->IterateWeakRoots(&root_visitor);
+ while (marking_stack_.overflowed()) {
RefillMarkingStack();
EmptyMarkingStack();
}
- // Repeat the object groups to mark unmarked groups reachable from the
- // weak roots.
- ProcessObjectGroups();
+ // Repeat host application specific marking to mark unmarked objects
+ // reachable from the weak roots.
+ ProcessExternalMarking();
// Prune the symbol table removing all symbols only pointed to by the
// symbol table. Cannot use symbol_table() here because the symbol
// table is marked.
- SymbolTable* symbol_table = Heap::raw_unchecked_symbol_table();
+ SymbolTable* symbol_table = heap_->raw_unchecked_symbol_table();
SymbolTableCleaner v;
symbol_table->IterateElements(&v);
symbol_table->ElementsRemoved(v.PointersRemoved());
- ExternalStringTable::Iterate(&v);
- ExternalStringTable::CleanUp();
+ heap_->external_string_table_.Iterate(&v);
+ heap_->external_string_table_.CleanUp();
// Process the weak references.
MarkCompactWeakObjectRetainer mark_compact_object_retainer;
- Heap::ProcessWeakReferences(&mark_compact_object_retainer);
+ heap_->ProcessWeakReferences(&mark_compact_object_retainer);
// Remove object groups after marking phase.
- GlobalHandles::RemoveObjectGroups();
+ heap_->isolate()->global_handles()->RemoveObjectGroups();
+ heap_->isolate()->global_handles()->RemoveImplicitRefGroups();
// Flush code from collected candidates.
- FlushCode::ProcessCandidates();
+ if (is_code_flushing_enabled()) {
+ code_flusher_->ProcessCandidates();
+ }
// Clean up dead objects from the runtime profiler.
- RuntimeProfiler::RemoveDeadSamples();
+ heap_->isolate()->runtime_profiler()->RemoveDeadSamples();
}
#ifdef DEBUG
void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
live_bytes_ += obj->Size();
- if (Heap::new_space()->Contains(obj)) {
+ if (HEAP->new_space()->Contains(obj)) {
live_young_objects_size_ += obj->Size();
- } else if (Heap::map_space()->Contains(obj)) {
+ } else if (HEAP->map_space()->Contains(obj)) {
ASSERT(obj->IsMap());
live_map_objects_size_ += obj->Size();
- } else if (Heap::cell_space()->Contains(obj)) {
+ } else if (HEAP->cell_space()->Contains(obj)) {
ASSERT(obj->IsJSGlobalPropertyCell());
live_cell_objects_size_ += obj->Size();
- } else if (Heap::old_pointer_space()->Contains(obj)) {
+ } else if (HEAP->old_pointer_space()->Contains(obj)) {
live_old_pointer_objects_size_ += obj->Size();
- } else if (Heap::old_data_space()->Contains(obj)) {
+ } else if (HEAP->old_data_space()->Contains(obj)) {
live_old_data_objects_size_ += obj->Size();
- } else if (Heap::code_space()->Contains(obj)) {
+ } else if (HEAP->code_space()->Contains(obj)) {
live_code_objects_size_ += obj->Size();
- } else if (Heap::lo_space()->Contains(obj)) {
+ } else if (HEAP->lo_space()->Contains(obj)) {
live_lo_objects_size_ += obj->Size();
} else {
UNREACHABLE();
@@ -1392,7 +1469,7 @@ void MarkCompactCollector::SweepLargeObjectSpace() {
compacting_collection_ ? ENCODE_FORWARDING_ADDRESSES : SWEEP_SPACES;
#endif
// Deallocate unmarked objects and clear marked bits for marked objects.
- Heap::lo_space()->FreeUnmarkedObjects();
+ HEAP->lo_space()->FreeUnmarkedObjects();
}
@@ -1405,7 +1482,7 @@ bool MarkCompactCollector::SafeIsMap(HeapObject* object) {
void MarkCompactCollector::ClearNonLiveTransitions() {
- HeapObjectIterator map_iterator(Heap::map_space(), &SizeOfMarkedObject);
+ HeapObjectIterator map_iterator(HEAP->map_space(), &SizeOfMarkedObject);
// Iterate over the map space, setting map transitions that go from
// a marked map to an unmarked map to null transitions. At the same time,
// set all the prototype fields of maps back to their original value,
@@ -1455,7 +1532,7 @@ void MarkCompactCollector::ClearNonLiveTransitions() {
// This test will always be false on the first iteration.
if (on_dead_path && current->IsMarked()) {
on_dead_path = false;
- current->ClearNonLiveTransitions(real_prototype);
+ current->ClearNonLiveTransitions(heap_, real_prototype);
}
*HeapObject::RawField(current, Map::kPrototypeOffset) =
real_prototype;
@@ -1517,20 +1594,21 @@ void EncodeFreeRegion(Address free_start, int free_size) {
// Try to promote all objects in new space. Heap numbers and sequential
// strings are promoted to the code space, large objects to large object space,
// and all others to the old space.
-inline MaybeObject* MCAllocateFromNewSpace(HeapObject* object,
+inline MaybeObject* MCAllocateFromNewSpace(Heap* heap,
+ HeapObject* object,
int object_size) {
MaybeObject* forwarded;
- if (object_size > Heap::MaxObjectSizeInPagedSpace()) {
+ if (object_size > heap->MaxObjectSizeInPagedSpace()) {
forwarded = Failure::Exception();
} else {
- OldSpace* target_space = Heap::TargetSpace(object);
- ASSERT(target_space == Heap::old_pointer_space() ||
- target_space == Heap::old_data_space());
+ OldSpace* target_space = heap->TargetSpace(object);
+ ASSERT(target_space == heap->old_pointer_space() ||
+ target_space == heap->old_data_space());
forwarded = target_space->MCAllocateRaw(object_size);
}
Object* result;
if (!forwarded->ToObject(&result)) {
- result = Heap::new_space()->MCAllocateRaw(object_size)->ToObjectUnchecked();
+ result = heap->new_space()->MCAllocateRaw(object_size)->ToObjectUnchecked();
}
return result;
}
@@ -1538,48 +1616,53 @@ inline MaybeObject* MCAllocateFromNewSpace(HeapObject* object,
// Allocation functions for the paged spaces call the space's MCAllocateRaw.
MUST_USE_RESULT inline MaybeObject* MCAllocateFromOldPointerSpace(
+ Heap *heap,
HeapObject* ignore,
int object_size) {
- return Heap::old_pointer_space()->MCAllocateRaw(object_size);
+ return heap->old_pointer_space()->MCAllocateRaw(object_size);
}
MUST_USE_RESULT inline MaybeObject* MCAllocateFromOldDataSpace(
+ Heap* heap,
HeapObject* ignore,
int object_size) {
- return Heap::old_data_space()->MCAllocateRaw(object_size);
+ return heap->old_data_space()->MCAllocateRaw(object_size);
}
MUST_USE_RESULT inline MaybeObject* MCAllocateFromCodeSpace(
+ Heap* heap,
HeapObject* ignore,
int object_size) {
- return Heap::code_space()->MCAllocateRaw(object_size);
+ return heap->code_space()->MCAllocateRaw(object_size);
}
MUST_USE_RESULT inline MaybeObject* MCAllocateFromMapSpace(
+ Heap* heap,
HeapObject* ignore,
int object_size) {
- return Heap::map_space()->MCAllocateRaw(object_size);
+ return heap->map_space()->MCAllocateRaw(object_size);
}
-MUST_USE_RESULT inline MaybeObject* MCAllocateFromCellSpace(HeapObject* ignore,
- int object_size) {
- return Heap::cell_space()->MCAllocateRaw(object_size);
+MUST_USE_RESULT inline MaybeObject* MCAllocateFromCellSpace(
+ Heap* heap, HeapObject* ignore, int object_size) {
+ return heap->cell_space()->MCAllocateRaw(object_size);
}
// The forwarding address is encoded at the same offset as the current
// to-space object, but in from space.
-inline void EncodeForwardingAddressInNewSpace(HeapObject* old_object,
+inline void EncodeForwardingAddressInNewSpace(Heap* heap,
+ HeapObject* old_object,
int object_size,
Object* new_object,
int* ignored) {
int offset =
- Heap::new_space()->ToSpaceOffsetForAddress(old_object->address());
- Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset) =
+ heap->new_space()->ToSpaceOffsetForAddress(old_object->address());
+ Memory::Address_at(heap->new_space()->FromSpaceLow() + offset) =
HeapObject::cast(new_object)->address();
}
@@ -1587,7 +1670,8 @@ inline void EncodeForwardingAddressInNewSpace(HeapObject* old_object,
// The forwarding address is encoded in the map pointer of the object as an
// offset (in terms of live bytes) from the address of the first live object
// in the page.
-inline void EncodeForwardingAddressInPagedSpace(HeapObject* old_object,
+inline void EncodeForwardingAddressInPagedSpace(Heap* heap,
+ HeapObject* old_object,
int object_size,
Object* new_object,
int* offset) {
@@ -1620,7 +1704,8 @@ inline void IgnoreNonLiveObject(HeapObject* object) {}
template<MarkCompactCollector::AllocationFunction Alloc,
MarkCompactCollector::EncodingFunction Encode,
MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive>
-inline void EncodeForwardingAddressesInRange(Address start,
+inline void EncodeForwardingAddressesInRange(MarkCompactCollector* collector,
+ Address start,
Address end,
int* offset) {
// The start address of the current free region while sweeping the space.
@@ -1640,12 +1725,12 @@ inline void EncodeForwardingAddressesInRange(Address start,
HeapObject* object = HeapObject::FromAddress(current);
if (object->IsMarked()) {
object->ClearMark();
- MarkCompactCollector::tracer()->decrement_marked_count();
+ collector->tracer()->decrement_marked_count();
object_size = object->Size();
- // Allocation cannot fail, because we are compacting the space.
- Object* forwarded = Alloc(object, object_size)->ToObjectUnchecked();
- Encode(object, object_size, forwarded, offset);
+ Object* forwarded =
+ Alloc(collector->heap(), object, object_size)->ToObjectUnchecked();
+ Encode(collector->heap(), object, object_size, forwarded, offset);
#ifdef DEBUG
if (FLAG_gc_verbose) {
@@ -1681,8 +1766,9 @@ void MarkCompactCollector::EncodeForwardingAddressesInNewSpace() {
EncodeForwardingAddressesInRange<MCAllocateFromNewSpace,
EncodeForwardingAddressInNewSpace,
IgnoreNonLiveObject>(
- Heap::new_space()->bottom(),
- Heap::new_space()->top(),
+ this,
+ heap_->new_space()->bottom(),
+ heap_->new_space()->top(),
&ignored);
}
@@ -1701,6 +1787,7 @@ void MarkCompactCollector::EncodeForwardingAddressesInPagedSpace(
EncodeForwardingAddressesInRange<Alloc,
EncodeForwardingAddressInPagedSpace,
ProcessNonLive>(
+ this,
p->ObjectAreaStart(),
p->AllocationTop(),
&offset);
@@ -1718,14 +1805,15 @@ void MarkCompactCollector::EncodeForwardingAddressesInPagedSpace(
// to encounter pointers to dead objects during traversal of dirty regions we
// should clear them to avoid encountering them during next dirty regions
// iteration.
-static void MigrateObject(Address dst,
+static void MigrateObject(Heap* heap,
+ Address dst,
Address src,
int size,
bool to_old_space) {
if (to_old_space) {
- Heap::CopyBlockToOldSpaceAndUpdateRegionMarks(dst, src, size);
+ heap->CopyBlockToOldSpaceAndUpdateRegionMarks(dst, src, size);
} else {
- Heap::CopyBlock(dst, src, size);
+ heap->CopyBlock(dst, src, size);
}
Memory::Address_at(src) = dst;
@@ -1735,14 +1823,14 @@ static void MigrateObject(Address dst,
class StaticPointersToNewGenUpdatingVisitor : public
StaticNewSpaceVisitor<StaticPointersToNewGenUpdatingVisitor> {
public:
- static inline void VisitPointer(Object** p) {
+ static inline void VisitPointer(Heap* heap, Object** p) {
if (!(*p)->IsHeapObject()) return;
HeapObject* obj = HeapObject::cast(*p);
Address old_addr = obj->address();
- if (Heap::new_space()->Contains(obj)) {
- ASSERT(Heap::InFromSpace(*p));
+ if (heap->new_space()->Contains(obj)) {
+ ASSERT(heap->InFromSpace(*p));
*p = HeapObject::FromAddress(Memory::Address_at(old_addr));
}
}
@@ -1753,13 +1841,15 @@ class StaticPointersToNewGenUpdatingVisitor : public
// It does not expect to encounter pointers to dead objects.
class PointersToNewGenUpdatingVisitor: public ObjectVisitor {
public:
+ explicit PointersToNewGenUpdatingVisitor(Heap* heap) : heap_(heap) { }
+
void VisitPointer(Object** p) {
- StaticPointersToNewGenUpdatingVisitor::VisitPointer(p);
+ StaticPointersToNewGenUpdatingVisitor::VisitPointer(heap_, p);
}
void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) {
- StaticPointersToNewGenUpdatingVisitor::VisitPointer(p);
+ StaticPointersToNewGenUpdatingVisitor::VisitPointer(heap_, p);
}
}
@@ -1779,6 +1869,8 @@ class PointersToNewGenUpdatingVisitor: public ObjectVisitor {
VisitPointer(&target);
rinfo->set_call_address(Code::cast(target)->instruction_start());
}
+ private:
+ Heap* heap_;
};
@@ -1789,7 +1881,7 @@ static void UpdatePointerToNewGen(HeapObject** p) {
if (!(*p)->IsHeapObject()) return;
Address old_addr = (*p)->address();
- ASSERT(Heap::InFromSpace(*p));
+ ASSERT(HEAP->InFromSpace(*p));
Address new_addr = Memory::Address_at(old_addr);
@@ -1803,39 +1895,42 @@ static void UpdatePointerToNewGen(HeapObject** p) {
}
-static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Object **p) {
+static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
+ Object** p) {
Address old_addr = HeapObject::cast(*p)->address();
Address new_addr = Memory::Address_at(old_addr);
return String::cast(HeapObject::FromAddress(new_addr));
}
-static bool TryPromoteObject(HeapObject* object, int object_size) {
+static bool TryPromoteObject(Heap* heap, HeapObject* object, int object_size) {
Object* result;
- if (object_size > Heap::MaxObjectSizeInPagedSpace()) {
+ if (object_size > heap->MaxObjectSizeInPagedSpace()) {
MaybeObject* maybe_result =
- Heap::lo_space()->AllocateRawFixedArray(object_size);
+ heap->lo_space()->AllocateRawFixedArray(object_size);
if (maybe_result->ToObject(&result)) {
HeapObject* target = HeapObject::cast(result);
- MigrateObject(target->address(), object->address(), object_size, true);
- MarkCompactCollector::tracer()->
+ MigrateObject(heap, target->address(), object->address(), object_size,
+ true);
+ heap->mark_compact_collector()->tracer()->
increment_promoted_objects_size(object_size);
return true;
}
} else {
- OldSpace* target_space = Heap::TargetSpace(object);
+ OldSpace* target_space = heap->TargetSpace(object);
- ASSERT(target_space == Heap::old_pointer_space() ||
- target_space == Heap::old_data_space());
+ ASSERT(target_space == heap->old_pointer_space() ||
+ target_space == heap->old_data_space());
MaybeObject* maybe_result = target_space->AllocateRaw(object_size);
if (maybe_result->ToObject(&result)) {
HeapObject* target = HeapObject::cast(result);
- MigrateObject(target->address(),
+ MigrateObject(heap,
+ target->address(),
object->address(),
object_size,
- target_space == Heap::old_pointer_space());
- MarkCompactCollector::tracer()->
+ target_space == heap->old_pointer_space());
+ heap->mark_compact_collector()->tracer()->
increment_promoted_objects_size(object_size);
return true;
}
@@ -1845,8 +1940,8 @@ static bool TryPromoteObject(HeapObject* object, int object_size) {
}
-static void SweepNewSpace(NewSpace* space) {
- Heap::CheckNewSpaceExpansionCriteria();
+static void SweepNewSpace(Heap* heap, NewSpace* space) {
+ heap->CheckNewSpaceExpansionCriteria();
Address from_bottom = space->bottom();
Address from_top = space->top();
@@ -1866,13 +1961,13 @@ static void SweepNewSpace(NewSpace* space) {
if (object->IsMarked()) {
object->ClearMark();
- MarkCompactCollector::tracer()->decrement_marked_count();
+ heap->mark_compact_collector()->tracer()->decrement_marked_count();
size = object->Size();
survivors_size += size;
// Aggressively promote young survivors to the old space.
- if (TryPromoteObject(object, size)) {
+ if (TryPromoteObject(heap, object, size)) {
continue;
}
@@ -1880,7 +1975,8 @@ static void SweepNewSpace(NewSpace* space) {
// Allocation cannot fail at this point: semispaces are of equal size.
Object* target = space->AllocateRaw(size)->ToObjectUnchecked();
- MigrateObject(HeapObject::cast(target)->address(),
+ MigrateObject(heap,
+ HeapObject::cast(target)->address(),
current,
size,
false);
@@ -1894,7 +1990,7 @@ static void SweepNewSpace(NewSpace* space) {
}
// Second pass: find pointers to new space and update them.
- PointersToNewGenUpdatingVisitor updating_visitor;
+ PointersToNewGenUpdatingVisitor updating_visitor(heap);
// Update pointers in to space.
Address current = space->bottom();
@@ -1906,19 +2002,19 @@ static void SweepNewSpace(NewSpace* space) {
}
// Update roots.
- Heap::IterateRoots(&updating_visitor, VISIT_ALL_IN_SCAVENGE);
+ heap->IterateRoots(&updating_visitor, VISIT_ALL_IN_SCAVENGE);
LiveObjectList::IterateElements(&updating_visitor);
// Update pointers in old spaces.
- Heap::IterateDirtyRegions(Heap::old_pointer_space(),
+ heap->IterateDirtyRegions(heap->old_pointer_space(),
&Heap::IteratePointersInDirtyRegion,
&UpdatePointerToNewGen,
- Heap::WATERMARK_SHOULD_BE_VALID);
+ heap->WATERMARK_SHOULD_BE_VALID);
- Heap::lo_space()->IterateDirtyRegions(&UpdatePointerToNewGen);
+ heap->lo_space()->IterateDirtyRegions(&UpdatePointerToNewGen);
// Update pointers from cells.
- HeapObjectIterator cell_iterator(Heap::cell_space());
+ HeapObjectIterator cell_iterator(heap->cell_space());
for (HeapObject* cell = cell_iterator.next();
cell != NULL;
cell = cell_iterator.next()) {
@@ -1931,22 +2027,22 @@ static void SweepNewSpace(NewSpace* space) {
}
// Update pointer from the global contexts list.
- updating_visitor.VisitPointer(Heap::global_contexts_list_address());
+ updating_visitor.VisitPointer(heap->global_contexts_list_address());
// Update pointers from external string table.
- Heap::UpdateNewSpaceReferencesInExternalStringTable(
+ heap->UpdateNewSpaceReferencesInExternalStringTable(
&UpdateNewSpaceReferenceInExternalStringTableEntry);
// All pointers were updated. Update auxiliary allocation info.
- Heap::IncrementYoungSurvivorsCounter(survivors_size);
+ heap->IncrementYoungSurvivorsCounter(survivors_size);
space->set_age_mark(space->top());
// Update JSFunction pointers from the runtime profiler.
- RuntimeProfiler::UpdateSamplesAfterScavenge();
+ heap->isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
}
-static void SweepSpace(PagedSpace* space) {
+static void SweepSpace(Heap* heap, PagedSpace* space) {
PageIterator it(space, PageIterator::PAGES_IN_USE);
// During sweeping of paged space we are trying to find longest sequences
@@ -1984,7 +2080,7 @@ static void SweepSpace(PagedSpace* space) {
object = HeapObject::FromAddress(current);
if (object->IsMarked()) {
object->ClearMark();
- MarkCompactCollector::tracer()->decrement_marked_count();
+ heap->mark_compact_collector()->tracer()->decrement_marked_count();
if (!is_previous_alive) { // Transition from free to live.
space->DeallocateBlock(free_start,
@@ -1993,7 +2089,7 @@ static void SweepSpace(PagedSpace* space) {
is_previous_alive = true;
}
} else {
- MarkCompactCollector::ReportDeleteIfNeeded(object);
+ heap->mark_compact_collector()->ReportDeleteIfNeeded(object);
if (is_previous_alive) { // Transition from live to free.
free_start = current;
is_previous_alive = false;
@@ -2093,24 +2189,24 @@ void MarkCompactCollector::EncodeForwardingAddresses() {
// Objects in the active semispace of the young generation may be
// relocated to the inactive semispace (if not promoted). Set the
// relocation info to the beginning of the inactive semispace.
- Heap::new_space()->MCResetRelocationInfo();
+ heap_->new_space()->MCResetRelocationInfo();
// Compute the forwarding pointers in each space.
EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldPointerSpace,
ReportDeleteIfNeeded>(
- Heap::old_pointer_space());
+ heap_->old_pointer_space());
EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldDataSpace,
IgnoreNonLiveObject>(
- Heap::old_data_space());
+ heap_->old_data_space());
EncodeForwardingAddressesInPagedSpace<MCAllocateFromCodeSpace,
ReportDeleteIfNeeded>(
- Heap::code_space());
+ heap_->code_space());
EncodeForwardingAddressesInPagedSpace<MCAllocateFromCellSpace,
IgnoreNonLiveObject>(
- Heap::cell_space());
+ heap_->cell_space());
// Compute new space next to last after the old and code spaces have been
@@ -2122,25 +2218,25 @@ void MarkCompactCollector::EncodeForwardingAddresses() {
// non-live map pointers to get the sizes of non-live objects.
EncodeForwardingAddressesInPagedSpace<MCAllocateFromMapSpace,
IgnoreNonLiveObject>(
- Heap::map_space());
+ heap_->map_space());
// Write relocation info to the top page, so we can use it later. This is
// done after promoting objects from the new space so we get the correct
// allocation top.
- Heap::old_pointer_space()->MCWriteRelocationInfoToPage();
- Heap::old_data_space()->MCWriteRelocationInfoToPage();
- Heap::code_space()->MCWriteRelocationInfoToPage();
- Heap::map_space()->MCWriteRelocationInfoToPage();
- Heap::cell_space()->MCWriteRelocationInfoToPage();
+ heap_->old_pointer_space()->MCWriteRelocationInfoToPage();
+ heap_->old_data_space()->MCWriteRelocationInfoToPage();
+ heap_->code_space()->MCWriteRelocationInfoToPage();
+ heap_->map_space()->MCWriteRelocationInfoToPage();
+ heap_->cell_space()->MCWriteRelocationInfoToPage();
}
class MapIterator : public HeapObjectIterator {
public:
- MapIterator() : HeapObjectIterator(Heap::map_space(), &SizeCallback) { }
+ MapIterator() : HeapObjectIterator(HEAP->map_space(), &SizeCallback) { }
explicit MapIterator(Address start)
- : HeapObjectIterator(Heap::map_space(), start, &SizeCallback) { }
+ : HeapObjectIterator(HEAP->map_space(), start, &SizeCallback) { }
private:
static int SizeCallback(HeapObject* unused) {
@@ -2152,9 +2248,10 @@ class MapIterator : public HeapObjectIterator {
class MapCompact {
public:
- explicit MapCompact(int live_maps)
- : live_maps_(live_maps),
- to_evacuate_start_(Heap::map_space()->TopAfterCompaction(live_maps)),
+ explicit MapCompact(Heap* heap, int live_maps)
+ : heap_(heap),
+ live_maps_(live_maps),
+ to_evacuate_start_(heap->map_space()->TopAfterCompaction(live_maps)),
map_to_evacuate_it_(to_evacuate_start_),
first_map_to_evacuate_(
reinterpret_cast<Map*>(HeapObject::FromAddress(to_evacuate_start_))) {
@@ -2175,37 +2272,39 @@ class MapCompact {
}
void UpdateMapPointersInRoots() {
- Heap::IterateRoots(&map_updating_visitor_, VISIT_ONLY_STRONG);
- GlobalHandles::IterateWeakRoots(&map_updating_visitor_);
- LiveObjectList::IterateElements(&map_updating_visitor_);
+ MapUpdatingVisitor map_updating_visitor;
+ heap_->IterateRoots(&map_updating_visitor, VISIT_ONLY_STRONG);
+ heap_->isolate()->global_handles()->IterateWeakRoots(&map_updating_visitor);
+ LiveObjectList::IterateElements(&map_updating_visitor);
}
void UpdateMapPointersInPagedSpace(PagedSpace* space) {
- ASSERT(space != Heap::map_space());
+ ASSERT(space != heap_->map_space());
PageIterator it(space, PageIterator::PAGES_IN_USE);
while (it.has_next()) {
Page* p = it.next();
- UpdateMapPointersInRange(p->ObjectAreaStart(), p->AllocationTop());
+ UpdateMapPointersInRange(heap_, p->ObjectAreaStart(), p->AllocationTop());
}
}
void UpdateMapPointersInNewSpace() {
- NewSpace* space = Heap::new_space();
- UpdateMapPointersInRange(space->bottom(), space->top());
+ NewSpace* space = heap_->new_space();
+ UpdateMapPointersInRange(heap_, space->bottom(), space->top());
}
void UpdateMapPointersInLargeObjectSpace() {
- LargeObjectIterator it(Heap::lo_space());
+ LargeObjectIterator it(heap_->lo_space());
for (HeapObject* obj = it.next(); obj != NULL; obj = it.next())
- UpdateMapPointersInObject(obj);
+ UpdateMapPointersInObject(heap_, obj);
}
void Finish() {
- Heap::map_space()->FinishCompaction(to_evacuate_start_, live_maps_);
+ heap_->map_space()->FinishCompaction(to_evacuate_start_, live_maps_);
}
private:
+ Heap* heap_;
int live_maps_;
Address to_evacuate_start_;
MapIterator vacant_map_it_;
@@ -2215,6 +2314,8 @@ class MapCompact {
// Helper class for updating map pointers in HeapObjects.
class MapUpdatingVisitor: public ObjectVisitor {
public:
+ MapUpdatingVisitor() {}
+
void VisitPointer(Object** p) {
UpdateMapPointer(p);
}
@@ -2237,8 +2338,6 @@ class MapCompact {
}
};
- static MapUpdatingVisitor map_updating_visitor_;
-
static Map* NextMap(MapIterator* it, HeapObject* last, bool live) {
while (true) {
HeapObject* next = it->next();
@@ -2272,9 +2371,8 @@ class MapCompact {
ASSERT(Map::kSize % 4 == 0);
- Heap::CopyBlockToOldSpaceAndUpdateRegionMarks(vacant_map->address(),
- map_to_evacuate->address(),
- Map::kSize);
+ map_to_evacuate->heap()->CopyBlockToOldSpaceAndUpdateRegionMarks(
+ vacant_map->address(), map_to_evacuate->address(), Map::kSize);
ASSERT(vacant_map->IsMap()); // Due to memcpy above.
@@ -2294,15 +2392,15 @@ class MapCompact {
return new_map;
}
- static int UpdateMapPointersInObject(HeapObject* obj) {
+ static int UpdateMapPointersInObject(Heap* heap, HeapObject* obj) {
ASSERT(!obj->IsMarked());
Map* map = obj->map();
- ASSERT(Heap::map_space()->Contains(map));
+ ASSERT(heap->map_space()->Contains(map));
MapWord map_word = map->map_word();
ASSERT(!map_word.IsMarked());
if (map_word.IsOverflowed()) {
Map* new_map = GetForwardedMap(map_word);
- ASSERT(Heap::map_space()->Contains(new_map));
+ ASSERT(heap->map_space()->Contains(new_map));
obj->set_map(new_map);
#ifdef DEBUG
@@ -2316,16 +2414,17 @@ class MapCompact {
}
int size = obj->SizeFromMap(map);
- obj->IterateBody(map->instance_type(), size, &map_updating_visitor_);
+ MapUpdatingVisitor map_updating_visitor;
+ obj->IterateBody(map->instance_type(), size, &map_updating_visitor);
return size;
}
- static void UpdateMapPointersInRange(Address start, Address end) {
+ static void UpdateMapPointersInRange(Heap* heap, Address start, Address end) {
HeapObject* object;
int size;
for (Address current = start; current < end; current += size) {
object = HeapObject::FromAddress(current);
- size = UpdateMapPointersInObject(object);
+ size = UpdateMapPointersInObject(heap, object);
ASSERT(size > 0);
}
}
@@ -2342,8 +2441,6 @@ class MapCompact {
#endif
};
-MapCompact::MapUpdatingVisitor MapCompact::map_updating_visitor_;
-
void MarkCompactCollector::SweepSpaces() {
GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP);
@@ -2355,26 +2452,26 @@ void MarkCompactCollector::SweepSpaces() {
// the map space last because freeing non-live maps overwrites them and
// the other spaces rely on possibly non-live maps to get the sizes for
// non-live objects.
- SweepSpace(Heap::old_pointer_space());
- SweepSpace(Heap::old_data_space());
- SweepSpace(Heap::code_space());
- SweepSpace(Heap::cell_space());
+ SweepSpace(heap_, heap_->old_pointer_space());
+ SweepSpace(heap_, heap_->old_data_space());
+ SweepSpace(heap_, heap_->code_space());
+ SweepSpace(heap_, heap_->cell_space());
{ GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE);
- SweepNewSpace(Heap::new_space());
+ SweepNewSpace(heap_, heap_->new_space());
}
- SweepSpace(Heap::map_space());
+ SweepSpace(heap_, heap_->map_space());
- Heap::IterateDirtyRegions(Heap::map_space(),
- &Heap::IteratePointersInDirtyMapsRegion,
- &UpdatePointerToNewGen,
- Heap::WATERMARK_SHOULD_BE_VALID);
+ heap_->IterateDirtyRegions(heap_->map_space(),
+ &heap_->IteratePointersInDirtyMapsRegion,
+ &UpdatePointerToNewGen,
+ heap_->WATERMARK_SHOULD_BE_VALID);
- intptr_t live_maps_size = Heap::map_space()->Size();
+ intptr_t live_maps_size = heap_->map_space()->Size();
int live_maps = static_cast<int>(live_maps_size / Map::kSize);
ASSERT(live_map_objects_size_ == live_maps_size);
- if (Heap::map_space()->NeedsCompaction(live_maps)) {
- MapCompact map_compact(live_maps);
+ if (heap_->map_space()->NeedsCompaction(live_maps)) {
+ MapCompact map_compact(heap_, live_maps);
map_compact.CompactMaps();
map_compact.UpdateMapPointersInRoots();
@@ -2382,7 +2479,7 @@ void MarkCompactCollector::SweepSpaces() {
PagedSpaces spaces;
for (PagedSpace* space = spaces.next();
space != NULL; space = spaces.next()) {
- if (space == Heap::map_space()) continue;
+ if (space == heap_->map_space()) continue;
map_compact.UpdateMapPointersInPagedSpace(space);
}
map_compact.UpdateMapPointersInNewSpace();
@@ -2401,7 +2498,7 @@ void MarkCompactCollector::SweepSpaces() {
int MarkCompactCollector::IterateLiveObjectsInRange(
Address start,
Address end,
- HeapObjectCallback size_func) {
+ LiveObjectCallback size_func) {
int live_objects_size = 0;
Address current = start;
while (current < end) {
@@ -2411,7 +2508,7 @@ int MarkCompactCollector::IterateLiveObjectsInRange(
} else if (encoded_map == kMultiFreeEncoding) {
current += Memory::int_at(current + kIntSize);
} else {
- int size = size_func(HeapObject::FromAddress(current));
+ int size = (this->*size_func)(HeapObject::FromAddress(current));
current += size;
live_objects_size += size;
}
@@ -2420,15 +2517,15 @@ int MarkCompactCollector::IterateLiveObjectsInRange(
}
-int MarkCompactCollector::IterateLiveObjects(NewSpace* space,
- HeapObjectCallback size_f) {
+int MarkCompactCollector::IterateLiveObjects(
+ NewSpace* space, LiveObjectCallback size_f) {
ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
return IterateLiveObjectsInRange(space->bottom(), space->top(), size_f);
}
-int MarkCompactCollector::IterateLiveObjects(PagedSpace* space,
- HeapObjectCallback size_f) {
+int MarkCompactCollector::IterateLiveObjects(
+ PagedSpace* space, LiveObjectCallback size_f) {
ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
int total = 0;
PageIterator it(space, PageIterator::PAGES_IN_USE);
@@ -2448,6 +2545,8 @@ int MarkCompactCollector::IterateLiveObjects(PagedSpace* space,
// Helper class for updating pointers in HeapObjects.
class UpdatingVisitor: public ObjectVisitor {
public:
+ explicit UpdatingVisitor(Heap* heap) : heap_(heap) {}
+
void VisitPointer(Object** p) {
UpdatePointer(p);
}
@@ -2483,27 +2582,27 @@ class UpdatingVisitor: public ObjectVisitor {
HeapObject* obj = HeapObject::cast(*p);
Address old_addr = obj->address();
Address new_addr;
- ASSERT(!Heap::InFromSpace(obj));
+ ASSERT(!heap_->InFromSpace(obj));
- if (Heap::new_space()->Contains(obj)) {
+ if (heap_->new_space()->Contains(obj)) {
Address forwarding_pointer_addr =
- Heap::new_space()->FromSpaceLow() +
- Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
+ heap_->new_space()->FromSpaceLow() +
+ heap_->new_space()->ToSpaceOffsetForAddress(old_addr);
new_addr = Memory::Address_at(forwarding_pointer_addr);
#ifdef DEBUG
- ASSERT(Heap::old_pointer_space()->Contains(new_addr) ||
- Heap::old_data_space()->Contains(new_addr) ||
- Heap::new_space()->FromSpaceContains(new_addr) ||
- Heap::lo_space()->Contains(HeapObject::FromAddress(new_addr)));
-
- if (Heap::new_space()->FromSpaceContains(new_addr)) {
- ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
- Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
+ ASSERT(heap_->old_pointer_space()->Contains(new_addr) ||
+ heap_->old_data_space()->Contains(new_addr) ||
+ heap_->new_space()->FromSpaceContains(new_addr) ||
+ heap_->lo_space()->Contains(HeapObject::FromAddress(new_addr)));
+
+ if (heap_->new_space()->FromSpaceContains(new_addr)) {
+ ASSERT(heap_->new_space()->FromSpaceOffsetForAddress(new_addr) <=
+ heap_->new_space()->ToSpaceOffsetForAddress(old_addr));
}
#endif
- } else if (Heap::lo_space()->Contains(obj)) {
+ } else if (heap_->lo_space()->Contains(obj)) {
// Don't move objects in the large object space.
return;
@@ -2532,6 +2631,8 @@ class UpdatingVisitor: public ObjectVisitor {
}
#endif
}
+
+ Heap* heap_;
};
@@ -2540,31 +2641,34 @@ void MarkCompactCollector::UpdatePointers() {
ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
state_ = UPDATE_POINTERS;
#endif
- UpdatingVisitor updating_visitor;
- RuntimeProfiler::UpdateSamplesAfterCompact(&updating_visitor);
- Heap::IterateRoots(&updating_visitor, VISIT_ONLY_STRONG);
- GlobalHandles::IterateWeakRoots(&updating_visitor);
+ UpdatingVisitor updating_visitor(heap_);
+ heap_->isolate()->runtime_profiler()->UpdateSamplesAfterCompact(
+ &updating_visitor);
+ heap_->IterateRoots(&updating_visitor, VISIT_ONLY_STRONG);
+ heap_->isolate()->global_handles()->IterateWeakRoots(&updating_visitor);
// Update the pointer to the head of the weak list of global contexts.
- updating_visitor.VisitPointer(&Heap::global_contexts_list_);
+ updating_visitor.VisitPointer(&heap_->global_contexts_list_);
LiveObjectList::IterateElements(&updating_visitor);
- int live_maps_size = IterateLiveObjects(Heap::map_space(),
- &UpdatePointersInOldObject);
- int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(),
- &UpdatePointersInOldObject);
- int live_data_olds_size = IterateLiveObjects(Heap::old_data_space(),
- &UpdatePointersInOldObject);
- int live_codes_size = IterateLiveObjects(Heap::code_space(),
- &UpdatePointersInOldObject);
- int live_cells_size = IterateLiveObjects(Heap::cell_space(),
- &UpdatePointersInOldObject);
- int live_news_size = IterateLiveObjects(Heap::new_space(),
- &UpdatePointersInNewObject);
+ int live_maps_size = IterateLiveObjects(
+ heap_->map_space(), &MarkCompactCollector::UpdatePointersInOldObject);
+ int live_pointer_olds_size = IterateLiveObjects(
+ heap_->old_pointer_space(),
+ &MarkCompactCollector::UpdatePointersInOldObject);
+ int live_data_olds_size = IterateLiveObjects(
+ heap_->old_data_space(),
+ &MarkCompactCollector::UpdatePointersInOldObject);
+ int live_codes_size = IterateLiveObjects(
+ heap_->code_space(), &MarkCompactCollector::UpdatePointersInOldObject);
+ int live_cells_size = IterateLiveObjects(
+ heap_->cell_space(), &MarkCompactCollector::UpdatePointersInOldObject);
+ int live_news_size = IterateLiveObjects(
+ heap_->new_space(), &MarkCompactCollector::UpdatePointersInNewObject);
// Large objects do not move, the map word can be updated directly.
- LargeObjectIterator it(Heap::lo_space());
+ LargeObjectIterator it(heap_->lo_space());
for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
UpdatePointersInNewObject(obj);
}
@@ -2591,8 +2695,8 @@ int MarkCompactCollector::UpdatePointersInNewObject(HeapObject* obj) {
Address forwarded = GetForwardingAddressInOldSpace(old_map);
- ASSERT(Heap::map_space()->Contains(old_map));
- ASSERT(Heap::map_space()->Contains(forwarded));
+ ASSERT(heap_->map_space()->Contains(old_map));
+ ASSERT(heap_->map_space()->Contains(forwarded));
#ifdef DEBUG
if (FLAG_gc_verbose) {
PrintF("update %p : %p -> %p\n", obj->address(), old_map->address(),
@@ -2607,7 +2711,7 @@ int MarkCompactCollector::UpdatePointersInNewObject(HeapObject* obj) {
int obj_size = obj->SizeFromMap(old_map);
// Update pointers in the object body.
- UpdatingVisitor updating_visitor;
+ UpdatingVisitor updating_visitor(heap_);
obj->IterateBody(old_map->instance_type(), obj_size, &updating_visitor);
return obj_size;
}
@@ -2616,8 +2720,8 @@ int MarkCompactCollector::UpdatePointersInNewObject(HeapObject* obj) {
int MarkCompactCollector::UpdatePointersInOldObject(HeapObject* obj) {
// Decode the map pointer.
MapWord encoding = obj->map_word();
- Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
- ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
+ Address map_addr = encoding.DecodeMapAddress(heap_->map_space());
+ ASSERT(heap_->map_space()->Contains(HeapObject::FromAddress(map_addr)));
// At this point, the first word of map_addr is also encoded, cannot
// cast it to Map* using Map::cast.
@@ -2638,7 +2742,7 @@ int MarkCompactCollector::UpdatePointersInOldObject(HeapObject* obj) {
#endif
// Update pointers in the object body.
- UpdatingVisitor updating_visitor;
+ UpdatingVisitor updating_visitor(heap_);
obj->IterateBody(type, obj_size, &updating_visitor);
return obj_size;
}
@@ -2694,18 +2798,19 @@ void MarkCompactCollector::RelocateObjects() {
#endif
// Relocates objects, always relocate map objects first. Relocating
// objects in other space relies on map objects to get object size.
- int live_maps_size = IterateLiveObjects(Heap::map_space(),
- &RelocateMapObject);
- int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(),
- &RelocateOldPointerObject);
- int live_data_olds_size = IterateLiveObjects(Heap::old_data_space(),
- &RelocateOldDataObject);
- int live_codes_size = IterateLiveObjects(Heap::code_space(),
- &RelocateCodeObject);
- int live_cells_size = IterateLiveObjects(Heap::cell_space(),
- &RelocateCellObject);
- int live_news_size = IterateLiveObjects(Heap::new_space(),
- &RelocateNewObject);
+ int live_maps_size = IterateLiveObjects(
+ heap_->map_space(), &MarkCompactCollector::RelocateMapObject);
+ int live_pointer_olds_size = IterateLiveObjects(
+ heap_->old_pointer_space(),
+ &MarkCompactCollector::RelocateOldPointerObject);
+ int live_data_olds_size = IterateLiveObjects(
+ heap_->old_data_space(), &MarkCompactCollector::RelocateOldDataObject);
+ int live_codes_size = IterateLiveObjects(
+ heap_->code_space(), &MarkCompactCollector::RelocateCodeObject);
+ int live_cells_size = IterateLiveObjects(
+ heap_->cell_space(), &MarkCompactCollector::RelocateCellObject);
+ int live_news_size = IterateLiveObjects(
+ heap_->new_space(), &MarkCompactCollector::RelocateNewObject);
USE(live_maps_size);
USE(live_pointer_olds_size);
@@ -2721,28 +2826,28 @@ void MarkCompactCollector::RelocateObjects() {
ASSERT(live_news_size == live_young_objects_size_);
// Flip from and to spaces
- Heap::new_space()->Flip();
+ heap_->new_space()->Flip();
- Heap::new_space()->MCCommitRelocationInfo();
+ heap_->new_space()->MCCommitRelocationInfo();
// Set age_mark to bottom in to space
- Address mark = Heap::new_space()->bottom();
- Heap::new_space()->set_age_mark(mark);
+ Address mark = heap_->new_space()->bottom();
+ heap_->new_space()->set_age_mark(mark);
PagedSpaces spaces;
for (PagedSpace* space = spaces.next(); space != NULL; space = spaces.next())
space->MCCommitRelocationInfo();
- Heap::CheckNewSpaceExpansionCriteria();
- Heap::IncrementYoungSurvivorsCounter(live_news_size);
+ heap_->CheckNewSpaceExpansionCriteria();
+ heap_->IncrementYoungSurvivorsCounter(live_news_size);
}
int MarkCompactCollector::RelocateMapObject(HeapObject* obj) {
// Recover map pointer.
MapWord encoding = obj->map_word();
- Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
- ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
+ Address map_addr = encoding.DecodeMapAddress(heap_->map_space());
+ ASSERT(heap_->map_space()->Contains(HeapObject::FromAddress(map_addr)));
// Get forwarding address before resetting map pointer
Address new_addr = GetForwardingAddressInOldSpace(obj);
@@ -2755,9 +2860,9 @@ int MarkCompactCollector::RelocateMapObject(HeapObject* obj) {
if (new_addr != old_addr) {
// Move contents.
- Heap::MoveBlockToOldSpaceAndUpdateRegionMarks(new_addr,
- old_addr,
- Map::kSize);
+ heap_->MoveBlockToOldSpaceAndUpdateRegionMarks(new_addr,
+ old_addr,
+ Map::kSize);
}
#ifdef DEBUG
@@ -2801,8 +2906,8 @@ int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
PagedSpace* space) {
// Recover map pointer.
MapWord encoding = obj->map_word();
- Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
- ASSERT(Heap::map_space()->Contains(map_addr));
+ Address map_addr = encoding.DecodeMapAddress(heap_->map_space());
+ ASSERT(heap_->map_space()->Contains(map_addr));
// Get forwarding address before resetting map pointer.
Address new_addr = GetForwardingAddressInOldSpace(obj);
@@ -2814,12 +2919,12 @@ int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
if (new_addr != old_addr) {
// Move contents.
- if (space == Heap::old_data_space()) {
- Heap::MoveBlock(new_addr, old_addr, obj_size);
+ if (space == heap_->old_data_space()) {
+ heap_->MoveBlock(new_addr, old_addr, obj_size);
} else {
- Heap::MoveBlockToOldSpaceAndUpdateRegionMarks(new_addr,
- old_addr,
- obj_size);
+ heap_->MoveBlockToOldSpaceAndUpdateRegionMarks(new_addr,
+ old_addr,
+ obj_size);
}
}
@@ -2827,46 +2932,47 @@ int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
HeapObject* copied_to = HeapObject::FromAddress(new_addr);
if (copied_to->IsSharedFunctionInfo()) {
- PROFILE(SFIMoveEvent(old_addr, new_addr));
+ PROFILE(heap_->isolate(),
+ SharedFunctionInfoMoveEvent(old_addr, new_addr));
}
- HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));
+ HEAP_PROFILE(heap_, ObjectMoveEvent(old_addr, new_addr));
return obj_size;
}
int MarkCompactCollector::RelocateOldPointerObject(HeapObject* obj) {
- return RelocateOldNonCodeObject(obj, Heap::old_pointer_space());
+ return RelocateOldNonCodeObject(obj, heap_->old_pointer_space());
}
int MarkCompactCollector::RelocateOldDataObject(HeapObject* obj) {
- return RelocateOldNonCodeObject(obj, Heap::old_data_space());
+ return RelocateOldNonCodeObject(obj, heap_->old_data_space());
}
int MarkCompactCollector::RelocateCellObject(HeapObject* obj) {
- return RelocateOldNonCodeObject(obj, Heap::cell_space());
+ return RelocateOldNonCodeObject(obj, heap_->cell_space());
}
int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) {
// Recover map pointer.
MapWord encoding = obj->map_word();
- Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
- ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
+ Address map_addr = encoding.DecodeMapAddress(heap_->map_space());
+ ASSERT(heap_->map_space()->Contains(HeapObject::FromAddress(map_addr)));
// Get forwarding address before resetting map pointer
Address new_addr = GetForwardingAddressInOldSpace(obj);
// Reset the map pointer.
- int obj_size = RestoreMap(obj, Heap::code_space(), new_addr, map_addr);
+ int obj_size = RestoreMap(obj, heap_->code_space(), new_addr, map_addr);
Address old_addr = obj->address();
if (new_addr != old_addr) {
// Move contents.
- Heap::MoveBlock(new_addr, old_addr, obj_size);
+ heap_->MoveBlock(new_addr, old_addr, obj_size);
}
HeapObject* copied_to = HeapObject::FromAddress(new_addr);
@@ -2874,9 +2980,9 @@ int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) {
// May also update inline cache target.
Code::cast(copied_to)->Relocate(new_addr - old_addr);
// Notify the logger that compiled code has moved.
- PROFILE(CodeMoveEvent(old_addr, new_addr));
+ PROFILE(heap_->isolate(), CodeMoveEvent(old_addr, new_addr));
}
- HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));
+ HEAP_PROFILE(heap_, ObjectMoveEvent(old_addr, new_addr));
return obj_size;
}
@@ -2887,28 +2993,28 @@ int MarkCompactCollector::RelocateNewObject(HeapObject* obj) {
// Get forwarding address
Address old_addr = obj->address();
- int offset = Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
+ int offset = heap_->new_space()->ToSpaceOffsetForAddress(old_addr);
Address new_addr =
- Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset);
+ Memory::Address_at(heap_->new_space()->FromSpaceLow() + offset);
#ifdef DEBUG
- if (Heap::new_space()->FromSpaceContains(new_addr)) {
- ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
- Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
+ if (heap_->new_space()->FromSpaceContains(new_addr)) {
+ ASSERT(heap_->new_space()->FromSpaceOffsetForAddress(new_addr) <=
+ heap_->new_space()->ToSpaceOffsetForAddress(old_addr));
} else {
- ASSERT(Heap::TargetSpace(obj) == Heap::old_pointer_space() ||
- Heap::TargetSpace(obj) == Heap::old_data_space());
+ ASSERT(heap_->TargetSpace(obj) == heap_->old_pointer_space() ||
+ heap_->TargetSpace(obj) == heap_->old_data_space());
}
#endif
// New and old addresses cannot overlap.
- if (Heap::InNewSpace(HeapObject::FromAddress(new_addr))) {
- Heap::CopyBlock(new_addr, old_addr, obj_size);
+ if (heap_->InNewSpace(HeapObject::FromAddress(new_addr))) {
+ heap_->CopyBlock(new_addr, old_addr, obj_size);
} else {
- Heap::CopyBlockToOldSpaceAndUpdateRegionMarks(new_addr,
- old_addr,
- obj_size);
+ heap_->CopyBlockToOldSpaceAndUpdateRegionMarks(new_addr,
+ old_addr,
+ obj_size);
}
#ifdef DEBUG
@@ -2919,14 +3025,27 @@ int MarkCompactCollector::RelocateNewObject(HeapObject* obj) {
HeapObject* copied_to = HeapObject::FromAddress(new_addr);
if (copied_to->IsSharedFunctionInfo()) {
- PROFILE(SFIMoveEvent(old_addr, new_addr));
+ PROFILE(heap_->isolate(),
+ SharedFunctionInfoMoveEvent(old_addr, new_addr));
}
- HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));
+ HEAP_PROFILE(heap_, ObjectMoveEvent(old_addr, new_addr));
return obj_size;
}
+void MarkCompactCollector::EnableCodeFlushing(bool enable) {
+ if (enable) {
+ if (code_flusher_ != NULL) return;
+ code_flusher_ = new CodeFlusher(heap_->isolate());
+ } else {
+ if (code_flusher_ == NULL) return;
+ delete code_flusher_;
+ code_flusher_ = NULL;
+ }
+}
+
+
void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) {
#ifdef ENABLE_GDB_JIT_INTERFACE
if (obj->IsCode()) {
@@ -2935,7 +3054,7 @@ void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) {
#endif
#ifdef ENABLE_LOGGING_AND_PROFILING
if (obj->IsCode()) {
- PROFILE(CodeDeleteEvent(obj->address()));
+ PROFILE(ISOLATE, CodeDeleteEvent(obj->address()));
}
#endif
}
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 1b7e6002..3c9d28ba 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -28,6 +28,8 @@
#ifndef V8_MARK_COMPACT_H_
#define V8_MARK_COMPACT_H_
+#include "spaces.h"
+
namespace v8 {
namespace internal {
@@ -37,8 +39,61 @@ namespace internal {
typedef bool (*IsAliveFunction)(HeapObject* obj, int* size, int* offset);
// Forward declarations.
-class RootMarkingVisitor;
+class CodeFlusher;
+class GCTracer;
class MarkingVisitor;
+class RootMarkingVisitor;
+
+
+// ----------------------------------------------------------------------------
+// Marking stack for tracing live objects.
+
+class MarkingStack {
+ public:
+ MarkingStack() : low_(NULL), top_(NULL), high_(NULL), overflowed_(false) { }
+
+ void Initialize(Address low, Address high) {
+ top_ = low_ = reinterpret_cast<HeapObject**>(low);
+ high_ = reinterpret_cast<HeapObject**>(high);
+ overflowed_ = false;
+ }
+
+ bool is_full() const { return top_ >= high_; }
+
+ bool is_empty() const { return top_ <= low_; }
+
+ bool overflowed() const { return overflowed_; }
+
+ void clear_overflowed() { overflowed_ = false; }
+
+ // Push the (marked) object on the marking stack if there is room,
+ // otherwise mark the object as overflowed and wait for a rescan of the
+ // heap.
+ void Push(HeapObject* object) {
+ CHECK(object->IsHeapObject());
+ if (is_full()) {
+ object->SetOverflow();
+ overflowed_ = true;
+ } else {
+ *(top_++) = object;
+ }
+ }
+
+ HeapObject* Pop() {
+ ASSERT(!is_empty());
+ HeapObject* object = *(--top_);
+ CHECK(object->IsHeapObject());
+ return object;
+ }
+
+ private:
+ HeapObject** low_;
+ HeapObject** top_;
+ HeapObject** high_;
+ bool overflowed_;
+
+ DISALLOW_COPY_AND_ASSIGN(MarkingStack);
+};
// -------------------------------------------------------------------------
@@ -46,14 +101,17 @@ class MarkingVisitor;
//
// All methods are static.
-class MarkCompactCollector: public AllStatic {
+class OverflowedObjectsScanner;
+
+class MarkCompactCollector {
public:
// Type of functions to compute forwarding addresses of objects in
// compacted spaces. Given an object and its size, return a (non-failure)
// Object* that will be the object after forwarding. There is a separate
// allocation function for each (compactable) space based on the location
// of the object before compaction.
- typedef MaybeObject* (*AllocationFunction)(HeapObject* object,
+ typedef MaybeObject* (*AllocationFunction)(Heap* heap,
+ HeapObject* object,
int object_size);
// Type of functions to encode the forwarding address for an object.
@@ -64,7 +122,8 @@ class MarkCompactCollector: public AllStatic {
// page as input, and is updated to contain the offset to be used for the
// next live object in the same page. For spaces using a different
// encoding (ie, contiguous spaces), the offset parameter is ignored.
- typedef void (*EncodingFunction)(HeapObject* old_object,
+ typedef void (*EncodingFunction)(Heap* heap,
+ HeapObject* old_object,
int object_size,
Object* new_object,
int* offset);
@@ -72,9 +131,12 @@ class MarkCompactCollector: public AllStatic {
// Type of functions to process non-live objects.
typedef void (*ProcessNonLiveFunction)(HeapObject* object);
+ // Pointer to member function, used in IterateLiveObjects.
+ typedef int (MarkCompactCollector::*LiveObjectCallback)(HeapObject* obj);
+
// Set the global force_compaction flag, it must be called before Prepare
// to take effect.
- static void SetForceCompaction(bool value) {
+ void SetForceCompaction(bool value) {
force_compaction_ = value;
}
@@ -83,16 +145,16 @@ class MarkCompactCollector: public AllStatic {
// Prepares for GC by resetting relocation info in old and map spaces and
// choosing spaces to compact.
- static void Prepare(GCTracer* tracer);
+ void Prepare(GCTracer* tracer);
// Performs a global garbage collection.
- static void CollectGarbage();
+ void CollectGarbage();
// True if the last full GC performed heap compaction.
- static bool HasCompacted() { return compacting_collection_; }
+ bool HasCompacted() { return compacting_collection_; }
// True after the Prepare phase if the compaction is taking place.
- static bool IsCompacting() {
+ bool IsCompacting() {
#ifdef DEBUG
// For the purposes of asserts we don't want this to keep returning true
// after the collection is completed.
@@ -104,16 +166,16 @@ class MarkCompactCollector: public AllStatic {
// The count of the number of objects left marked at the end of the last
// completed full GC (expected to be zero).
- static int previous_marked_count() { return previous_marked_count_; }
+ int previous_marked_count() { return previous_marked_count_; }
// During a full GC, there is a stack-allocated GCTracer that is used for
// bookkeeping information. Return a pointer to that tracer.
- static GCTracer* tracer() { return tracer_; }
+ GCTracer* tracer() { return tracer_; }
#ifdef DEBUG
// Checks whether performing mark-compact collection.
- static bool in_use() { return state_ > PREPARE_GC; }
- static bool are_map_pointers_encoded() { return state_ == UPDATE_POINTERS; }
+ bool in_use() { return state_ > PREPARE_GC; }
+ bool are_map_pointers_encoded() { return state_ == UPDATE_POINTERS; }
#endif
// Determine type of object and emit deletion log event.
@@ -127,7 +189,16 @@ class MarkCompactCollector: public AllStatic {
static const uint32_t kSingleFreeEncoding = 0;
static const uint32_t kMultiFreeEncoding = 1;
+ inline Heap* heap() const { return heap_; }
+
+ CodeFlusher* code_flusher() { return code_flusher_; }
+ inline bool is_code_flushing_enabled() const { return code_flusher_ != NULL; }
+ void EnableCodeFlushing(bool enable);
+
private:
+ MarkCompactCollector();
+ ~MarkCompactCollector();
+
#ifdef DEBUG
enum CollectorState {
IDLE,
@@ -140,28 +211,28 @@ class MarkCompactCollector: public AllStatic {
};
// The current stage of the collector.
- static CollectorState state_;
+ CollectorState state_;
#endif
// Global flag that forces a compaction.
- static bool force_compaction_;
+ bool force_compaction_;
// Global flag indicating whether spaces were compacted on the last GC.
- static bool compacting_collection_;
+ bool compacting_collection_;
// Global flag indicating whether spaces will be compacted on the next GC.
- static bool compact_on_next_gc_;
+ bool compact_on_next_gc_;
// The number of objects left marked at the end of the last completed full
// GC (expected to be zero).
- static int previous_marked_count_;
+ int previous_marked_count_;
// A pointer to the current stack-allocated GC tracer object during a full
// collection (NULL before and after).
- static GCTracer* tracer_;
+ GCTracer* tracer_;
// Finishes GC, performs heap verification if enabled.
- static void Finish();
+ void Finish();
// -----------------------------------------------------------------------
// Phase 1: Marking live objects.
@@ -179,85 +250,82 @@ class MarkCompactCollector: public AllStatic {
friend class CodeMarkingVisitor;
friend class SharedFunctionInfoMarkingVisitor;
- static void PrepareForCodeFlushing();
+ void PrepareForCodeFlushing();
// Marking operations for objects reachable from roots.
- static void MarkLiveObjects();
+ void MarkLiveObjects();
- static void MarkUnmarkedObject(HeapObject* obj);
+ void MarkUnmarkedObject(HeapObject* obj);
- static inline void MarkObject(HeapObject* obj) {
+ inline void MarkObject(HeapObject* obj) {
if (!obj->IsMarked()) MarkUnmarkedObject(obj);
}
- static inline void SetMark(HeapObject* obj) {
- tracer_->increment_marked_count();
-#ifdef DEBUG
- UpdateLiveObjectCount(obj);
-#endif
- obj->SetMark();
- }
+ inline void SetMark(HeapObject* obj);
// Creates back pointers for all map transitions, stores them in
// the prototype field. The original prototype pointers are restored
// in ClearNonLiveTransitions(). All JSObject maps
// connected by map transitions have the same prototype object, which
// is why we can use this field temporarily for back pointers.
- static void CreateBackPointers();
+ void CreateBackPointers();
// Mark a Map and its DescriptorArray together, skipping transitions.
- static void MarkMapContents(Map* map);
- static void MarkDescriptorArray(DescriptorArray* descriptors);
+ void MarkMapContents(Map* map);
+ void MarkDescriptorArray(DescriptorArray* descriptors);
// Mark the heap roots and all objects reachable from them.
- static void MarkRoots(RootMarkingVisitor* visitor);
+ void MarkRoots(RootMarkingVisitor* visitor);
// Mark the symbol table specially. References to symbols from the
// symbol table are weak.
- static void MarkSymbolTable();
+ void MarkSymbolTable();
// Mark objects in object groups that have at least one object in the
// group marked.
- static void MarkObjectGroups();
+ void MarkObjectGroups();
+
+ // Mark objects in implicit references groups if their parent object
+ // is marked.
+ void MarkImplicitRefGroups();
- // Mark all objects in an object group with at least one marked
- // object, then all objects reachable from marked objects in object
- // groups, and repeat.
- static void ProcessObjectGroups();
+ // Mark all objects which are reachable due to host application
+ // logic like object groups or implicit references' groups.
+ void ProcessExternalMarking();
// Mark objects reachable (transitively) from objects in the marking stack
// or overflowed in the heap.
- static void ProcessMarkingStack();
+ void ProcessMarkingStack();
// Mark objects reachable (transitively) from objects in the marking
// stack. This function empties the marking stack, but may leave
// overflowed objects in the heap, in which case the marking stack's
// overflow flag will be set.
- static void EmptyMarkingStack();
+ void EmptyMarkingStack();
// Refill the marking stack with overflowed objects from the heap. This
// function either leaves the marking stack full or clears the overflow
// flag on the marking stack.
- static void RefillMarkingStack();
+ void RefillMarkingStack();
// Callback function for telling whether the object *p is an unmarked
// heap object.
static bool IsUnmarkedHeapObject(Object** p);
#ifdef DEBUG
- static void UpdateLiveObjectCount(HeapObject* obj);
+ void UpdateLiveObjectCount(HeapObject* obj);
#endif
// We sweep the large object space in the same way whether we are
// compacting or not, because the large object space is never compacted.
- static void SweepLargeObjectSpace();
+ void SweepLargeObjectSpace();
// Test whether a (possibly marked) object is a Map.
static inline bool SafeIsMap(HeapObject* object);
// Map transitions from a live map to a dead map must be killed.
// We replace them with a null descriptor, with the same key.
- static void ClearNonLiveTransitions();
+ void ClearNonLiveTransitions();
// -----------------------------------------------------------------------
// Phase 2: Sweeping to clear mark bits and free non-live objects for
@@ -302,32 +370,32 @@ class MarkCompactCollector: public AllStatic {
// Encodes forwarding addresses of objects in compactable parts of the
// heap.
- static void EncodeForwardingAddresses();
+ void EncodeForwardingAddresses();
// Encodes the forwarding addresses of objects in new space.
- static void EncodeForwardingAddressesInNewSpace();
+ void EncodeForwardingAddressesInNewSpace();
// Function template to encode the forwarding addresses of objects in
// paged spaces, parameterized by allocation and non-live processing
// functions.
template<AllocationFunction Alloc, ProcessNonLiveFunction ProcessNonLive>
- static void EncodeForwardingAddressesInPagedSpace(PagedSpace* space);
+ void EncodeForwardingAddressesInPagedSpace(PagedSpace* space);
// Iterates live objects in a space, passes live objects
// to a callback function which returns the heap size of the object.
// Returns the number of live objects iterated.
- static int IterateLiveObjects(NewSpace* space, HeapObjectCallback size_f);
- static int IterateLiveObjects(PagedSpace* space, HeapObjectCallback size_f);
+ int IterateLiveObjects(NewSpace* space, LiveObjectCallback size_f);
+ int IterateLiveObjects(PagedSpace* space, LiveObjectCallback size_f);
// Iterates the live objects between a range of addresses, returning the
// number of live objects.
- static int IterateLiveObjectsInRange(Address start, Address end,
- HeapObjectCallback size_func);
+ int IterateLiveObjectsInRange(Address start, Address end,
+ LiveObjectCallback size_func);
// If we are not compacting the heap, we simply sweep the spaces except
// for the large object space, clearing mark bits and adding unmarked
// regions to each space's free list.
- static void SweepSpaces();
+ void SweepSpaces();
// -----------------------------------------------------------------------
// Phase 3: Updating pointers in live objects.
@@ -341,15 +409,15 @@ class MarkCompactCollector: public AllStatic {
friend class UpdatingVisitor; // helper for updating visited objects
// Updates pointers in all spaces.
- static void UpdatePointers();
+ void UpdatePointers();
// Updates pointers in an object in new space.
// Returns the heap size of the object.
- static int UpdatePointersInNewObject(HeapObject* obj);
+ int UpdatePointersInNewObject(HeapObject* obj);
// Updates pointers in an object in old spaces.
// Returns the heap size of the object.
- static int UpdatePointersInOldObject(HeapObject* obj);
+ int UpdatePointersInOldObject(HeapObject* obj);
// Calculates the forwarding address of an object in an old space.
static Address GetForwardingAddressInOldSpace(HeapObject* obj);
@@ -363,31 +431,31 @@ class MarkCompactCollector: public AllStatic {
// After: Objects have been moved to their new addresses.
// Relocates objects in all spaces.
- static void RelocateObjects();
+ void RelocateObjects();
// Converts a code object's inline target to addresses, convention from
// address to target happens in the marking phase.
- static int ConvertCodeICTargetToAddress(HeapObject* obj);
+ int ConvertCodeICTargetToAddress(HeapObject* obj);
// Relocate a map object.
- static int RelocateMapObject(HeapObject* obj);
+ int RelocateMapObject(HeapObject* obj);
// Relocates an old object.
- static int RelocateOldPointerObject(HeapObject* obj);
- static int RelocateOldDataObject(HeapObject* obj);
+ int RelocateOldPointerObject(HeapObject* obj);
+ int RelocateOldDataObject(HeapObject* obj);
// Relocate a property cell object.
- static int RelocateCellObject(HeapObject* obj);
+ int RelocateCellObject(HeapObject* obj);
// Helper function.
- static inline int RelocateOldNonCodeObject(HeapObject* obj,
- PagedSpace* space);
+ inline int RelocateOldNonCodeObject(HeapObject* obj,
+ PagedSpace* space);
// Relocates an object in the code space.
- static int RelocateCodeObject(HeapObject* obj);
+ int RelocateCodeObject(HeapObject* obj);
// Copy a new object.
- static int RelocateNewObject(HeapObject* obj);
+ int RelocateNewObject(HeapObject* obj);
#ifdef DEBUG
// -----------------------------------------------------------------------
@@ -396,28 +464,28 @@ class MarkCompactCollector: public AllStatic {
// mark-sweep collection.
// Size of live objects in Heap::to_space_.
- static int live_young_objects_size_;
+ int live_young_objects_size_;
// Size of live objects in Heap::old_pointer_space_.
- static int live_old_pointer_objects_size_;
+ int live_old_pointer_objects_size_;
// Size of live objects in Heap::old_data_space_.
- static int live_old_data_objects_size_;
+ int live_old_data_objects_size_;
// Size of live objects in Heap::code_space_.
- static int live_code_objects_size_;
+ int live_code_objects_size_;
// Size of live objects in Heap::map_space_.
- static int live_map_objects_size_;
+ int live_map_objects_size_;
// Size of live objects in Heap::cell_space_.
- static int live_cell_objects_size_;
+ int live_cell_objects_size_;
// Size of live objects in Heap::lo_space_.
- static int live_lo_objects_size_;
+ int live_lo_objects_size_;
// Number of live bytes in this collection.
- static int live_bytes_;
+ int live_bytes_;
friend class MarkObjectVisitor;
static void VisitObject(HeapObject* obj);
@@ -425,6 +493,13 @@ class MarkCompactCollector: public AllStatic {
friend class UnmarkObjectVisitor;
static void UnmarkObject(HeapObject* obj);
#endif
+
+ Heap* heap_;
+ MarkingStack marking_stack_;
+ CodeFlusher* code_flusher_;
+
+ friend class Heap;
+ friend class OverflowedObjectsScanner;
};
diff --git a/src/messages.cc b/src/messages.cc
index 990000a3..cab982ce 100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -32,7 +32,6 @@
#include "execution.h"
#include "messages.h"
#include "spaces-inl.h"
-#include "top.h"
namespace v8 {
namespace internal {
@@ -68,18 +67,18 @@ Handle<JSMessageObject> MessageHandler::MakeMessageObject(
Vector< Handle<Object> > args,
Handle<String> stack_trace,
Handle<JSArray> stack_frames) {
- Handle<String> type_handle = Factory::LookupAsciiSymbol(type);
+ Handle<String> type_handle = FACTORY->LookupAsciiSymbol(type);
Handle<FixedArray> arguments_elements =
- Factory::NewFixedArray(args.length());
+ FACTORY->NewFixedArray(args.length());
for (int i = 0; i < args.length(); i++) {
arguments_elements->set(i, *args[i]);
}
Handle<JSArray> arguments_handle =
- Factory::NewJSArrayWithElements(arguments_elements);
+ FACTORY->NewJSArrayWithElements(arguments_elements);
int start = 0;
int end = 0;
- Handle<Object> script_handle = Factory::undefined_value();
+ Handle<Object> script_handle = FACTORY->undefined_value();
if (loc) {
start = loc->start_pos();
end = loc->end_pos();
@@ -87,15 +86,15 @@ Handle<JSMessageObject> MessageHandler::MakeMessageObject(
}
Handle<Object> stack_trace_handle = stack_trace.is_null()
- ? Factory::undefined_value()
+ ? FACTORY->undefined_value()
: Handle<Object>::cast(stack_trace);
Handle<Object> stack_frames_handle = stack_frames.is_null()
- ? Factory::undefined_value()
+ ? FACTORY->undefined_value()
: Handle<Object>::cast(stack_frames);
Handle<JSMessageObject> message =
- Factory::NewJSMessageObject(type_handle,
+ FACTORY->NewJSMessageObject(type_handle,
arguments_handle,
start,
end,
@@ -111,7 +110,7 @@ void MessageHandler::ReportMessage(MessageLocation* loc,
Handle<Object> message) {
v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
- v8::NeanderArray global_listeners(Factory::message_listeners());
+ v8::NeanderArray global_listeners(FACTORY->message_listeners());
int global_length = global_listeners.length();
if (global_length == 0) {
DefaultMessageReport(loc, message);
@@ -131,18 +130,21 @@ void MessageHandler::ReportMessage(MessageLocation* loc,
Handle<String> MessageHandler::GetMessage(Handle<Object> data) {
- Handle<String> fmt_str = Factory::LookupAsciiSymbol("FormatMessage");
+ Handle<String> fmt_str = FACTORY->LookupAsciiSymbol("FormatMessage");
Handle<JSFunction> fun =
- Handle<JSFunction>(JSFunction::cast(
- Top::builtins()->GetPropertyNoExceptionThrown(*fmt_str)));
+ Handle<JSFunction>(
+ JSFunction::cast(
+ Isolate::Current()->js_builtins_object()->
+ GetPropertyNoExceptionThrown(*fmt_str)));
Object** argv[1] = { data.location() };
bool caught_exception;
Handle<Object> result =
- Execution::TryCall(fun, Top::builtins(), 1, argv, &caught_exception);
+ Execution::TryCall(fun,
+ Isolate::Current()->js_builtins_object(), 1, argv, &caught_exception);
if (caught_exception || !result->IsString()) {
- return Factory::LookupAsciiSymbol("<error>");
+ return FACTORY->LookupAsciiSymbol("<error>");
}
Handle<String> result_string = Handle<String>::cast(result);
// A string that has been obtained from JS code in this way is
diff --git a/src/messages.js b/src/messages.js
index 2c94912f..3eb056f3 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -230,6 +230,11 @@ function FormatMessage(message) {
strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"],
strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"],
+ strict_arguments_callee: ["Cannot access property 'callee' of strict mode arguments"],
+ strict_arguments_caller: ["Cannot access property 'caller' of strict mode arguments"],
+ strict_function_caller: ["Cannot access property 'caller' of a strict mode function"],
+ strict_function_arguments: ["Cannot access property 'arguments' of a strict mode function"],
+ strict_caller: ["Illegal access to a strict mode caller function."],
};
}
var message_type = %MessageGetType(message);
@@ -491,10 +496,24 @@ Script.prototype.nameOrSourceURL = function() {
// because this file is being processed by js2c whose handling of spaces
// in regexps is broken. Also, ['"] are excluded from allowed URLs to
// avoid matches against sources that invoke evals with sourceURL.
- var sourceUrlPattern =
- /\/\/@[\040\t]sourceURL=[\040\t]*([^\s'"]*)[\040\t]*$/m;
- var match = sourceUrlPattern.exec(this.source);
- return match ? match[1] : this.name;
+ // A better solution would be to detect these special comments in
+ // the scanner/parser.
+ var source = ToString(this.source);
+ var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
+ if (sourceUrlPos > 4) {
+ var sourceUrlPattern =
+ /\/\/@[\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
+ // Don't reuse lastMatchInfo here, so we create a new array with room
+ // for four captures (array with length one longer than the index
+ // of the fourth capture, where the numbering is zero-based).
+ var matchInfo = new InternalArray(CAPTURE(3) + 1);
+ var match =
+ %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
+ if (match) {
+ return SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
+ }
+ }
+ return this.name;
}
@@ -1067,5 +1086,5 @@ function errorToString() {
InstallFunctions($Error.prototype, DONT_ENUM, ['toString', errorToString]);
// Boilerplate for exceptions for stack overflows. Used from
-// Top::StackOverflow().
+// Isolate::StackOverflow().
const kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);
diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h
index 2e634617..f7453d16 100644
--- a/src/mips/assembler-mips-inl.h
+++ b/src/mips/assembler-mips-inl.h
@@ -38,21 +38,13 @@
#include "mips/assembler-mips.h"
#include "cpu.h"
+#include "debug.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
-// Condition
-
-Condition NegateCondition(Condition cc) {
- ASSERT(cc != cc_always);
- return static_cast<Condition>(cc ^ 1);
-}
-
-
-// -----------------------------------------------------------------------------
// Operand and MemOperand
Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) {
@@ -61,17 +53,13 @@ Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) {
rmode_ = rmode;
}
+
Operand::Operand(const ExternalReference& f) {
rm_ = no_reg;
imm32_ = reinterpret_cast<int32_t>(f.address());
rmode_ = RelocInfo::EXTERNAL_REFERENCE;
}
-Operand::Operand(const char* s) {
- rm_ = no_reg;
- imm32_ = reinterpret_cast<int32_t>(s);
- rmode_ = RelocInfo::EMBEDDED_STRING;
-}
Operand::Operand(Smi* value) {
rm_ = no_reg;
@@ -79,10 +67,12 @@ Operand::Operand(Smi* value) {
rmode_ = RelocInfo::NONE;
}
+
Operand::Operand(Register rm) {
rm_ = rm;
}
+
bool Operand::is_reg() const {
return rm_.is_valid();
}
@@ -105,8 +95,29 @@ Address RelocInfo::target_address() {
Address RelocInfo::target_address_address() {
- ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
- return reinterpret_cast<Address>(pc_);
+ ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY
+ || rmode_ == EMBEDDED_OBJECT
+ || rmode_ == EXTERNAL_REFERENCE);
+ // Read the address of the word containing the target_address in an
+ // instruction stream.
+ // The only architecture-independent user of this function is the serializer.
+ // The serializer uses it to find out how many raw bytes of instruction to
+ // output before the next target.
+ // For an instructions like LUI/ORI where the target bits are mixed into the
+ // instruction bits, the size of the target will be zero, indicating that the
+ // serializer should not step forward in memory after a target is resolved
+ // and written. In this case the target_address_address function should
+ // return the end of the instructions to be patched, allowing the
+ // deserializer to deserialize the instructions as raw bytes and put them in
+ // place, ready to be patched with the target. In our case, that is the
+ // address of the instruction that follows LUI/ORI instruction pair.
+ return reinterpret_cast<Address>(
+ pc_ + Assembler::kInstructionsFor32BitConstant * Assembler::kInstrSize);
+}
+
+
+int RelocInfo::target_address_size() {
+ return Assembler::kExternalTargetSize;
}
@@ -130,8 +141,15 @@ Handle<Object> RelocInfo::target_object_handle(Assembler *origin) {
Object** RelocInfo::target_object_address() {
+ // Provide a "natural pointer" to the embedded object,
+ // which can be de-referenced during heap iteration.
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
- return reinterpret_cast<Object**>(pc_);
+ // TODO(mips): Commenting out, to simplify arch-independent changes.
+ // GC won't work like this, but this commit is for asm/disasm/sim.
+ // reconstructed_obj_ptr_ =
+ // reinterpret_cast<Object*>(Assembler::target_address_at(pc_));
+ // return &reconstructed_obj_ptr_;
+ return NULL;
}
@@ -143,23 +161,55 @@ void RelocInfo::set_target_object(Object* target) {
Address* RelocInfo::target_reference_address() {
ASSERT(rmode_ == EXTERNAL_REFERENCE);
- return reinterpret_cast<Address*>(pc_);
+ // TODO(mips): Commenting out, to simplify arch-independent changes.
+ // GC won't work like this, but this commit is for asm/disasm/sim.
+ // reconstructed_adr_ptr_ = Assembler::target_address_at(pc_);
+ // return &reconstructed_adr_ptr_;
+ return NULL;
+}
+
+
+Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() {
+ ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
+ Address address = Memory::Address_at(pc_);
+ return Handle<JSGlobalPropertyCell>(
+ reinterpret_cast<JSGlobalPropertyCell**>(address));
+}
+
+
+JSGlobalPropertyCell* RelocInfo::target_cell() {
+ ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
+ Address address = Memory::Address_at(pc_);
+ Object* object = HeapObject::FromAddress(
+ address - JSGlobalPropertyCell::kValueOffset);
+ return reinterpret_cast<JSGlobalPropertyCell*>(object);
+}
+
+
+void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell) {
+ ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
+ Address address = cell->address() + JSGlobalPropertyCell::kValueOffset;
+ Memory::Address_at(pc_) = address;
}
Address RelocInfo::call_address() {
- ASSERT(IsPatchedReturnSequence());
- // The 2 instructions offset assumes patched return sequence.
- ASSERT(IsJSReturn(rmode()));
- return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize);
+ ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
+ (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
+ // The pc_ offset of 0 assumes mips patched return sequence per
+ // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
+ // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+ return Assembler::target_address_at(pc_);
}
void RelocInfo::set_call_address(Address target) {
- ASSERT(IsPatchedReturnSequence());
- // The 2 instructions offset assumes patched return sequence.
- ASSERT(IsJSReturn(rmode()));
- Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target;
+ ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
+ (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
+ // The pc_ offset of 0 assumes mips patched return sequence per
+ // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
+ // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
+ Assembler::set_target_address_at(pc_, target);
}
@@ -169,9 +219,8 @@ Object* RelocInfo::call_object() {
Object** RelocInfo::call_object_address() {
- ASSERT(IsPatchedReturnSequence());
- // The 2 instructions offset assumes patched return sequence.
- ASSERT(IsJSReturn(rmode()));
+ ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
+ (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
}
@@ -182,13 +231,76 @@ void RelocInfo::set_call_object(Object* target) {
bool RelocInfo::IsPatchedReturnSequence() {
-#ifdef DEBUG
- PrintF("%s - %d - %s : Checking for jal(r)",
- __FILE__, __LINE__, __func__);
+ Instr instr0 = Assembler::instr_at(pc_);
+ Instr instr1 = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize);
+ Instr instr2 = Assembler::instr_at(pc_ + 2 * Assembler::kInstrSize);
+ bool patched_return = ((instr0 & kOpcodeMask) == LUI &&
+ (instr1 & kOpcodeMask) == ORI &&
+ (instr2 & kOpcodeMask) == SPECIAL &&
+ (instr2 & kFunctionFieldMask) == JALR);
+ return patched_return;
+}
+
+
+bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
+ Instr current_instr = Assembler::instr_at(pc_);
+ return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
+}
+
+
+void RelocInfo::Visit(ObjectVisitor* visitor) {
+ RelocInfo::Mode mode = rmode();
+ if (mode == RelocInfo::EMBEDDED_OBJECT) {
+ // RelocInfo is needed when pointer must be updated/serialized, such as
+ // UpdatingVisitor in mark-compact.cc or Serializer in serialize.cc.
+ // It is ignored by visitors that do not need it.
+ // Commenting out, to simplify arch-independednt changes.
+ // GC won't work like this, but this commit is for asm/disasm/sim.
+ // visitor->VisitPointer(target_object_address(), this);
+ } else if (RelocInfo::IsCodeTarget(mode)) {
+ visitor->VisitCodeTarget(this);
+ } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
+ // RelocInfo is needed when external-references must be serialized by
+ // Serializer Visitor in serialize.cc. It is ignored by visitors that
+ // do not need it.
+ // Commenting out, to simplify arch-independednt changes.
+ // Serializer won't work like this, but this commit is for asm/disasm/sim.
+ // visitor->VisitExternalReference(target_reference_address(), this);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ // TODO(isolates): Get a cached isolate below.
+ } else if (((RelocInfo::IsJSReturn(mode) &&
+ IsPatchedReturnSequence()) ||
+ (RelocInfo::IsDebugBreakSlot(mode) &&
+ IsPatchedDebugBreakSlotSequence())) &&
+ Isolate::Current()->debug()->has_break_points()) {
+ visitor->VisitDebugTarget(this);
#endif
- return ((Assembler::instr_at(pc_) & kOpcodeMask) == SPECIAL) &&
- (((Assembler::instr_at(pc_) & kFunctionFieldMask) == JAL) ||
- ((Assembler::instr_at(pc_) & kFunctionFieldMask) == JALR));
+ } else if (mode == RelocInfo::RUNTIME_ENTRY) {
+ visitor->VisitRuntimeEntry(this);
+ }
+}
+
+
+template<typename StaticVisitor>
+void RelocInfo::Visit(Heap* heap) {
+ RelocInfo::Mode mode = rmode();
+ if (mode == RelocInfo::EMBEDDED_OBJECT) {
+ StaticVisitor::VisitPointer(heap, target_object_address());
+ } else if (RelocInfo::IsCodeTarget(mode)) {
+ StaticVisitor::VisitCodeTarget(this);
+ } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
+ StaticVisitor::VisitExternalReference(target_reference_address());
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ } else if (heap->isolate()->debug()->has_break_points() &&
+ ((RelocInfo::IsJSReturn(mode) &&
+ IsPatchedReturnSequence()) ||
+ (RelocInfo::IsDebugBreakSlot(mode) &&
+ IsPatchedDebugBreakSlotSequence()))) {
+ StaticVisitor::VisitDebugTarget(this);
+#endif
+ } else if (mode == RelocInfo::RUNTIME_ENTRY) {
+ StaticVisitor::VisitRuntimeEntry(this);
+ }
}
@@ -203,10 +315,18 @@ void Assembler::CheckBuffer() {
}
+void Assembler::CheckTrampolinePoolQuick() {
+ if (pc_offset() >= next_buffer_check_) {
+ CheckTrampolinePool();
+ }
+}
+
+
void Assembler::emit(Instr x) {
CheckBuffer();
*reinterpret_cast<Instr*>(pc_) = x;
pc_ += kInstrSize;
+ CheckTrampolinePoolQuick();
}
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index a3b316b1..7d00da1f 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -40,82 +40,40 @@
#include "mips/assembler-mips-inl.h"
#include "serialize.h"
-
namespace v8 {
namespace internal {
+CpuFeatures::CpuFeatures()
+ : supported_(0),
+ enabled_(0),
+ found_by_runtime_probing_(0) {
+}
+void CpuFeatures::Probe(bool portable) {
+ // If the compiler is allowed to use fpu then we can use fpu too in our
+ // code generation.
+#if !defined(__mips__)
+ // For the simulator=mips build, use FPU when FLAG_enable_fpu is enabled.
+ if (FLAG_enable_fpu) {
+ supported_ |= 1u << FPU;
+ }
+#else
+ if (portable && Serializer::enabled()) {
+ supported_ |= OS::CpuFeaturesImpliedByPlatform();
+ return; // No features if we might serialize.
+ }
+
+ if (OS::MipsCpuHasFeature(FPU)) {
+ // This implementation also sets the FPU flags if
+ // runtime detection of FPU returns true.
+ supported_ |= 1u << FPU;
+ found_by_runtime_probing_ |= 1u << FPU;
+ }
+
+ if (!portable) found_by_runtime_probing_ = 0;
+#endif
+}
-const Register no_reg = { -1 };
-
-const Register zero_reg = { 0 };
-const Register at = { 1 };
-const Register v0 = { 2 };
-const Register v1 = { 3 };
-const Register a0 = { 4 };
-const Register a1 = { 5 };
-const Register a2 = { 6 };
-const Register a3 = { 7 };
-const Register t0 = { 8 };
-const Register t1 = { 9 };
-const Register t2 = { 10 };
-const Register t3 = { 11 };
-const Register t4 = { 12 };
-const Register t5 = { 13 };
-const Register t6 = { 14 };
-const Register t7 = { 15 };
-const Register s0 = { 16 };
-const Register s1 = { 17 };
-const Register s2 = { 18 };
-const Register s3 = { 19 };
-const Register s4 = { 20 };
-const Register s5 = { 21 };
-const Register s6 = { 22 };
-const Register s7 = { 23 };
-const Register t8 = { 24 };
-const Register t9 = { 25 };
-const Register k0 = { 26 };
-const Register k1 = { 27 };
-const Register gp = { 28 };
-const Register sp = { 29 };
-const Register s8_fp = { 30 };
-const Register ra = { 31 };
-
-
-const FPURegister no_creg = { -1 };
-
-const FPURegister f0 = { 0 };
-const FPURegister f1 = { 1 };
-const FPURegister f2 = { 2 };
-const FPURegister f3 = { 3 };
-const FPURegister f4 = { 4 };
-const FPURegister f5 = { 5 };
-const FPURegister f6 = { 6 };
-const FPURegister f7 = { 7 };
-const FPURegister f8 = { 8 };
-const FPURegister f9 = { 9 };
-const FPURegister f10 = { 10 };
-const FPURegister f11 = { 11 };
-const FPURegister f12 = { 12 };
-const FPURegister f13 = { 13 };
-const FPURegister f14 = { 14 };
-const FPURegister f15 = { 15 };
-const FPURegister f16 = { 16 };
-const FPURegister f17 = { 17 };
-const FPURegister f18 = { 18 };
-const FPURegister f19 = { 19 };
-const FPURegister f20 = { 20 };
-const FPURegister f21 = { 21 };
-const FPURegister f22 = { 22 };
-const FPURegister f23 = { 23 };
-const FPURegister f24 = { 24 };
-const FPURegister f25 = { 25 };
-const FPURegister f26 = { 26 };
-const FPURegister f27 = { 27 };
-const FPURegister f28 = { 28 };
-const FPURegister f29 = { 29 };
-const FPURegister f30 = { 30 };
-const FPURegister f31 = { 31 };
int ToNumber(Register reg) {
ASSERT(reg.is_valid());
@@ -156,6 +114,7 @@ int ToNumber(Register reg) {
return kNumbers[reg.code()];
}
+
Register ToRegister(int num) {
ASSERT(num >= 0 && num < kNumRegisters);
const Register kRegisters[] = {
@@ -181,6 +140,15 @@ Register ToRegister(int num) {
const int RelocInfo::kApplyMask = 0;
+
+bool RelocInfo::IsCodedSpecially() {
+ // The deserializer needs to know whether a pointer is specially coded. Being
+ // specially coded on MIPS means that it is a lui/ori instruction, and that is
+ // always the case inside code objects.
+ return true;
+}
+
+
// Patch the code at the current address with the supplied instructions.
void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
Instr* pc = reinterpret_cast<Instr*>(pc_);
@@ -210,7 +178,7 @@ Operand::Operand(Handle<Object> handle) {
rm_ = no_reg;
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
- ASSERT(!Heap::InNewSpace(obj));
+ ASSERT(!HEAP->InNewSpace(obj));
if (obj->IsHeapObject()) {
imm32_ = reinterpret_cast<intptr_t>(handle.location());
rmode_ = RelocInfo::EMBEDDED_OBJECT;
@@ -221,26 +189,66 @@ Operand::Operand(Handle<Object> handle) {
}
}
-MemOperand::MemOperand(Register rm, int16_t offset) : Operand(rm) {
+
+MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
offset_ = offset;
}
// -----------------------------------------------------------------------------
-// Implementation of Assembler.
-
-static const int kMinimalBufferSize = 4*KB;
-static byte* spare_buffer_ = NULL;
-
-Assembler::Assembler(void* buffer, int buffer_size) {
+// Specific instructions, constants, and masks.
+
+static const int kNegOffset = 0x00008000;
+// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
+// operations as post-increment of sp.
+const Instr kPopInstruction = ADDIU | (sp.code() << kRsShift)
+ | (sp.code() << kRtShift) | (kPointerSize & kImm16Mask);
+// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
+const Instr kPushInstruction = ADDIU | (sp.code() << kRsShift)
+ | (sp.code() << kRtShift) | (-kPointerSize & kImm16Mask);
+// sw(r, MemOperand(sp, 0))
+const Instr kPushRegPattern = SW | (sp.code() << kRsShift)
+ | (0 & kImm16Mask);
+// lw(r, MemOperand(sp, 0))
+const Instr kPopRegPattern = LW | (sp.code() << kRsShift)
+ | (0 & kImm16Mask);
+
+const Instr kLwRegFpOffsetPattern = LW | (s8_fp.code() << kRsShift)
+ | (0 & kImm16Mask);
+
+const Instr kSwRegFpOffsetPattern = SW | (s8_fp.code() << kRsShift)
+ | (0 & kImm16Mask);
+
+const Instr kLwRegFpNegOffsetPattern = LW | (s8_fp.code() << kRsShift)
+ | (kNegOffset & kImm16Mask);
+
+const Instr kSwRegFpNegOffsetPattern = SW | (s8_fp.code() << kRsShift)
+ | (kNegOffset & kImm16Mask);
+// A mask for the Rt register for push, pop, lw, sw instructions.
+const Instr kRtMask = kRtFieldMask;
+const Instr kLwSwInstrTypeMask = 0xffe00000;
+const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
+const Instr kLwSwOffsetMask = kImm16Mask;
+
+
+// Spare buffer.
+static const int kMinimalBufferSize = 4 * KB;
+
+
+Assembler::Assembler(void* buffer, int buffer_size)
+ : AssemblerBase(Isolate::Current()),
+ positions_recorder_(this),
+ allow_peephole_optimization_(false) {
+ // BUG(3245989): disable peephole optimization if crankshaft is enabled.
+ allow_peephole_optimization_ = FLAG_peephole_optimization;
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
buffer_size = kMinimalBufferSize;
- if (spare_buffer_ != NULL) {
- buffer = spare_buffer_;
- spare_buffer_ = NULL;
+ if (isolate()->assembler_spare_buffer() != NULL) {
+ buffer = isolate()->assembler_spare_buffer();
+ isolate()->set_assembler_spare_buffer(NULL);
}
}
if (buffer == NULL) {
@@ -263,17 +271,19 @@ Assembler::Assembler(void* buffer, int buffer_size) {
ASSERT(buffer_ != NULL);
pc_ = buffer_;
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
- current_statement_position_ = RelocInfo::kNoPosition;
- current_position_ = RelocInfo::kNoPosition;
- written_statement_position_ = current_statement_position_;
- written_position_ = current_position_;
+
+ last_trampoline_pool_end_ = 0;
+ no_trampoline_pool_before_ = 0;
+ trampoline_pool_blocked_nesting_ = 0;
+ next_buffer_check_ = kMaxBranchOffset - kTrampolineSize;
}
Assembler::~Assembler() {
if (own_buffer_) {
- if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
- spare_buffer_ = buffer_;
+ if (isolate()->assembler_spare_buffer() == NULL &&
+ buffer_size_ == kMinimalBufferSize) {
+ isolate()->set_assembler_spare_buffer(buffer_);
} else {
DeleteArray(buffer_);
}
@@ -282,7 +292,7 @@ Assembler::~Assembler() {
void Assembler::GetCode(CodeDesc* desc) {
- ASSERT(pc_ <= reloc_info_writer.pos()); // no overlap
+ ASSERT(pc_ <= reloc_info_writer.pos()); // No overlap.
// Setup code descriptor.
desc->buffer = buffer_;
desc->buffer_size = buffer_size_;
@@ -291,6 +301,60 @@ void Assembler::GetCode(CodeDesc* desc) {
}
+void Assembler::Align(int m) {
+ ASSERT(m >= 4 && IsPowerOf2(m));
+ while ((pc_offset() & (m - 1)) != 0) {
+ nop();
+ }
+}
+
+
+void Assembler::CodeTargetAlign() {
+ // No advantage to aligning branch/call targets to more than
+ // single instruction, that I am aware of.
+ Align(4);
+}
+
+
+Register Assembler::GetRt(Instr instr) {
+ Register rt;
+ rt.code_ = (instr & kRtMask) >> kRtShift;
+ return rt;
+}
+
+
+bool Assembler::IsPop(Instr instr) {
+ return (instr & ~kRtMask) == kPopRegPattern;
+}
+
+
+bool Assembler::IsPush(Instr instr) {
+ return (instr & ~kRtMask) == kPushRegPattern;
+}
+
+
+bool Assembler::IsSwRegFpOffset(Instr instr) {
+ return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
+}
+
+
+bool Assembler::IsLwRegFpOffset(Instr instr) {
+ return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
+}
+
+
+bool Assembler::IsSwRegFpNegOffset(Instr instr) {
+ return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
+ kSwRegFpNegOffsetPattern);
+}
+
+
+bool Assembler::IsLwRegFpNegOffset(Instr instr) {
+ return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
+ kLwRegFpNegOffsetPattern);
+}
+
+
// Labels refer to positions in the (to be) generated code.
// There are bound, linked, and unused labels.
//
@@ -301,14 +365,19 @@ void Assembler::GetCode(CodeDesc* desc) {
// to be generated; pos() is the position of the last
// instruction using the label.
+// The link chain is terminated by a value in the instruction of -1,
+// which is an otherwise illegal value (branch -1 is inf loop).
+// The instruction 16-bit offset field addresses 32-bit words, but in
+// code is conv to an 18-bit value addressing bytes, hence the -4 value.
-// The link chain is terminated by a negative code position (must be aligned).
const int kEndOfChain = -4;
-bool Assembler::is_branch(Instr instr) {
+
+bool Assembler::IsBranch(Instr instr) {
uint32_t opcode = ((instr & kOpcodeMask));
uint32_t rt_field = ((instr & kRtFieldMask));
uint32_t rs_field = ((instr & kRsFieldMask));
+ uint32_t label_constant = (instr & ~kImm16Mask);
// Checks if the instruction is a branch.
return opcode == BEQ ||
opcode == BNE ||
@@ -320,7 +389,79 @@ bool Assembler::is_branch(Instr instr) {
opcode == BGTZL||
(opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
rt_field == BLTZAL || rt_field == BGEZAL)) ||
- (opcode == COP1 && rs_field == BC1); // Coprocessor branch.
+ (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
+ label_constant == 0; // Emitted label const in reg-exp engine.
+}
+
+
+bool Assembler::IsNop(Instr instr, unsigned int type) {
+ // See Assembler::nop(type).
+ ASSERT(type < 32);
+ uint32_t opcode = ((instr & kOpcodeMask));
+ uint32_t rt = ((instr & kRtFieldMask) >> kRtShift);
+ uint32_t rs = ((instr & kRsFieldMask) >> kRsShift);
+ uint32_t sa = ((instr & kSaFieldMask) >> kSaShift);
+
+ // nop(type) == sll(zero_reg, zero_reg, type);
+ // Technically all these values will be 0 but
+ // this makes more sense to the reader.
+
+ bool ret = (opcode == SLL &&
+ rt == static_cast<uint32_t>(ToNumber(zero_reg)) &&
+ rs == static_cast<uint32_t>(ToNumber(zero_reg)) &&
+ sa == type);
+
+ return ret;
+}
+
+
+int32_t Assembler::GetBranchOffset(Instr instr) {
+ ASSERT(IsBranch(instr));
+ return ((int16_t)(instr & kImm16Mask)) << 2;
+}
+
+
+bool Assembler::IsLw(Instr instr) {
+ return ((instr & kOpcodeMask) == LW);
+}
+
+
+int16_t Assembler::GetLwOffset(Instr instr) {
+ ASSERT(IsLw(instr));
+ return ((instr & kImm16Mask));
+}
+
+
+Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
+ ASSERT(IsLw(instr));
+
+ // We actually create a new lw instruction based on the original one.
+ Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
+ | (offset & kImm16Mask);
+
+ return temp_instr;
+}
+
+
+bool Assembler::IsSw(Instr instr) {
+ return ((instr & kOpcodeMask) == SW);
+}
+
+
+Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
+ ASSERT(IsSw(instr));
+ return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
+}
+
+
+bool Assembler::IsAddImmediate(Instr instr) {
+ return ((instr & kOpcodeMask) == ADDIU);
+}
+
+
+Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
+ ASSERT(IsAddImmediate(instr));
+ return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
}
@@ -328,16 +469,25 @@ int Assembler::target_at(int32_t pos) {
Instr instr = instr_at(pos);
if ((instr & ~kImm16Mask) == 0) {
// Emitted label constant, not part of a branch.
- return instr - (Code::kHeaderSize - kHeapObjectTag);
+ if (instr == 0) {
+ return kEndOfChain;
+ } else {
+ int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
+ return (imm18 + pos);
+ }
}
// Check we have a branch instruction.
- ASSERT(is_branch(instr));
+ ASSERT(IsBranch(instr));
// Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
// the compiler uses arithmectic shifts for signed integers.
- int32_t imm18 = ((instr &
- static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
+ int32_t imm18 = ((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
- return pos + kBranchPCOffset + imm18;
+ if (imm18 == kEndOfChain) {
+ // EndOfChain sentinel is returned directly, not relative to pc or pos.
+ return kEndOfChain;
+ } else {
+ return pos + kBranchPCOffset + imm18;
+ }
}
@@ -351,7 +501,7 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos) {
return;
}
- ASSERT(is_branch(instr));
+ ASSERT(IsBranch(instr));
int32_t imm18 = target_pos - (pos + kBranchPCOffset);
ASSERT((imm18 & 3) == 0);
@@ -388,10 +538,28 @@ void Assembler::print(Label* L) {
void Assembler::bind_to(Label* L, int pos) {
- ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position
+ ASSERT(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
while (L->is_linked()) {
int32_t fixup_pos = L->pos();
- next(L); // call next before overwriting link with target at fixup_pos
+ int32_t dist = pos - fixup_pos;
+ next(L); // Call next before overwriting link with target at fixup_pos.
+ if (dist > kMaxBranchOffset) {
+ do {
+ int32_t trampoline_pos = get_trampoline_entry(fixup_pos);
+ ASSERT((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
+ target_at_put(fixup_pos, trampoline_pos);
+ fixup_pos = trampoline_pos;
+ dist = pos - fixup_pos;
+ } while (dist > kMaxBranchOffset);
+ } else if (dist < -kMaxBranchOffset) {
+ do {
+ int32_t trampoline_pos = get_trampoline_entry(fixup_pos, false);
+ ASSERT((trampoline_pos - fixup_pos) >= -kMaxBranchOffset);
+ target_at_put(fixup_pos, trampoline_pos);
+ fixup_pos = trampoline_pos;
+ dist = pos - fixup_pos;
+ } while (dist < -kMaxBranchOffset);
+ };
target_at_put(fixup_pos, pos);
}
L->bind_to(pos);
@@ -416,16 +584,16 @@ void Assembler::link_to(Label* L, Label* appendix) {
ASSERT(link == kEndOfChain);
target_at_put(fixup_pos, appendix->pos());
} else {
- // L is empty, simply use appendix
+ // L is empty, simply use appendix.
*L = *appendix;
}
}
- appendix->Unuse(); // appendix should not be used anymore
+ appendix->Unuse(); // Appendix should not be used anymore.
}
void Assembler::bind(Label* L) {
- ASSERT(!L->is_bound()); // label can only be bound once
+ ASSERT(!L->is_bound()); // Label can only be bound once.
bind_to(L, pc_offset());
}
@@ -433,11 +601,11 @@ void Assembler::bind(Label* L) {
void Assembler::next(Label* L) {
ASSERT(L->is_linked());
int link = target_at(L->pos());
- if (link > 0) {
- L->link_to(link);
- } else {
- ASSERT(link == kEndOfChain);
+ ASSERT(link > 0 || link == kEndOfChain);
+ if (link == kEndOfChain) {
L->Unuse();
+ } else if (link > 0) {
+ L->link_to(link);
}
}
@@ -446,13 +614,8 @@ void Assembler::next(Label* L) {
// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
// space. There is no guarantee that the relocated location can be similarly
// encoded.
-bool Assembler::MustUseAt(RelocInfo::Mode rmode) {
- if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
- return Serializer::enabled();
- } else if (rmode == RelocInfo::NONE) {
- return false;
- }
- return true;
+bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
+ return rmode != RelocInfo::NONE;
}
@@ -470,14 +633,28 @@ void Assembler::GenInstrRegister(Opcode opcode,
void Assembler::GenInstrRegister(Opcode opcode,
+ Register rs,
+ Register rt,
+ uint16_t msb,
+ uint16_t lsb,
+ SecondaryField func) {
+ ASSERT(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
+ Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
+ | (msb << kRdShift) | (lsb << kSaShift) | func;
+ emit(instr);
+}
+
+
+void Assembler::GenInstrRegister(Opcode opcode,
SecondaryField fmt,
FPURegister ft,
FPURegister fs,
FPURegister fd,
SecondaryField func) {
ASSERT(fd.is_valid() && fs.is_valid() && ft.is_valid());
- Instr instr = opcode | fmt | (ft.code() << 16) | (fs.code() << kFsShift)
- | (fd.code() << 6) | func;
+ ASSERT(isolate()->cpu_features()->IsEnabled(FPU));
+ Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
+ | (fd.code() << kFdShift) | func;
emit(instr);
}
@@ -489,8 +666,22 @@ void Assembler::GenInstrRegister(Opcode opcode,
FPURegister fd,
SecondaryField func) {
ASSERT(fd.is_valid() && fs.is_valid() && rt.is_valid());
+ ASSERT(isolate()->cpu_features()->IsEnabled(FPU));
Instr instr = opcode | fmt | (rt.code() << kRtShift)
- | (fs.code() << kFsShift) | (fd.code() << 6) | func;
+ | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
+ emit(instr);
+}
+
+
+void Assembler::GenInstrRegister(Opcode opcode,
+ SecondaryField fmt,
+ Register rt,
+ FPUControlRegister fs,
+ SecondaryField func) {
+ ASSERT(fs.is_valid() && rt.is_valid());
+ ASSERT(isolate()->cpu_features()->IsEnabled(FPU));
+ Instr instr =
+ opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
emit(instr);
}
@@ -523,6 +714,7 @@ void Assembler::GenInstrImmediate(Opcode opcode,
FPURegister ft,
int32_t j) {
ASSERT(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
+ ASSERT(isolate()->cpu_features()->IsEnabled(FPU));
Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
| (j & kImm16Mask);
emit(instr);
@@ -532,26 +724,122 @@ void Assembler::GenInstrImmediate(Opcode opcode,
// Registers are in the order of the instruction encoding, from left to right.
void Assembler::GenInstrJump(Opcode opcode,
uint32_t address) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
ASSERT(is_uint26(address));
Instr instr = opcode | address;
emit(instr);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
+}
+
+
+// Returns the next free label entry from the next trampoline pool.
+int32_t Assembler::get_label_entry(int32_t pos, bool next_pool) {
+ int trampoline_count = trampolines_.length();
+ int32_t label_entry = 0;
+ ASSERT(trampoline_count > 0);
+
+ if (next_pool) {
+ for (int i = 0; i < trampoline_count; i++) {
+ if (trampolines_[i].start() > pos) {
+ label_entry = trampolines_[i].take_label();
+ break;
+ }
+ }
+ } else { // Caller needs a label entry from the previous pool.
+ for (int i = trampoline_count-1; i >= 0; i--) {
+ if (trampolines_[i].end() < pos) {
+ label_entry = trampolines_[i].take_label();
+ break;
+ }
+ }
+ }
+ return label_entry;
+}
+
+
+// Returns the next free trampoline entry from the next trampoline pool.
+int32_t Assembler::get_trampoline_entry(int32_t pos, bool next_pool) {
+ int trampoline_count = trampolines_.length();
+ int32_t trampoline_entry = 0;
+ ASSERT(trampoline_count > 0);
+
+ if (next_pool) {
+ for (int i = 0; i < trampoline_count; i++) {
+ if (trampolines_[i].start() > pos) {
+ trampoline_entry = trampolines_[i].take_slot();
+ break;
+ }
+ }
+ } else { // Caller needs a trampoline entry from the previous pool.
+ for (int i = trampoline_count-1; i >= 0; i--) {
+ if (trampolines_[i].end() < pos) {
+ trampoline_entry = trampolines_[i].take_slot();
+ break;
+ }
+ }
+ }
+ return trampoline_entry;
}
int32_t Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
int32_t target_pos;
+ int32_t pc_offset_v = pc_offset();
+
if (L->is_bound()) {
target_pos = L->pos();
+ int32_t dist = pc_offset_v - target_pos;
+ if (dist > kMaxBranchOffset) {
+ do {
+ int32_t trampoline_pos = get_trampoline_entry(target_pos);
+ ASSERT((trampoline_pos - target_pos) > 0);
+ ASSERT((trampoline_pos - target_pos) <= kMaxBranchOffset);
+ target_at_put(trampoline_pos, target_pos);
+ target_pos = trampoline_pos;
+ dist = pc_offset_v - target_pos;
+ } while (dist > kMaxBranchOffset);
+ } else if (dist < -kMaxBranchOffset) {
+ do {
+ int32_t trampoline_pos = get_trampoline_entry(target_pos, false);
+ ASSERT((target_pos - trampoline_pos) > 0);
+ ASSERT((target_pos - trampoline_pos) <= kMaxBranchOffset);
+ target_at_put(trampoline_pos, target_pos);
+ target_pos = trampoline_pos;
+ dist = pc_offset_v - target_pos;
+ } while (dist < -kMaxBranchOffset);
+ }
} else {
if (L->is_linked()) {
- target_pos = L->pos(); // L's link
+ target_pos = L->pos(); // L's link.
+ int32_t dist = pc_offset_v - target_pos;
+ if (dist > kMaxBranchOffset) {
+ do {
+ int32_t label_pos = get_label_entry(target_pos);
+ ASSERT((label_pos - target_pos) < kMaxBranchOffset);
+ label_at_put(L, label_pos);
+ target_pos = label_pos;
+ dist = pc_offset_v - target_pos;
+ } while (dist > kMaxBranchOffset);
+ } else if (dist < -kMaxBranchOffset) {
+ do {
+ int32_t label_pos = get_label_entry(target_pos, false);
+ ASSERT((label_pos - target_pos) > -kMaxBranchOffset);
+ label_at_put(L, label_pos);
+ target_pos = label_pos;
+ dist = pc_offset_v - target_pos;
+ } while (dist < -kMaxBranchOffset);
+ }
+ L->link_to(pc_offset());
} else {
- target_pos = kEndOfChain;
+ L->link_to(pc_offset());
+ return kEndOfChain;
}
- L->link_to(pc_offset());
}
int32_t offset = target_pos - (pc_offset() + kBranchPCOffset);
+ ASSERT((offset & 3) == 0);
+ ASSERT(is_int16(offset >> 2));
+
return offset;
}
@@ -560,14 +848,20 @@ void Assembler::label_at_put(Label* L, int at_offset) {
int target_pos;
if (L->is_bound()) {
target_pos = L->pos();
+ instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
} else {
if (L->is_linked()) {
- target_pos = L->pos(); // L's link
+ target_pos = L->pos(); // L's link.
+ int32_t imm18 = target_pos - at_offset;
+ ASSERT((imm18 & 3) == 0);
+ int32_t imm16 = imm18 >> 2;
+ ASSERT(is_int16(imm16));
+ instr_at_put(at_offset, (imm16 & kImm16Mask));
} else {
target_pos = kEndOfChain;
+ instr_at_put(at_offset, 0);
}
L->link_to(at_offset);
- instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
}
}
@@ -580,47 +874,66 @@ void Assembler::b(int16_t offset) {
void Assembler::bal(int16_t offset) {
+ positions_recorder()->WriteRecordedPositions();
bgezal(zero_reg, offset);
}
void Assembler::beq(Register rs, Register rt, int16_t offset) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(BEQ, rs, rt, offset);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
void Assembler::bgez(Register rs, int16_t offset) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(REGIMM, rs, BGEZ, offset);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
void Assembler::bgezal(Register rs, int16_t offset) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ positions_recorder()->WriteRecordedPositions();
GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
void Assembler::bgtz(Register rs, int16_t offset) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(BGTZ, rs, zero_reg, offset);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
void Assembler::blez(Register rs, int16_t offset) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(BLEZ, rs, zero_reg, offset);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
void Assembler::bltz(Register rs, int16_t offset) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(REGIMM, rs, BLTZ, offset);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
void Assembler::bltzal(Register rs, int16_t offset) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ positions_recorder()->WriteRecordedPositions();
GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
void Assembler::bne(Register rs, Register rt, int16_t offset) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(BNE, rs, rt, offset);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
@@ -631,18 +944,27 @@ void Assembler::j(int32_t target) {
void Assembler::jr(Register rs) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ if (rs.is(ra)) {
+ positions_recorder()->WriteRecordedPositions();
+ }
GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
void Assembler::jal(int32_t target) {
+ positions_recorder()->WriteRecordedPositions();
ASSERT(is_uint28(target) && ((target & 3) == 0));
GenInstrJump(JAL, target >> 2);
}
void Assembler::jalr(Register rs, Register rd) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ positions_recorder()->WriteRecordedPositions();
GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
+ BlockTrampolinePoolFor(1); // For associated delay slot.
}
@@ -650,28 +972,164 @@ void Assembler::jalr(Register rs, Register rd) {
// Arithmetic.
-void Assembler::add(Register rd, Register rs, Register rt) {
- GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADD);
-}
-
-
void Assembler::addu(Register rd, Register rs, Register rt) {
GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
}
-void Assembler::addi(Register rd, Register rs, int32_t j) {
- GenInstrImmediate(ADDI, rs, rd, j);
-}
-
-
void Assembler::addiu(Register rd, Register rs, int32_t j) {
GenInstrImmediate(ADDIU, rs, rd, j);
-}
+ // Eliminate pattern: push(r), pop().
+ // addiu(sp, sp, Operand(-kPointerSize));
+ // sw(src, MemOperand(sp, 0);
+ // addiu(sp, sp, Operand(kPointerSize));
+ // Both instructions can be eliminated.
+ if (can_peephole_optimize(3) &&
+ // Pattern.
+ instr_at(pc_ - 1 * kInstrSize) == kPopInstruction &&
+ (instr_at(pc_ - 2 * kInstrSize) & ~kRtMask) == kPushRegPattern &&
+ (instr_at(pc_ - 3 * kInstrSize)) == kPushInstruction) {
+ pc_ -= 3 * kInstrSize;
+ if (FLAG_print_peephole_optimization) {
+ PrintF("%x push(reg)/pop() eliminated\n", pc_offset());
+ }
+ }
+
+ // Eliminate pattern: push(ry), pop(rx).
+ // addiu(sp, sp, -kPointerSize)
+ // sw(ry, MemOperand(sp, 0)
+ // lw(rx, MemOperand(sp, 0)
+ // addiu(sp, sp, kPointerSize);
+ // Both instructions can be eliminated if ry = rx.
+ // If ry != rx, a register copy from ry to rx is inserted
+ // after eliminating the push and the pop instructions.
+ if (can_peephole_optimize(4)) {
+ Instr pre_push_sp_set = instr_at(pc_ - 4 * kInstrSize);
+ Instr push_instr = instr_at(pc_ - 3 * kInstrSize);
+ Instr pop_instr = instr_at(pc_ - 2 * kInstrSize);
+ Instr post_pop_sp_set = instr_at(pc_ - 1 * kInstrSize);
+
+ if (IsPush(push_instr) &&
+ IsPop(pop_instr) && pre_push_sp_set == kPushInstruction &&
+ post_pop_sp_set == kPopInstruction) {
+ if ((pop_instr & kRtMask) != (push_instr & kRtMask)) {
+ // For consecutive push and pop on different registers,
+ // we delete both the push & pop and insert a register move.
+ // push ry, pop rx --> mov rx, ry.
+ Register reg_pushed, reg_popped;
+ reg_pushed = GetRt(push_instr);
+ reg_popped = GetRt(pop_instr);
+ pc_ -= 4 * kInstrSize;
+ // Insert a mov instruction, which is better than a pair of push & pop.
+ or_(reg_popped, reg_pushed, zero_reg);
+ if (FLAG_print_peephole_optimization) {
+ PrintF("%x push/pop (diff reg) replaced by a reg move\n",
+ pc_offset());
+ }
+ } else {
+ // For consecutive push and pop on the same register,
+ // both the push and the pop can be deleted.
+ pc_ -= 4 * kInstrSize;
+ if (FLAG_print_peephole_optimization) {
+ PrintF("%x push/pop (same reg) eliminated\n", pc_offset());
+ }
+ }
+ }
+ }
-void Assembler::sub(Register rd, Register rs, Register rt) {
- GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUB);
+ if (can_peephole_optimize(5)) {
+ Instr pre_push_sp_set = instr_at(pc_ - 5 * kInstrSize);
+ Instr mem_write_instr = instr_at(pc_ - 4 * kInstrSize);
+ Instr lw_instr = instr_at(pc_ - 3 * kInstrSize);
+ Instr mem_read_instr = instr_at(pc_ - 2 * kInstrSize);
+ Instr post_pop_sp_set = instr_at(pc_ - 1 * kInstrSize);
+
+ if (IsPush(mem_write_instr) &&
+ pre_push_sp_set == kPushInstruction &&
+ IsPop(mem_read_instr) &&
+ post_pop_sp_set == kPopInstruction) {
+ if ((IsLwRegFpOffset(lw_instr) ||
+ IsLwRegFpNegOffset(lw_instr))) {
+ if ((mem_write_instr & kRtMask) ==
+ (mem_read_instr & kRtMask)) {
+ // Pattern: push & pop from/to same register,
+ // with a fp+offset lw in between.
+ //
+ // The following:
+ // addiu sp, sp, -4
+ // sw rx, [sp, #0]!
+ // lw rz, [fp, #-24]
+ // lw rx, [sp, 0],
+ // addiu sp, sp, 4
+ //
+ // Becomes:
+ // if(rx == rz)
+ // delete all
+ // else
+ // lw rz, [fp, #-24]
+
+ if ((mem_write_instr & kRtMask) == (lw_instr & kRtMask)) {
+ pc_ -= 5 * kInstrSize;
+ } else {
+ pc_ -= 5 * kInstrSize;
+ // Reinsert back the lw rz.
+ emit(lw_instr);
+ }
+ if (FLAG_print_peephole_optimization) {
+ PrintF("%x push/pop -dead ldr fp+offset in middle\n", pc_offset());
+ }
+ } else {
+ // Pattern: push & pop from/to different registers
+ // with a fp + offset lw in between.
+ //
+ // The following:
+ // addiu sp, sp ,-4
+ // sw rx, [sp, 0]
+ // lw rz, [fp, #-24]
+ // lw ry, [sp, 0]
+ // addiu sp, sp, 4
+ //
+ // Becomes:
+ // if(ry == rz)
+ // mov ry, rx;
+ // else if(rx != rz)
+ // lw rz, [fp, #-24]
+ // mov ry, rx
+ // else if((ry != rz) || (rx == rz)) becomes:
+ // mov ry, rx
+ // lw rz, [fp, #-24]
+
+ Register reg_pushed, reg_popped;
+ if ((mem_read_instr & kRtMask) == (lw_instr & kRtMask)) {
+ reg_pushed = GetRt(mem_write_instr);
+ reg_popped = GetRt(mem_read_instr);
+ pc_ -= 5 * kInstrSize;
+ or_(reg_popped, reg_pushed, zero_reg); // Move instruction.
+ } else if ((mem_write_instr & kRtMask)
+ != (lw_instr & kRtMask)) {
+ reg_pushed = GetRt(mem_write_instr);
+ reg_popped = GetRt(mem_read_instr);
+ pc_ -= 5 * kInstrSize;
+ emit(lw_instr);
+ or_(reg_popped, reg_pushed, zero_reg); // Move instruction.
+ } else if (((mem_read_instr & kRtMask)
+ != (lw_instr & kRtMask)) ||
+ ((mem_write_instr & kRtMask)
+ == (lw_instr & kRtMask)) ) {
+ reg_pushed = GetRt(mem_write_instr);
+ reg_popped = GetRt(mem_read_instr);
+ pc_ -= 5 * kInstrSize;
+ or_(reg_popped, reg_pushed, zero_reg); // Move instruction.
+ emit(lw_instr);
+ }
+ if (FLAG_print_peephole_optimization) {
+ PrintF("%x push/pop (ldr fp+off in middle)\n", pc_offset());
+ }
+ }
+ }
+ }
+ }
}
@@ -743,7 +1201,15 @@ void Assembler::nor(Register rd, Register rs, Register rt) {
// Shifts.
-void Assembler::sll(Register rd, Register rt, uint16_t sa) {
+void Assembler::sll(Register rd,
+ Register rt,
+ uint16_t sa,
+ bool coming_from_nop) {
+ // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
+ // generated using the sll instruction. They must be generated using
+ // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
+ // instructions.
+ ASSERT(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SLL);
}
@@ -773,30 +1239,199 @@ void Assembler::srav(Register rd, Register rt, Register rs) {
}
+void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
+ // Should be called via MacroAssembler::Ror.
+ ASSERT(rd.is_valid() && rt.is_valid() && is_uint5(sa));
+ ASSERT(mips32r2);
+ Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
+ | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
+ emit(instr);
+}
+
+
+void Assembler::rotrv(Register rd, Register rt, Register rs) {
+ // Should be called via MacroAssembler::Ror.
+ ASSERT(rd.is_valid() && rt.is_valid() && rs.is_valid() );
+ ASSERT(mips32r2);
+ Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
+ | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
+ emit(instr);
+}
+
+
//------------Memory-instructions-------------
+// Helper for base-reg + offset, when offset is larger than int16.
+void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
+ ASSERT(!src.rm().is(at));
+ lui(at, src.offset_ >> kLuiShift);
+ ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
+ addu(at, at, src.rm()); // Add base register.
+}
+
+
void Assembler::lb(Register rd, const MemOperand& rs) {
- GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
+ if (is_int16(rs.offset_)) {
+ GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
+ } else { // Offset > 16 bits, use multiple instructions to load.
+ LoadRegPlusOffsetToAt(rs);
+ GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
+ }
}
void Assembler::lbu(Register rd, const MemOperand& rs) {
- GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
+ if (is_int16(rs.offset_)) {
+ GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
+ } else { // Offset > 16 bits, use multiple instructions to load.
+ LoadRegPlusOffsetToAt(rs);
+ GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
+ }
+}
+
+
+void Assembler::lh(Register rd, const MemOperand& rs) {
+ if (is_int16(rs.offset_)) {
+ GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
+ } else { // Offset > 16 bits, use multiple instructions to load.
+ LoadRegPlusOffsetToAt(rs);
+ GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
+ }
+}
+
+
+void Assembler::lhu(Register rd, const MemOperand& rs) {
+ if (is_int16(rs.offset_)) {
+ GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
+ } else { // Offset > 16 bits, use multiple instructions to load.
+ LoadRegPlusOffsetToAt(rs);
+ GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
+ }
}
void Assembler::lw(Register rd, const MemOperand& rs) {
- GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
+ if (is_int16(rs.offset_)) {
+ GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
+ } else { // Offset > 16 bits, use multiple instructions to load.
+ LoadRegPlusOffsetToAt(rs);
+ GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
+ }
+
+ if (can_peephole_optimize(2)) {
+ Instr sw_instr = instr_at(pc_ - 2 * kInstrSize);
+ Instr lw_instr = instr_at(pc_ - 1 * kInstrSize);
+
+ if ((IsSwRegFpOffset(sw_instr) &&
+ IsLwRegFpOffset(lw_instr)) ||
+ (IsSwRegFpNegOffset(sw_instr) &&
+ IsLwRegFpNegOffset(lw_instr))) {
+ if ((lw_instr & kLwSwInstrArgumentMask) ==
+ (sw_instr & kLwSwInstrArgumentMask)) {
+ // Pattern: Lw/sw same fp+offset, same register.
+ //
+ // The following:
+ // sw rx, [fp, #-12]
+ // lw rx, [fp, #-12]
+ //
+ // Becomes:
+ // sw rx, [fp, #-12]
+
+ pc_ -= 1 * kInstrSize;
+ if (FLAG_print_peephole_optimization) {
+ PrintF("%x sw/lw (fp + same offset), same reg\n", pc_offset());
+ }
+ } else if ((lw_instr & kLwSwOffsetMask) ==
+ (sw_instr & kLwSwOffsetMask)) {
+ // Pattern: Lw/sw same fp+offset, different register.
+ //
+ // The following:
+ // sw rx, [fp, #-12]
+ // lw ry, [fp, #-12]
+ //
+ // Becomes:
+ // sw rx, [fp, #-12]
+ // mov ry, rx
+
+ Register reg_stored, reg_loaded;
+ reg_stored = GetRt(sw_instr);
+ reg_loaded = GetRt(lw_instr);
+ pc_ -= 1 * kInstrSize;
+ // Insert a mov instruction, which is better than lw.
+ or_(reg_loaded, reg_stored, zero_reg); // Move instruction.
+ if (FLAG_print_peephole_optimization) {
+ PrintF("%x sw/lw (fp + same offset), diff reg \n", pc_offset());
+ }
+ }
+ }
+ }
+}
+
+
+void Assembler::lwl(Register rd, const MemOperand& rs) {
+ GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
+}
+
+
+void Assembler::lwr(Register rd, const MemOperand& rs) {
+ GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
}
void Assembler::sb(Register rd, const MemOperand& rs) {
- GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
+ if (is_int16(rs.offset_)) {
+ GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
+ } else { // Offset > 16 bits, use multiple instructions to store.
+ LoadRegPlusOffsetToAt(rs);
+ GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
+ }
+}
+
+
+void Assembler::sh(Register rd, const MemOperand& rs) {
+ if (is_int16(rs.offset_)) {
+ GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
+ } else { // Offset > 16 bits, use multiple instructions to store.
+ LoadRegPlusOffsetToAt(rs);
+ GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
+ }
}
void Assembler::sw(Register rd, const MemOperand& rs) {
- GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
+ if (is_int16(rs.offset_)) {
+ GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
+ } else { // Offset > 16 bits, use multiple instructions to store.
+ LoadRegPlusOffsetToAt(rs);
+ GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
+ }
+
+ // Eliminate pattern: pop(), push(r).
+ // addiu sp, sp, Operand(kPointerSize);
+ // addiu sp, sp, Operand(-kPointerSize);
+ // -> sw r, MemOpernad(sp, 0);
+ if (can_peephole_optimize(3) &&
+ // Pattern.
+ instr_at(pc_ - 1 * kInstrSize) ==
+ (kPushRegPattern | (rd.code() << kRtShift)) &&
+ instr_at(pc_ - 2 * kInstrSize) == kPushInstruction &&
+ instr_at(pc_ - 3 * kInstrSize) == kPopInstruction) {
+ pc_ -= 3 * kInstrSize;
+ GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
+ if (FLAG_print_peephole_optimization) {
+ PrintF("%x pop()/push(reg) eliminated\n", pc_offset());
+ }
+ }
+}
+
+
+void Assembler::swl(Register rd, const MemOperand& rs) {
+ GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
+}
+
+
+void Assembler::swr(Register rd, const MemOperand& rs) {
+ GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
}
@@ -841,7 +1476,8 @@ void Assembler::tlt(Register rs, Register rt, uint16_t code) {
void Assembler::tltu(Register rs, Register rt, uint16_t code) {
ASSERT(is_uint10(code));
- Instr instr = SPECIAL | TLTU | rs.code() << kRsShift
+ Instr instr =
+ SPECIAL | TLTU | rs.code() << kRsShift
| rt.code() << kRtShift | code << 6;
emit(instr);
}
@@ -896,6 +1532,54 @@ void Assembler::sltiu(Register rt, Register rs, int32_t j) {
}
+// Conditional move.
+void Assembler::movz(Register rd, Register rs, Register rt) {
+ GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
+}
+
+
+void Assembler::movn(Register rd, Register rs, Register rt) {
+ GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
+}
+
+
+void Assembler::movt(Register rd, Register rs, uint16_t cc) {
+ Register rt;
+ rt.code_ = (cc & 0x0003) << 2 | 1;
+ GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
+}
+
+
+void Assembler::movf(Register rd, Register rs, uint16_t cc) {
+ Register rt;
+ rt.code_ = (cc & 0x0003) << 2 | 0;
+ GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
+}
+
+
+// Bit twiddling.
+void Assembler::clz(Register rd, Register rs) {
+ // Clz instr requires same GPR number in 'rd' and 'rt' fields.
+ GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
+}
+
+
+void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
+ // Should be called via MacroAssembler::Ins.
+ // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
+ ASSERT(mips32r2);
+ GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
+}
+
+
+void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
+ // Should be called via MacroAssembler::Ext.
+ // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
+ ASSERT(mips32r2);
+ GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
+}
+
+
//--------Coprocessor-instructions----------------
// Load, store, move.
@@ -905,7 +1589,12 @@ void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
- GenInstrImmediate(LDC1, src.rm(), fd, src.offset_);
+ // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
+ // load to two 32-bit loads.
+ GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
+ FPURegister nextfpreg;
+ nextfpreg.setcode(fd.code() + 1);
+ GenInstrImmediate(LWC1, src.rm(), nextfpreg, src.offset_ + 4);
}
@@ -915,27 +1604,74 @@ void Assembler::swc1(FPURegister fd, const MemOperand& src) {
void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
- GenInstrImmediate(SDC1, src.rm(), fd, src.offset_);
+ // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
+ // store to two 32-bit stores.
+ GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
+ FPURegister nextfpreg;
+ nextfpreg.setcode(fd.code() + 1);
+ GenInstrImmediate(SWC1, src.rm(), nextfpreg, src.offset_ + 4);
}
-void Assembler::mtc1(FPURegister fs, Register rt) {
+void Assembler::mtc1(Register rt, FPURegister fs) {
GenInstrRegister(COP1, MTC1, rt, fs, f0);
}
-void Assembler::mthc1(FPURegister fs, Register rt) {
- GenInstrRegister(COP1, MTHC1, rt, fs, f0);
+void Assembler::mfc1(Register rt, FPURegister fs) {
+ GenInstrRegister(COP1, MFC1, rt, fs, f0);
}
-void Assembler::mfc1(FPURegister fs, Register rt) {
- GenInstrRegister(COP1, MFC1, rt, fs, f0);
+void Assembler::ctc1(Register rt, FPUControlRegister fs) {
+ GenInstrRegister(COP1, CTC1, rt, fs);
+}
+
+
+void Assembler::cfc1(Register rt, FPUControlRegister fs) {
+ GenInstrRegister(COP1, CFC1, rt, fs);
+}
+
+
+// Arithmetic.
+
+void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
+ GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
+}
+
+
+void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
+ GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
+}
+
+
+void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
+ GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
+}
+
+
+void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
+ GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
+}
+
+
+void Assembler::abs_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
}
-void Assembler::mfhc1(FPURegister fs, Register rt) {
- GenInstrRegister(COP1, MFHC1, rt, fs, f0);
+void Assembler::mov_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
+}
+
+
+void Assembler::neg_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
+}
+
+
+void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
}
@@ -951,22 +1687,107 @@ void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
}
+void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
+}
+
+
+void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
+}
+
+
+void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
+}
+
+
+void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
+}
+
+
+void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
+}
+
+
+void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
+}
+
+
+void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
+}
+
+
+void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
+}
+
+
void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
+ ASSERT(mips32r2);
GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
}
void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
+ ASSERT(mips32r2);
GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
}
+void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
+ ASSERT(mips32r2);
+ GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
+}
+
+
+void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
+ ASSERT(mips32r2);
+ GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
+}
+
+
+void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
+}
+
+
+void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
+}
+
+
+void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
+}
+
+
+void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
+}
+
+
+void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
+}
+
+
+void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
+ GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
+}
+
+
void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
}
void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
+ ASSERT(mips32r2);
GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
}
@@ -982,6 +1803,7 @@ void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
+ ASSERT(mips32r2);
GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
}
@@ -993,7 +1815,8 @@ void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
// Conditions.
void Assembler::c(FPUCondition cond, SecondaryField fmt,
- FPURegister ft, FPURegister fs, uint16_t cc) {
+ FPURegister fs, FPURegister ft, uint16_t cc) {
+ ASSERT(isolate()->cpu_features()->IsEnabled(FPU));
ASSERT(is_uint3(cc));
ASSERT((fmt & ~(31 << kRsShift)) == 0);
Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
@@ -1002,7 +1825,18 @@ void Assembler::c(FPUCondition cond, SecondaryField fmt,
}
+void Assembler::fcmp(FPURegister src1, const double src2,
+ FPUCondition cond) {
+ ASSERT(isolate()->cpu_features()->IsSupported(FPU));
+ ASSERT(src2 == 0.0);
+ mtc1(zero_reg, f14);
+ cvt_d_w(f14, f14);
+ c(cond, D, src1, f14, 0);
+}
+
+
void Assembler::bc1f(int16_t offset, uint16_t cc) {
+ ASSERT(isolate()->cpu_features()->IsEnabled(FPU));
ASSERT(is_uint3(cc));
Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
emit(instr);
@@ -1010,6 +1844,7 @@ void Assembler::bc1f(int16_t offset, uint16_t cc) {
void Assembler::bc1t(int16_t offset, uint16_t cc) {
+ ASSERT(isolate()->cpu_features()->IsEnabled(FPU));
ASSERT(is_uint3(cc));
Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
emit(instr);
@@ -1018,58 +1853,24 @@ void Assembler::bc1t(int16_t offset, uint16_t cc) {
// Debugging.
void Assembler::RecordJSReturn() {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
CheckBuffer();
RecordRelocInfo(RelocInfo::JS_RETURN);
}
-void Assembler::RecordComment(const char* msg) {
- if (FLAG_debug_code) {
- CheckBuffer();
- RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
- }
-}
-
-
-void Assembler::RecordPosition(int pos) {
- if (pos == RelocInfo::kNoPosition) return;
- ASSERT(pos >= 0);
- current_position_ = pos;
-}
-
-
-void Assembler::RecordStatementPosition(int pos) {
- if (pos == RelocInfo::kNoPosition) return;
- ASSERT(pos >= 0);
- current_statement_position_ = pos;
+void Assembler::RecordDebugBreakSlot() {
+ positions_recorder()->WriteRecordedPositions();
+ CheckBuffer();
+ RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
-bool Assembler::WriteRecordedPositions() {
- bool written = false;
-
- // Write the statement position if it is different from what was written last
- // time.
- if (current_statement_position_ != written_statement_position_) {
- CheckBuffer();
- RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
- written_statement_position_ = current_statement_position_;
- written = true;
- }
-
- // Write the position if it is different from what was written last time and
- // also different from the written statement position.
- if (current_position_ != written_position_ &&
- current_position_ != written_statement_position_) {
+void Assembler::RecordComment(const char* msg) {
+ if (FLAG_code_comments) {
CheckBuffer();
- RecordRelocInfo(RelocInfo::POSITION, current_position_);
- written_position_ = current_position_;
- written = true;
+ RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
}
-
- // Return whether something was written.
- return written;
}
@@ -1077,7 +1878,7 @@ void Assembler::GrowBuffer() {
if (!own_buffer_) FATAL("external code buffer is too small");
// Compute new buffer size.
- CodeDesc desc; // the new buffer
+ CodeDesc desc; // The new buffer.
if (buffer_size_ < 4*KB) {
desc.buffer_size = 4*KB;
} else if (buffer_size_ < 1*MB) {
@@ -1085,7 +1886,7 @@ void Assembler::GrowBuffer() {
} else {
desc.buffer_size = buffer_size_ + 1*MB;
}
- CHECK_GT(desc.buffer_size, 0); // no overflow
+ CHECK_GT(desc.buffer_size, 0); // No overflow.
// Setup new buffer.
desc.buffer = NewArray<byte>(desc.buffer_size);
@@ -1108,7 +1909,6 @@ void Assembler::GrowBuffer() {
reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
reloc_info_writer.last_pc() + pc_delta);
-
// On ia32 and ARM pc relative addressing is used, and we thus need to apply a
// shift by pc_delta. But on MIPS the target address it directly loaded, so
// we do not need to relocate here.
@@ -1117,11 +1917,26 @@ void Assembler::GrowBuffer() {
}
+void Assembler::db(uint8_t data) {
+ CheckBuffer();
+ *reinterpret_cast<uint8_t*>(pc_) = data;
+ pc_ += sizeof(uint8_t);
+}
+
+
+void Assembler::dd(uint32_t data) {
+ CheckBuffer();
+ *reinterpret_cast<uint32_t*>(pc_) = data;
+ pc_ += sizeof(uint32_t);
+}
+
+
void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
- RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants
- if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::STATEMENT_POSITION) {
+ RelocInfo rinfo(pc_, rmode, data); // We do not try to reuse pool constants.
+ if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
// Adjust code for new modes.
- ASSERT(RelocInfo::IsJSReturn(rmode)
+ ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
+ || RelocInfo::IsJSReturn(rmode)
|| RelocInfo::IsComment(rmode)
|| RelocInfo::IsPosition(rmode));
// These modes do not need an entry in the constant pool.
@@ -1133,12 +1948,72 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
!FLAG_debug_code) {
return;
}
- ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
+ ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
reloc_info_writer.Write(&rinfo);
}
}
+void Assembler::BlockTrampolinePoolFor(int instructions) {
+ BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
+}
+
+
+void Assembler::CheckTrampolinePool(bool force_emit) {
+ // Calculate the offset of the next check.
+ next_buffer_check_ = pc_offset() + kCheckConstInterval;
+
+ int dist = pc_offset() - last_trampoline_pool_end_;
+
+ if (dist <= kMaxDistBetweenPools && !force_emit) {
+ return;
+ }
+
+ // Some small sequences of instructions must not be broken up by the
+ // insertion of a trampoline pool; such sequences are protected by setting
+ // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
+ // which are both checked here. Also, recursive calls to CheckTrampolinePool
+ // are blocked by trampoline_pool_blocked_nesting_.
+ if ((trampoline_pool_blocked_nesting_ > 0) ||
+ (pc_offset() < no_trampoline_pool_before_)) {
+ // Emission is currently blocked; make sure we try again as soon as
+ // possible.
+ if (trampoline_pool_blocked_nesting_ > 0) {
+ next_buffer_check_ = pc_offset() + kInstrSize;
+ } else {
+ next_buffer_check_ = no_trampoline_pool_before_;
+ }
+ return;
+ }
+
+ // First we emit jump (2 instructions), then we emit trampoline pool.
+ { BlockTrampolinePoolScope block_trampoline_pool(this);
+ Label after_pool;
+ b(&after_pool);
+ nop();
+
+ int pool_start = pc_offset();
+ for (int i = 0; i < kSlotsPerTrampoline; i++) {
+ b(&after_pool);
+ nop();
+ }
+ for (int i = 0; i < kLabelsPerTrampoline; i++) {
+ emit(0);
+ }
+ last_trampoline_pool_end_ = pc_offset() - kInstrSize;
+ bind(&after_pool);
+ trampolines_.Add(Trampoline(pool_start,
+ kSlotsPerTrampoline,
+ kLabelsPerTrampoline));
+
+ // Since a trampoline pool was just emitted,
+ // move the check offset forward by the standard interval.
+ next_buffer_check_ = last_trampoline_pool_end_ + kMaxDistBetweenPools;
+ }
+ return;
+}
+
+
Address Assembler::target_address_at(Address pc) {
Instr instr1 = instr_at(pc);
Instr instr2 = instr_at(pc + kInstrSize);
@@ -1157,7 +2032,7 @@ Address Assembler::target_address_at(Address pc) {
return reinterpret_cast<Address>((instr2 & kImm16Mask) << 16);
}
} else if ((instr1 & kOpcodeMask) == LUI && (instr2 & kOpcodeMask) == ORI) {
- // 32 bits value.
+ // 32 bit value.
return reinterpret_cast<Address>(
(instr1 & kImm16Mask) << 16 | (instr2 & kImm16Mask));
}
@@ -1176,38 +2051,37 @@ void Assembler::set_target_address_at(Address pc, Address target) {
#ifdef DEBUG
Instr instr1 = instr_at(pc);
- // Check we have indeed the result from a li with MustUseAt true.
+ // Check we have indeed the result from a li with MustUseReg true.
CHECK(((instr1 & kOpcodeMask) == LUI && (instr2 & kOpcodeMask) == ORI) ||
((instr1 == 0) && ((instr2 & kOpcodeMask)== ADDIU ||
(instr2 & kOpcodeMask)== ORI ||
(instr2 & kOpcodeMask)== LUI)));
#endif
-
uint32_t rt_code = (instr2 & kRtFieldMask);
uint32_t* p = reinterpret_cast<uint32_t*>(pc);
uint32_t itarget = reinterpret_cast<uint32_t>(target);
if (is_int16(itarget)) {
- // nop
- // addiu rt zero_reg j
+ // nop.
+ // addiu rt zero_reg j.
*p = nopInstr;
- *(p+1) = ADDIU | rt_code | (itarget & LOMask);
- } else if (!(itarget & HIMask)) {
- // nop
- // ori rt zero_reg j
+ *(p+1) = ADDIU | rt_code | (itarget & kImm16Mask);
+ } else if (!(itarget & kHiMask)) {
+ // nop.
+ // ori rt zero_reg j.
*p = nopInstr;
- *(p+1) = ORI | rt_code | (itarget & LOMask);
- } else if (!(itarget & LOMask)) {
- // nop
- // lui rt (HIMask & itarget)>>16
+ *(p+1) = ORI | rt_code | (itarget & kImm16Mask);
+ } else if (!(itarget & kImm16Mask)) {
+ // nop.
+ // lui rt (kHiMask & itarget) >> kLuiShift.
*p = nopInstr;
- *(p+1) = LUI | rt_code | ((itarget & HIMask)>>16);
+ *(p+1) = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
} else {
- // lui rt (HIMask & itarget)>>16
- // ori rt rt, (LOMask & itarget)
- *p = LUI | rt_code | ((itarget & HIMask)>>16);
- *(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & LOMask);
+ // lui rt (kHiMask & itarget) >> kLuiShift.
+ // ori rt rt, (kImm16Mask & itarget).
+ *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
+ *(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
}
CPU::FlushICache(pc, 2 * sizeof(int32_t));
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index a687c2b8..5a6e2715 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -41,8 +41,6 @@
#include "constants-mips.h"
#include "serialize.h"
-using namespace assembler::mips;
-
namespace v8 {
namespace internal {
@@ -73,6 +71,44 @@ namespace internal {
// Core register.
struct Register {
+ static const int kNumRegisters = v8::internal::kNumRegisters;
+ static const int kNumAllocatableRegisters = 14; // v0 through t7
+
+ static int ToAllocationIndex(Register reg) {
+ return reg.code() - 2; // zero_reg and 'at' are skipped.
+ }
+
+ static Register FromAllocationIndex(int index) {
+ ASSERT(index >= 0 && index < kNumAllocatableRegisters);
+ return from_code(index + 2); // zero_reg and 'at' are skipped.
+ }
+
+ static const char* AllocationIndexToString(int index) {
+ ASSERT(index >= 0 && index < kNumAllocatableRegisters);
+ const char* const names[] = {
+ "v0",
+ "v1",
+ "a0",
+ "a1",
+ "a2",
+ "a3",
+ "t0",
+ "t1",
+ "t2",
+ "t3",
+ "t4",
+ "t5",
+ "t6",
+ "t7",
+ };
+ return names[index];
+ }
+
+ static Register from_code(int code) {
+ Register r = { code };
+ return r;
+ }
+
bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
bool is(Register reg) const { return code_ == reg.code_; }
int code() const {
@@ -88,40 +124,41 @@ struct Register {
int code_;
};
-extern const Register no_reg;
-
-extern const Register zero_reg;
-extern const Register at;
-extern const Register v0;
-extern const Register v1;
-extern const Register a0;
-extern const Register a1;
-extern const Register a2;
-extern const Register a3;
-extern const Register t0;
-extern const Register t1;
-extern const Register t2;
-extern const Register t3;
-extern const Register t4;
-extern const Register t5;
-extern const Register t6;
-extern const Register t7;
-extern const Register s0;
-extern const Register s1;
-extern const Register s2;
-extern const Register s3;
-extern const Register s4;
-extern const Register s5;
-extern const Register s6;
-extern const Register s7;
-extern const Register t8;
-extern const Register t9;
-extern const Register k0;
-extern const Register k1;
-extern const Register gp;
-extern const Register sp;
-extern const Register s8_fp;
-extern const Register ra;
+const Register no_reg = { -1 };
+
+const Register zero_reg = { 0 };
+const Register at = { 1 };
+const Register v0 = { 2 };
+const Register v1 = { 3 };
+const Register a0 = { 4 };
+const Register a1 = { 5 };
+const Register a2 = { 6 };
+const Register a3 = { 7 };
+const Register t0 = { 8 };
+const Register t1 = { 9 };
+const Register t2 = { 10 };
+const Register t3 = { 11 };
+const Register t4 = { 12 };
+const Register t5 = { 13 };
+const Register t6 = { 14 };
+const Register t7 = { 15 };
+const Register s0 = { 16 };
+const Register s1 = { 17 };
+const Register s2 = { 18 };
+const Register s3 = { 19 };
+const Register s4 = { 20 };
+const Register s5 = { 21 };
+const Register s6 = { 22 };
+const Register s7 = { 23 };
+const Register t8 = { 24 };
+const Register t9 = { 25 };
+const Register k0 = { 26 };
+const Register k1 = { 27 };
+const Register gp = { 28 };
+const Register sp = { 29 };
+const Register s8_fp = { 30 };
+const Register ra = { 31 };
+
int ToNumber(Register reg);
@@ -129,7 +166,50 @@ Register ToRegister(int num);
// Coprocessor register.
struct FPURegister {
- bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegister ; }
+ static const int kNumRegisters = v8::internal::kNumFPURegisters;
+ // f0 has been excluded from allocation. This is following ia32
+ // where xmm0 is excluded.
+ static const int kNumAllocatableRegisters = 15;
+
+ static int ToAllocationIndex(FPURegister reg) {
+ ASSERT(reg.code() != 0);
+ ASSERT(reg.code() % 2 == 0);
+ return (reg.code() / 2) - 1;
+ }
+
+ static FPURegister FromAllocationIndex(int index) {
+ ASSERT(index >= 0 && index < kNumAllocatableRegisters);
+ return from_code((index + 1) * 2);
+ }
+
+ static const char* AllocationIndexToString(int index) {
+ ASSERT(index >= 0 && index < kNumAllocatableRegisters);
+ const char* const names[] = {
+ "f2",
+ "f4",
+ "f6",
+ "f8",
+ "f10",
+ "f12",
+ "f14",
+ "f16",
+ "f18",
+ "f20",
+ "f22",
+ "f24",
+ "f26",
+ "f28",
+ "f30"
+ };
+ return names[index];
+ }
+
+ static FPURegister from_code(int code) {
+ FPURegister r = { code };
+ return r;
+ }
+
+ bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegisters ; }
bool is(FPURegister creg) const { return code_ == creg.code_; }
int code() const {
ASSERT(is_valid());
@@ -139,84 +219,77 @@ struct FPURegister {
ASSERT(is_valid());
return 1 << code_;
}
-
+ void setcode(int f) {
+ code_ = f;
+ ASSERT(is_valid());
+ }
// Unfortunately we can't make this private in a struct.
int code_;
};
-extern const FPURegister no_creg;
-
-extern const FPURegister f0;
-extern const FPURegister f1;
-extern const FPURegister f2;
-extern const FPURegister f3;
-extern const FPURegister f4;
-extern const FPURegister f5;
-extern const FPURegister f6;
-extern const FPURegister f7;
-extern const FPURegister f8;
-extern const FPURegister f9;
-extern const FPURegister f10;
-extern const FPURegister f11;
-extern const FPURegister f12; // arg
-extern const FPURegister f13;
-extern const FPURegister f14; // arg
-extern const FPURegister f15;
-extern const FPURegister f16;
-extern const FPURegister f17;
-extern const FPURegister f18;
-extern const FPURegister f19;
-extern const FPURegister f20;
-extern const FPURegister f21;
-extern const FPURegister f22;
-extern const FPURegister f23;
-extern const FPURegister f24;
-extern const FPURegister f25;
-extern const FPURegister f26;
-extern const FPURegister f27;
-extern const FPURegister f28;
-extern const FPURegister f29;
-extern const FPURegister f30;
-extern const FPURegister f31;
-
-
-// Returns the equivalent of !cc.
-// Negation of the default no_condition (-1) results in a non-default
-// no_condition value (-2). As long as tests for no_condition check
-// for condition < 0, this will work as expected.
-inline Condition NegateCondition(Condition cc);
-
-inline Condition ReverseCondition(Condition cc) {
- switch (cc) {
- case Uless:
- return Ugreater;
- case Ugreater:
- return Uless;
- case Ugreater_equal:
- return Uless_equal;
- case Uless_equal:
- return Ugreater_equal;
- case less:
- return greater;
- case greater:
- return less;
- case greater_equal:
- return less_equal;
- case less_equal:
- return greater_equal;
- default:
- return cc;
- };
-}
-
-
-enum Hint {
- no_hint = 0
+typedef FPURegister DoubleRegister;
+
+const FPURegister no_creg = { -1 };
+
+const FPURegister f0 = { 0 }; // Return value in hard float mode.
+const FPURegister f1 = { 1 };
+const FPURegister f2 = { 2 };
+const FPURegister f3 = { 3 };
+const FPURegister f4 = { 4 };
+const FPURegister f5 = { 5 };
+const FPURegister f6 = { 6 };
+const FPURegister f7 = { 7 };
+const FPURegister f8 = { 8 };
+const FPURegister f9 = { 9 };
+const FPURegister f10 = { 10 };
+const FPURegister f11 = { 11 };
+const FPURegister f12 = { 12 }; // Arg 0 in hard float mode.
+const FPURegister f13 = { 13 };
+const FPURegister f14 = { 14 }; // Arg 1 in hard float mode.
+const FPURegister f15 = { 15 };
+const FPURegister f16 = { 16 };
+const FPURegister f17 = { 17 };
+const FPURegister f18 = { 18 };
+const FPURegister f19 = { 19 };
+const FPURegister f20 = { 20 };
+const FPURegister f21 = { 21 };
+const FPURegister f22 = { 22 };
+const FPURegister f23 = { 23 };
+const FPURegister f24 = { 24 };
+const FPURegister f25 = { 25 };
+const FPURegister f26 = { 26 };
+const FPURegister f27 = { 27 };
+const FPURegister f28 = { 28 };
+const FPURegister f29 = { 29 };
+const FPURegister f30 = { 30 };
+const FPURegister f31 = { 31 };
+
+// FPU (coprocessor 1) control registers.
+// Currently only FCSR (#31) is implemented.
+struct FPUControlRegister {
+ static const int kFCSRRegister = 31;
+ static const int kInvalidFPUControlRegister = -1;
+
+ bool is_valid() const { return code_ == kFCSRRegister; }
+ bool is(FPUControlRegister creg) const { return code_ == creg.code_; }
+ int code() const {
+ ASSERT(is_valid());
+ return code_;
+ }
+ int bit() const {
+ ASSERT(is_valid());
+ return 1 << code_;
+ }
+ void setcode(int f) {
+ code_ = f;
+ ASSERT(is_valid());
+ }
+ // Unfortunately we can't make this private in a struct.
+ int code_;
};
-inline Hint NegateHint(Hint hint) {
- return no_hint;
-}
+const FPUControlRegister no_fpucreg = { -1 };
+const FPUControlRegister FCSR = { kFCSRRegister };
// -----------------------------------------------------------------------------
@@ -258,16 +331,75 @@ class Operand BASE_EMBEDDED {
class MemOperand : public Operand {
public:
- explicit MemOperand(Register rn, int16_t offset = 0);
+ explicit MemOperand(Register rn, int32_t offset = 0);
private:
- int16_t offset_;
+ int32_t offset_;
friend class Assembler;
};
-class Assembler : public Malloced {
+// CpuFeatures keeps track of which features are supported by the target CPU.
+// Supported features must be enabled by a Scope before use.
+class CpuFeatures {
+ public:
+ // Detect features of the target CPU. Set safe defaults if the serializer
+ // is enabled (snapshots must be portable).
+ void Probe(bool portable);
+
+ // Check whether a feature is supported by the target CPU.
+ bool IsSupported(CpuFeature f) const {
+ if (f == FPU && !FLAG_enable_fpu) return false;
+ return (supported_ & (1u << f)) != 0;
+ }
+
+ // Check whether a feature is currently enabled.
+ bool IsEnabled(CpuFeature f) const {
+ return (enabled_ & (1u << f)) != 0;
+ }
+
+ // Enable a specified feature within a scope.
+ class Scope BASE_EMBEDDED {
+#ifdef DEBUG
+ public:
+ explicit Scope(CpuFeature f)
+ : cpu_features_(Isolate::Current()->cpu_features()),
+ isolate_(Isolate::Current()) {
+ ASSERT(cpu_features_->IsSupported(f));
+ ASSERT(!Serializer::enabled() ||
+ (cpu_features_->found_by_runtime_probing_ & (1u << f)) == 0);
+ old_enabled_ = cpu_features_->enabled_;
+ cpu_features_->enabled_ |= 1u << f;
+ }
+ ~Scope() {
+ ASSERT_EQ(Isolate::Current(), isolate_);
+ cpu_features_->enabled_ = old_enabled_;
+ }
+ private:
+ unsigned old_enabled_;
+ CpuFeatures* cpu_features_;
+ Isolate* isolate_;
+#else
+ public:
+ explicit Scope(CpuFeature f) {}
+#endif
+ };
+
+ private:
+ CpuFeatures();
+
+ unsigned supported_;
+ unsigned enabled_;
+ unsigned found_by_runtime_probing_;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
+};
+
+
+class Assembler : public AssemblerBase {
public:
// Create an assembler. Instructions and relocation information are emitted
// into a buffer, with the instructions starting from the beginning and the
@@ -285,6 +417,9 @@ class Assembler : public Malloced {
Assembler(void* buffer, int buffer_size);
~Assembler();
+ // Overrides the default provided by FLAG_debug_code.
+ void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
+
// GetCode emits any pending (non-emitted) code and fills the descriptor
// desc. GetCode() is idempotent; it returns the same result if no other
// Assembler functions are invoked in between GetCode() calls.
@@ -320,12 +455,6 @@ class Assembler : public Malloced {
// The high 8 bits are set to zero.
void label_at_put(Label* L, int at_offset);
- // Size of an instruction.
- static const int kInstrSize = sizeof(Instr);
-
- // Difference between address of current opcode and target address offset.
- static const int kBranchPCOffset = 4;
-
// Read/Modify the code target address in the branch/call instruction at pc.
static Address target_address_at(Address pc);
static void set_target_address_at(Address pc, Address target);
@@ -344,8 +473,25 @@ class Assembler : public Malloced {
set_target_address_at(instruction_payload, target);
}
- static const int kCallTargetSize = 3 * kPointerSize;
- static const int kExternalTargetSize = 3 * kPointerSize;
+ // Size of an instruction.
+ static const int kInstrSize = sizeof(Instr);
+
+ // Difference between address of current opcode and target address offset.
+ static const int kBranchPCOffset = 4;
+
+ // Here we are patching the address in the LUI/ORI instruction pair.
+ // These values are used in the serialization process and must be zero for
+ // MIPS platform, as Code, Embedded Object or External-reference pointers
+ // are split across two consecutive instructions and don't exist separately
+ // in the code, so the serializer should not step forwards in memory after
+ // a target is resolved and written.
+ static const int kCallTargetSize = 0 * kInstrSize;
+ static const int kExternalTargetSize = 0 * kInstrSize;
+
+ // Number of consecutive instructions used to store 32bit constant.
+ // Used in RelocInfo::target_address_address() function to tell serializer
+ // address of the instruction that follows LUI/ORI instruction pair.
+ static const int kInstructionsFor32BitConstant = 2;
// Distance between the instruction referring to the address of the call
// target and the return address.
@@ -353,16 +499,53 @@ class Assembler : public Malloced {
// Distance between start of patched return sequence and the emitted address
// to jump to.
- static const int kPatchReturnSequenceAddressOffset = kInstrSize;
+ static const int kPatchReturnSequenceAddressOffset = 0;
// Distance between start of patched debug break slot and the emitted address
// to jump to.
- static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
+ static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
+
+ // Difference between address of current opcode and value read from pc
+ // register.
+ static const int kPcLoadDelta = 4;
+
+ // Number of instructions used for the JS return sequence. The constant is
+ // used by the debugger to patch the JS return sequence.
+ static const int kJSReturnSequenceInstructions = 7;
+ static const int kDebugBreakSlotInstructions = 4;
+ static const int kDebugBreakSlotLength =
+ kDebugBreakSlotInstructions * kInstrSize;
+
// ---------------------------------------------------------------------------
// Code generation.
- void nop() { sll(zero_reg, zero_reg, 0); }
+ // Insert the smallest number of nop instructions
+ // possible to align the pc offset to a multiple
+ // of m. m must be a power of 2 (>= 4).
+ void Align(int m);
+ // Aligns code to something that's optimal for a jump target for the platform.
+ void CodeTargetAlign();
+
+ // Different nop operations are used by the code generator to detect certain
+ // states of the generated code.
+ enum NopMarkerTypes {
+ NON_MARKING_NOP = 0,
+ DEBUG_BREAK_NOP,
+ // IC markers.
+ PROPERTY_ACCESS_INLINED,
+ PROPERTY_ACCESS_INLINED_CONTEXT,
+ PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
+ // Helper values.
+ LAST_CODE_MARKER,
+ FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
+ };
+
+ // type == 0 is the default non-marking type.
+ void nop(unsigned int type = 0) {
+ ASSERT(type < 32);
+ sll(zero_reg, zero_reg, type, true);
+ }
//------- Branch and jump instructions --------
@@ -400,9 +583,7 @@ class Assembler : public Malloced {
//-------Data-processing-instructions---------
// Arithmetic.
- void add(Register rd, Register rs, Register rt);
void addu(Register rd, Register rs, Register rt);
- void sub(Register rd, Register rs, Register rt);
void subu(Register rd, Register rs, Register rt);
void mult(Register rs, Register rt);
void multu(Register rs, Register rt);
@@ -410,7 +591,6 @@ class Assembler : public Malloced {
void divu(Register rs, Register rt);
void mul(Register rd, Register rs, Register rt);
- void addi(Register rd, Register rs, int32_t j);
void addiu(Register rd, Register rs, int32_t j);
// Logical.
@@ -425,21 +605,33 @@ class Assembler : public Malloced {
void lui(Register rd, int32_t j);
// Shifts.
- void sll(Register rd, Register rt, uint16_t sa);
+ // Please note: sll(zero_reg, zero_reg, x) instructions are reserved as nop
+ // and may cause problems in normal code. coming_from_nop makes sure this
+ // doesn't happen.
+ void sll(Register rd, Register rt, uint16_t sa, bool coming_from_nop = false);
void sllv(Register rd, Register rt, Register rs);
void srl(Register rd, Register rt, uint16_t sa);
void srlv(Register rd, Register rt, Register rs);
void sra(Register rt, Register rd, uint16_t sa);
void srav(Register rt, Register rd, Register rs);
+ void rotr(Register rd, Register rt, uint16_t sa);
+ void rotrv(Register rd, Register rt, Register rs);
//------------Memory-instructions-------------
void lb(Register rd, const MemOperand& rs);
void lbu(Register rd, const MemOperand& rs);
+ void lh(Register rd, const MemOperand& rs);
+ void lhu(Register rd, const MemOperand& rs);
void lw(Register rd, const MemOperand& rs);
+ void lwl(Register rd, const MemOperand& rs);
+ void lwr(Register rd, const MemOperand& rs);
void sb(Register rd, const MemOperand& rs);
+ void sh(Register rd, const MemOperand& rs);
void sw(Register rd, const MemOperand& rs);
+ void swl(Register rd, const MemOperand& rs);
+ void swr(Register rd, const MemOperand& rs);
//-------------Misc-instructions--------------
@@ -463,6 +655,16 @@ class Assembler : public Malloced {
void slti(Register rd, Register rs, int32_t j);
void sltiu(Register rd, Register rs, int32_t j);
+ // Conditional move.
+ void movz(Register rd, Register rs, Register rt);
+ void movn(Register rd, Register rs, Register rt);
+ void movt(Register rd, Register rs, uint16_t cc = 0);
+ void movf(Register rd, Register rs, uint16_t cc = 0);
+
+ // Bit twiddling.
+ void clz(Register rd, Register rs);
+ void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
+ void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
//--------Coprocessor-instructions----------------
@@ -473,19 +675,44 @@ class Assembler : public Malloced {
void swc1(FPURegister fs, const MemOperand& dst);
void sdc1(FPURegister fs, const MemOperand& dst);
- // When paired with MTC1 to write a value to a 64-bit FPR, the MTC1 must be
- // executed first, followed by the MTHC1.
- void mtc1(FPURegister fs, Register rt);
- void mthc1(FPURegister fs, Register rt);
- void mfc1(FPURegister fs, Register rt);
- void mfhc1(FPURegister fs, Register rt);
+ void mtc1(Register rt, FPURegister fs);
+ void mfc1(Register rt, FPURegister fs);
+
+ void ctc1(Register rt, FPUControlRegister fs);
+ void cfc1(Register rt, FPUControlRegister fs);
+
+ // Arithmetic.
+ void add_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void sub_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void mul_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void abs_d(FPURegister fd, FPURegister fs);
+ void mov_d(FPURegister fd, FPURegister fs);
+ void neg_d(FPURegister fd, FPURegister fs);
+ void sqrt_d(FPURegister fd, FPURegister fs);
// Conversion.
void cvt_w_s(FPURegister fd, FPURegister fs);
void cvt_w_d(FPURegister fd, FPURegister fs);
+ void trunc_w_s(FPURegister fd, FPURegister fs);
+ void trunc_w_d(FPURegister fd, FPURegister fs);
+ void round_w_s(FPURegister fd, FPURegister fs);
+ void round_w_d(FPURegister fd, FPURegister fs);
+ void floor_w_s(FPURegister fd, FPURegister fs);
+ void floor_w_d(FPURegister fd, FPURegister fs);
+ void ceil_w_s(FPURegister fd, FPURegister fs);
+ void ceil_w_d(FPURegister fd, FPURegister fs);
void cvt_l_s(FPURegister fd, FPURegister fs);
void cvt_l_d(FPURegister fd, FPURegister fs);
+ void trunc_l_s(FPURegister fd, FPURegister fs);
+ void trunc_l_d(FPURegister fd, FPURegister fs);
+ void round_l_s(FPURegister fd, FPURegister fs);
+ void round_l_d(FPURegister fd, FPURegister fs);
+ void floor_l_s(FPURegister fd, FPURegister fs);
+ void floor_l_d(FPURegister fd, FPURegister fs);
+ void ceil_l_s(FPURegister fd, FPURegister fs);
+ void ceil_l_d(FPURegister fd, FPURegister fs);
void cvt_s_w(FPURegister fd, FPURegister fs);
void cvt_s_l(FPURegister fd, FPURegister fs);
@@ -503,32 +730,60 @@ class Assembler : public Malloced {
void bc1f(Label* L, uint16_t cc = 0) { bc1f(branch_offset(L, false)>>2, cc); }
void bc1t(int16_t offset, uint16_t cc = 0);
void bc1t(Label* L, uint16_t cc = 0) { bc1t(branch_offset(L, false)>>2, cc); }
-
+ void fcmp(FPURegister src1, const double src2, FPUCondition cond);
// Check the code size generated from label to here.
int InstructionsGeneratedSince(Label* l) {
return (pc_offset() - l->pos()) / kInstrSize;
}
+ // Class for scoping postponing the trampoline pool generation.
+ class BlockTrampolinePoolScope {
+ public:
+ explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) {
+ assem_->StartBlockTrampolinePool();
+ }
+ ~BlockTrampolinePoolScope() {
+ assem_->EndBlockTrampolinePool();
+ }
+
+ private:
+ Assembler* assem_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
+ };
+
// Debugging.
// Mark address of the ExitJSFrame code.
void RecordJSReturn();
+ // Mark address of a debug break slot.
+ void RecordDebugBreakSlot();
+
// Record a comment relocation entry that can be used by a disassembler.
- // Use --debug_code to enable.
+ // Use --code-comments to enable.
void RecordComment(const char* msg);
- void RecordPosition(int pos);
- void RecordStatementPosition(int pos);
- bool WriteRecordedPositions();
+ // Writes a single byte or word of data in the code stream. Used for
+ // inline tables, e.g., jump-tables.
+ void db(uint8_t data);
+ void dd(uint32_t data);
int32_t pc_offset() const { return pc_ - buffer_; }
- int32_t current_position() const { return current_position_; }
- int32_t current_statement_position() const {
- return current_statement_position_;
+
+ PositionsRecorder* positions_recorder() { return &positions_recorder_; }
+
+ bool can_peephole_optimize(int instructions) {
+ if (!allow_peephole_optimization_) return false;
+ if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false;
+ return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize;
}
+ // Postpone the generation of the trampoline pool for the specified number of
+ // instructions.
+ void BlockTrampolinePoolFor(int instructions);
+
// Check if there is less than kGap bytes available in the buffer.
// If this is the case, we need to grow the buffer before emitting
// an instruction or relocation information.
@@ -537,12 +792,9 @@ class Assembler : public Malloced {
// Get the number of bytes available in the buffer.
inline int available_space() const { return reloc_info_writer.pos() - pc_; }
- protected:
- int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; }
-
// Read/patch instructions.
static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
- void instr_at_put(byte* pc, Instr instr) {
+ static void instr_at_put(byte* pc, Instr instr) {
*reinterpret_cast<Instr*>(pc) = instr;
}
Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
@@ -551,7 +803,34 @@ class Assembler : public Malloced {
}
// Check if an instruction is a branch of some kind.
- bool is_branch(Instr instr);
+ static bool IsBranch(Instr instr);
+
+ static bool IsNop(Instr instr, unsigned int type);
+ static bool IsPop(Instr instr);
+ static bool IsPush(Instr instr);
+ static bool IsLwRegFpOffset(Instr instr);
+ static bool IsSwRegFpOffset(Instr instr);
+ static bool IsLwRegFpNegOffset(Instr instr);
+ static bool IsSwRegFpNegOffset(Instr instr);
+
+ static Register GetRt(Instr instr);
+
+ static int32_t GetBranchOffset(Instr instr);
+ static bool IsLw(Instr instr);
+ static int16_t GetLwOffset(Instr instr);
+ static Instr SetLwOffset(Instr instr, int16_t offset);
+
+ static bool IsSw(Instr instr);
+ static Instr SetSwOffset(Instr instr, int16_t offset);
+ static bool IsAddImmediate(Instr instr);
+ static Instr SetAddImmediateOffset(Instr instr, int16_t offset);
+
+ void CheckTrampolinePool(bool force_emit = false);
+
+ protected:
+ bool emit_debug_code() const { return emit_debug_code_; }
+
+ int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; }
// Decode branch instruction at pos and return branch target pos.
int target_at(int32_t pos);
@@ -560,11 +839,28 @@ class Assembler : public Malloced {
void target_at_put(int32_t pos, int32_t target_pos);
// Say if we need to relocate with this mode.
- bool MustUseAt(RelocInfo::Mode rmode);
+ bool MustUseReg(RelocInfo::Mode rmode);
// Record reloc info for current pc_.
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
+ // Block the emission of the trampoline pool before pc_offset.
+ void BlockTrampolinePoolBefore(int pc_offset) {
+ if (no_trampoline_pool_before_ < pc_offset)
+ no_trampoline_pool_before_ = pc_offset;
+ }
+
+ void StartBlockTrampolinePool() {
+ trampoline_pool_blocked_nesting_++;
+ }
+ void EndBlockTrampolinePool() {
+ trampoline_pool_blocked_nesting_--;
+ }
+
+ bool is_trampoline_pool_blocked() const {
+ return trampoline_pool_blocked_nesting_ > 0;
+ }
+
private:
// Code buffer:
// The buffer into which code and relocation info are generated.
@@ -585,6 +881,22 @@ class Assembler : public Malloced {
static const int kGap = 32;
byte* pc_; // The program counter - moves forward.
+
+ // Repeated checking whether the trampoline pool should be emitted is rather
+ // expensive. By default we only check again once a number of instructions
+ // has been generated.
+ static const int kCheckConstIntervalInst = 32;
+ static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
+
+ int next_buffer_check_; // pc offset of next buffer check.
+
+ // Emission of the trampoline pool may be blocked in some code sequences.
+ int trampoline_pool_blocked_nesting_; // Block emission if this is not zero.
+ int no_trampoline_pool_before_; // Block emission before this pc offset.
+
+ // Keep track of the last emitted pool to guarantee a maximal distance.
+ int last_trampoline_pool_end_; // pc offset of the end of the last pool.
+
// Relocation information generation.
// Each relocation is encoded as a variable size value.
static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
@@ -593,16 +905,11 @@ class Assembler : public Malloced {
// The bound position, before this we cannot do instruction elimination.
int last_bound_pos_;
- // Source position information.
- int current_position_;
- int current_statement_position_;
- int written_position_;
- int written_statement_position_;
-
// Code emission.
inline void CheckBuffer();
void GrowBuffer();
inline void emit(Instr x);
+ inline void CheckTrampolinePoolQuick();
// Instruction generation.
// We have 3 different kind of encoding layout on MIPS.
@@ -620,6 +927,13 @@ class Assembler : public Malloced {
SecondaryField func = NULLSF);
void GenInstrRegister(Opcode opcode,
+ Register rs,
+ Register rt,
+ uint16_t msb,
+ uint16_t lsb,
+ SecondaryField func);
+
+ void GenInstrRegister(Opcode opcode,
SecondaryField fmt,
FPURegister ft,
FPURegister fs,
@@ -633,6 +947,12 @@ class Assembler : public Malloced {
FPURegister fd,
SecondaryField func = NULLSF);
+ void GenInstrRegister(Opcode opcode,
+ SecondaryField fmt,
+ Register rt,
+ FPUControlRegister fs,
+ SecondaryField func = NULLSF);
+
void GenInstrImmediate(Opcode opcode,
Register rs,
@@ -651,6 +971,8 @@ class Assembler : public Malloced {
void GenInstrJump(Opcode opcode,
uint32_t address);
+ // Helpers.
+ void LoadRegPlusOffsetToAt(const MemOperand& src);
// Labels.
void print(Label* L);
@@ -658,8 +980,85 @@ class Assembler : public Malloced {
void link_to(Label* L, Label* appendix);
void next(Label* L);
+ // One trampoline consists of:
+ // - space for trampoline slots,
+ // - space for labels.
+ //
+ // Space for trampoline slots is equal to slot_count * 2 * kInstrSize.
+ // Space for trampoline slots preceeds space for labels. Each label is of one
+ // instruction size, so total amount for labels is equal to
+ // label_count * kInstrSize.
+ class Trampoline {
+ public:
+ Trampoline(int start, int slot_count, int label_count) {
+ start_ = start;
+ next_slot_ = start;
+ free_slot_count_ = slot_count;
+ next_label_ = start + slot_count * 2 * kInstrSize;
+ free_label_count_ = label_count;
+ end_ = next_label_ + (label_count - 1) * kInstrSize;
+ }
+ int start() {
+ return start_;
+ }
+ int end() {
+ return end_;
+ }
+ int take_slot() {
+ int trampoline_slot = next_slot_;
+ ASSERT(free_slot_count_ > 0);
+ free_slot_count_--;
+ next_slot_ += 2 * kInstrSize;
+ return trampoline_slot;
+ }
+ int take_label() {
+ int label_pos = next_label_;
+ ASSERT(free_label_count_ > 0);
+ free_label_count_--;
+ next_label_ += kInstrSize;
+ return label_pos;
+ }
+ private:
+ int start_;
+ int end_;
+ int next_slot_;
+ int free_slot_count_;
+ int next_label_;
+ int free_label_count_;
+ };
+
+ int32_t get_label_entry(int32_t pos, bool next_pool = true);
+ int32_t get_trampoline_entry(int32_t pos, bool next_pool = true);
+
+ static const int kSlotsPerTrampoline = 2304;
+ static const int kLabelsPerTrampoline = 8;
+ static const int kTrampolineInst =
+ 2 * kSlotsPerTrampoline + kLabelsPerTrampoline;
+ static const int kTrampolineSize = kTrampolineInst * kInstrSize;
+ static const int kMaxBranchOffset = (1 << (18 - 1)) - 1;
+ static const int kMaxDistBetweenPools =
+ kMaxBranchOffset - 2 * kTrampolineSize;
+
+ List<Trampoline> trampolines_;
+
friend class RegExpMacroAssemblerMIPS;
friend class RelocInfo;
+ friend class CodePatcher;
+ friend class BlockTrampolinePoolScope;
+
+ PositionsRecorder positions_recorder_;
+ bool allow_peephole_optimization_;
+ bool emit_debug_code_;
+ friend class PositionsRecorder;
+ friend class EnsureSpace;
+};
+
+
+class EnsureSpace BASE_EMBEDDED {
+ public:
+ explicit EnsureSpace(Assembler* assembler) {
+ assembler->CheckBuffer();
+ }
};
} } // namespace v8::internal
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index 95329389..b4bab8ef 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -33,6 +33,8 @@
#include "codegen-inl.h"
#include "debug.h"
+#include "deoptimizer.h"
+#include "full-codegen.h"
#include "runtime.h"
namespace v8 {
@@ -59,126 +61,68 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
}
+void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
UNIMPLEMENTED_MIPS();
}
-void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
UNIMPLEMENTED_MIPS();
}
-void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
UNIMPLEMENTED_MIPS();
}
-static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
- bool is_construct) {
- // Called from JSEntryStub::GenerateBody
-
- // Registers:
- // a0: entry_address
- // a1: function
- // a2: reveiver_pointer
- // a3: argc
- // s0: argv
- //
- // Stack:
- // arguments slots
- // handler frame
- // entry frame
- // callee saved registers + ra
- // 4 args slots
- // args
-
- // Clear the context before we push it when entering the JS frame.
- __ li(cp, Operand(0, RelocInfo::NONE));
-
- // Enter an internal frame.
- __ EnterInternalFrame();
-
- // Set up the context from the function argument.
- __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
-
- // Set up the roots register.
- ExternalReference roots_address = ExternalReference::roots_address();
- __ li(s6, Operand(roots_address));
-
- // Push the function and the receiver onto the stack.
- __ MultiPushReversed(a1.bit() | a2.bit());
-
- // Copy arguments to the stack in a loop.
- // a3: argc
- // s0: argv, ie points to first arg
- Label loop, entry;
- __ sll(t0, a3, kPointerSizeLog2);
- __ add(t2, s0, t0);
- __ b(&entry);
- __ nop(); // Branch delay slot nop.
- // t2 points past last arg.
- __ bind(&loop);
- __ lw(t0, MemOperand(s0)); // Read next parameter.
- __ addiu(s0, s0, kPointerSize);
- __ lw(t0, MemOperand(t0)); // Dereference handle.
- __ Push(t0); // Push parameter.
- __ bind(&entry);
- __ Branch(ne, &loop, s0, Operand(t2));
-
- // Registers:
- // a0: entry_address
- // a1: function
- // a2: reveiver_pointer
- // a3: argc
- // s0: argv
- // s6: roots_address
- //
- // Stack:
- // arguments
- // receiver
- // function
- // arguments slots
- // handler frame
- // entry frame
- // callee saved registers + ra
- // 4 args slots
- // args
-
- // Initialize all JavaScript callee-saved registers, since they will be seen
- // by the garbage collector as part of handlers.
- __ LoadRoot(t4, Heap::kUndefinedValueRootIndex);
- __ mov(s1, t4);
- __ mov(s2, t4);
- __ mov(s3, t4);
- __ mov(s4, s4);
- __ mov(s5, t4);
- // s6 holds the root address. Do not clobber.
- // s7 is cp. Do not init.
-
- // Invoke the code and pass argc as a0.
- __ mov(a0, a3);
- if (is_construct) {
- UNIMPLEMENTED_MIPS();
- __ break_(0x164);
- } else {
- ParameterCount actual(a0);
- __ InvokeFunction(a1, actual, CALL_FUNCTION);
- }
-
- __ LeaveInternalFrame();
-
- __ Jump(ra);
+void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
}
void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
- Generate_JSEntryTrampolineHelper(masm, false);
+ UNIMPLEMENTED_MIPS();
}
void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
- Generate_JSEntryTrampolineHelper(masm, true);
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
}
@@ -194,7 +138,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
UNIMPLEMENTED_MIPS();
- __ break_(0x201);
}
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
new file mode 100644
index 00000000..6cc272c3
--- /dev/null
+++ b/src/mips/code-stubs-mips.cc
@@ -0,0 +1,752 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#if defined(V8_TARGET_ARCH_MIPS)
+
+#include "bootstrapper.h"
+#include "code-stubs.h"
+#include "codegen-inl.h"
+#include "regexp-macro-assembler.h"
+
+namespace v8 {
+namespace internal {
+
+
+#define __ ACCESS_MASM(masm)
+
+
+void ToNumberStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FastNewClosureStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FastNewContextStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// Takes a Smi and converts to an IEEE 64 bit floating point value in two
+// registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and
+// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
+// scratch register. Destroys the source register. No GC occurs during this
+// stub so you don't have to set up the frame.
+class ConvertToDoubleStub : public CodeStub {
+ public:
+ ConvertToDoubleStub(Register result_reg_1,
+ Register result_reg_2,
+ Register source_reg,
+ Register scratch_reg)
+ : result1_(result_reg_1),
+ result2_(result_reg_2),
+ source_(source_reg),
+ zeros_(scratch_reg) { }
+
+ private:
+ Register result1_;
+ Register result2_;
+ Register source_;
+ Register zeros_;
+
+ // Minor key encoding in 16 bits.
+ class ModeBits: public BitField<OverwriteMode, 0, 2> {};
+ class OpBits: public BitField<Token::Value, 2, 14> {};
+
+ Major MajorKey() { return ConvertToDouble; }
+ int MinorKey() {
+ // Encode the parameters in a unique 16 bit value.
+ return result1_.code() +
+ (result2_.code() << 4) +
+ (source_.code() << 8) +
+ (zeros_.code() << 12);
+ }
+
+ void Generate(MacroAssembler* masm);
+
+ const char* GetName() { return "ConvertToDoubleStub"; }
+
+#ifdef DEBUG
+ void Print() { PrintF("ConvertToDoubleStub\n"); }
+#endif
+};
+
+
+void ConvertToDoubleStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+class FloatingPointHelper : public AllStatic {
+ public:
+
+ enum Destination {
+ kFPURegisters,
+ kCoreRegisters
+ };
+
+
+ // Loads smis from a0 and a1 (right and left in binary operations) into
+ // floating point registers. Depending on the destination the values ends up
+ // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination
+ // is floating point registers FPU must be supported. If core registers are
+ // requested when FPU is supported f12 and f14 will be scratched.
+ static void LoadSmis(MacroAssembler* masm,
+ Destination destination,
+ Register scratch1,
+ Register scratch2);
+
+ // Loads objects from a0 and a1 (right and left in binary operations) into
+ // floating point registers. Depending on the destination the values ends up
+ // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination
+ // is floating point registers FPU must be supported. If core registers are
+ // requested when FPU is supported f12 and f14 will still be scratched. If
+ // either a0 or a1 is not a number (not smi and not heap number object) the
+ // not_number label is jumped to with a0 and a1 intact.
+ static void LoadOperands(MacroAssembler* masm,
+ FloatingPointHelper::Destination destination,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Label* not_number);
+ // Loads the number from object into dst as a 32-bit integer if possible. If
+ // the object is not a 32-bit integer control continues at the label
+ // not_int32. If FPU is supported double_scratch is used but not scratch2.
+ static void LoadNumberAsInteger(MacroAssembler* masm,
+ Register object,
+ Register dst,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ FPURegister double_scratch,
+ Label* not_int32);
+ private:
+ static void LoadNumber(MacroAssembler* masm,
+ FloatingPointHelper::Destination destination,
+ Register object,
+ FPURegister dst,
+ Register dst1,
+ Register dst2,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Label* not_number);
+};
+
+
+void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
+ FloatingPointHelper::Destination destination,
+ Register scratch1,
+ Register scratch2) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FloatingPointHelper::LoadOperands(
+ MacroAssembler* masm,
+ FloatingPointHelper::Destination destination,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Label* slow) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
+ Destination destination,
+ Register object,
+ FPURegister dst,
+ Register dst1,
+ Register dst2,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Label* not_number) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FloatingPointHelper::LoadNumberAsInteger(MacroAssembler* masm,
+ Register object,
+ Register dst,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ FPURegister double_scratch,
+ Label* not_int32) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// See comment for class, this does NOT work for int32's that are in Smi range.
+void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void EmitNanCheck(MacroAssembler* masm, Condition cc) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
+ Register object,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ bool object_is_smi,
+ Label* not_found) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void NumberToStringStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// On entry lhs_ (lhs) and rhs_ (rhs) are the things to be compared.
+// On exit, v0 is 0, positive, or negative (smi) to indicate the result
+// of the comparison.
+void CompareStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// This stub does not handle the inlined cases (Smis, Booleans, undefined).
+// The stub returns zero for false, and a non-zero value for true.
+void ToBooleanStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// We fall into this code if the operands were Smis, but the result was
+// not (eg. overflow). We branch into this code (to the not_smi label) if
+// the operands were not both Smi. The operands are in lhs and rhs.
+// To call the C-implemented binary fp operation routines we need to end up
+// with the double precision floating point operands in a0 and a1 (for the
+// value in a1) and a2 and a3 (for the value in a0).
+void GenericBinaryOpStub::HandleBinaryOpSlowCases(MacroAssembler* masm,
+ Label* not_smi,
+ Register lhs,
+ Register rhs,
+ const Builtins::JavaScript& builtin) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// For bitwise ops where the inputs are not both Smis we here try to determine
+// whether both inputs are either Smis or at least heap numbers that can be
+// represented by a 32 bit signed value. We truncate towards zero as required
+// by the ES spec. If this is the case we do the bitwise op and see if the
+// result is a Smi. If so, great, otherwise we try to find a heap number to
+// write the answer into (either by allocating or by overwriting).
+// On entry the operands are in lhs (x) and rhs (y). (Result = x op y).
+// On exit the result is in v0.
+void GenericBinaryOpStub::HandleNonSmiBitwiseOp(MacroAssembler* masm,
+ Register lhs,
+ Register rhs) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
+ GenericBinaryOpStub stub(key, type_info);
+ return stub.GetCode();
+}
+
+
+Handle<Code> GetTypeRecordingBinaryOpStub(int key,
+ TRBinaryOpIC::TypeInfo type_info,
+ TRBinaryOpIC::TypeInfo result_type_info) {
+ TypeRecordingBinaryOpStub stub(key, type_info, result_type_info);
+ return stub.GetCode();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateTypeTransitionWithSavedArgs(
+ MacroAssembler* masm) {
+ UNIMPLEMENTED();
+}
+
+
+void TypeRecordingBinaryOpStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+const char* TypeRecordingBinaryOpStub::GetName() {
+ UNIMPLEMENTED_MIPS();
+ return name_;
+}
+
+
+
+void TypeRecordingBinaryOpStub::GenerateSmiSmiOperation(
+ MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
+ bool smi_operands,
+ Label* not_numbers,
+ Label* gc_required) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// Generate the smi code. If the operation on smis are successful this return is
+// generated. If the result is not a smi and heap number allocation is not
+// requested the code falls through. If number allocation is requested but a
+// heap number cannot be allocated the code jumps to the lable gc_required.
+void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
+ Label* gc_required,
+ SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateHeapResultAllocation(
+ MacroAssembler* masm,
+ Register result,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+
+void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
+ UNIMPLEMENTED_MIPS();
+ return Runtime::kAbort;
+}
+
+
+void StackCheckStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+bool CEntryStub::NeedsImmovableCode() {
+ return true;
+}
+
+
+void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
+ UncatchableExceptionType type) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CEntryStub::GenerateCore(MacroAssembler* masm,
+ Label* throw_normal_exception,
+ Label* throw_termination_exception,
+ Label* throw_out_of_memory_exception,
+ bool do_gc,
+ bool always_allocate) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CEntryStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// Uses registers a0 to t0. Expected input is
+// object in a0 (or at sp+1*kPointerSize) and function in
+// a1 (or at sp), depending on whether or not
+// args_in_registers() is true.
+void InstanceofStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpExecStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CallFunctionStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// Unfortunately you have to run without snapshots to see most of these
+// names in the profile since most compare stubs end up in the snapshot.
+const char* CompareStub::GetName() {
+ UNIMPLEMENTED_MIPS();
+ return name_;
+}
+
+
+int CompareStub::MinorKey() {
+ UNIMPLEMENTED_MIPS();
+ return 0;
+}
+
+
+// StringCharCodeAtGenerator
+
+void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringCharCodeAtGenerator::GenerateSlow(
+ MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// -------------------------------------------------------------------------
+// StringCharFromCodeGenerator
+
+void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringCharFromCodeGenerator::GenerateSlow(
+ MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// -------------------------------------------------------------------------
+// StringCharAtGenerator
+
+void StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringCharAtGenerator::GenerateSlow(
+ MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+class StringHelper : public AllStatic {
+ public:
+ // Generate code for copying characters using a simple loop. This should only
+ // be used in places where the number of characters is small and the
+ // additional setup and checking in GenerateCopyCharactersLong adds too much
+ // overhead. Copying of overlapping regions is not supported.
+ // Dest register ends at the position after the last character written.
+ static void GenerateCopyCharacters(MacroAssembler* masm,
+ Register dest,
+ Register src,
+ Register count,
+ Register scratch,
+ bool ascii);
+
+ // Generate code for copying a large number of characters. This function
+ // is allowed to spend extra time setting up conditions to make copying
+ // faster. Copying of overlapping regions is not supported.
+ // Dest register ends at the position after the last character written.
+ static void GenerateCopyCharactersLong(MacroAssembler* masm,
+ Register dest,
+ Register src,
+ Register count,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Register scratch4,
+ Register scratch5,
+ int flags);
+
+
+ // Probe the symbol table for a two character string. If the string is
+ // not found by probing a jump to the label not_found is performed. This jump
+ // does not guarantee that the string is not in the symbol table. If the
+ // string is found the code falls through with the string in register r0.
+ // Contents of both c1 and c2 registers are modified. At the exit c1 is
+ // guaranteed to contain halfword with low and high bytes equal to
+ // initial contents of c1 and c2 respectively.
+ static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+ Register c1,
+ Register c2,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Register scratch4,
+ Register scratch5,
+ Label* not_found);
+
+ // Generate string hash.
+ static void GenerateHashInit(MacroAssembler* masm,
+ Register hash,
+ Register character);
+
+ static void GenerateHashAddCharacter(MacroAssembler* masm,
+ Register hash,
+ Register character);
+
+ static void GenerateHashGetHash(MacroAssembler* masm,
+ Register hash);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
+};
+
+
+void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
+ Register dest,
+ Register src,
+ Register count,
+ Register scratch,
+ bool ascii) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+enum CopyCharactersFlags {
+ COPY_ASCII = 1,
+ DEST_ALWAYS_ALIGNED = 2
+};
+
+
+void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
+ Register dest,
+ Register src,
+ Register count,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Register scratch4,
+ Register scratch5,
+ int flags) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+ Register c1,
+ Register c2,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Register scratch4,
+ Register scratch5,
+ Label* not_found) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringHelper::GenerateHashInit(MacroAssembler* masm,
+ Register hash,
+ Register character) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
+ Register hash,
+ Register character) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
+ Register hash) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void SubStringStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
+ Register right,
+ Register left,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Register scratch4) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringCompareStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StringAddStub::Generate(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void GenerateFastPixelArrayLoad(MacroAssembler* masm,
+ Register receiver,
+ Register key,
+ Register elements_map,
+ Register elements,
+ Register scratch1,
+ Register scratch2,
+ Register result,
+ Label* not_pixel_array,
+ Label* key_not_smi,
+ Label* out_of_range) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+#undef __
+
+} } // namespace v8::internal
+
+#endif // V8_TARGET_ARCH_MIPS
+
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
new file mode 100644
index 00000000..675730a5
--- /dev/null
+++ b/src/mips/code-stubs-mips.h
@@ -0,0 +1,511 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_MIPS_CODE_STUBS_ARM_H_
+#define V8_MIPS_CODE_STUBS_ARM_H_
+
+#include "ic-inl.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+// Compute a transcendental math function natively, or call the
+// TranscendentalCache runtime function.
+class TranscendentalCacheStub: public CodeStub {
+ public:
+ explicit TranscendentalCacheStub(TranscendentalCache::Type type)
+ : type_(type) {}
+ void Generate(MacroAssembler* masm);
+ private:
+ TranscendentalCache::Type type_;
+ Major MajorKey() { return TranscendentalCache; }
+ int MinorKey() { return type_; }
+ Runtime::FunctionId RuntimeFunction();
+};
+
+
+class ToBooleanStub: public CodeStub {
+ public:
+ explicit ToBooleanStub(Register tos) : tos_(tos) { }
+
+ void Generate(MacroAssembler* masm);
+
+ private:
+ Register tos_;
+ Major MajorKey() { return ToBoolean; }
+ int MinorKey() { return tos_.code(); }
+};
+
+
+class GenericBinaryOpStub : public CodeStub {
+ public:
+ static const int kUnknownIntValue = -1;
+
+ GenericBinaryOpStub(Token::Value op,
+ OverwriteMode mode,
+ Register lhs,
+ Register rhs,
+ int constant_rhs = kUnknownIntValue)
+ : op_(op),
+ mode_(mode),
+ lhs_(lhs),
+ rhs_(rhs),
+ constant_rhs_(constant_rhs),
+ specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)),
+ runtime_operands_type_(BinaryOpIC::UNINIT_OR_SMI),
+ name_(NULL) { }
+
+ GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info)
+ : op_(OpBits::decode(key)),
+ mode_(ModeBits::decode(key)),
+ lhs_(LhsRegister(RegisterBits::decode(key))),
+ rhs_(RhsRegister(RegisterBits::decode(key))),
+ constant_rhs_(KnownBitsForMinorKey(KnownIntBits::decode(key))),
+ specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op_, constant_rhs_)),
+ runtime_operands_type_(type_info),
+ name_(NULL) { }
+
+ private:
+ Token::Value op_;
+ OverwriteMode mode_;
+ Register lhs_;
+ Register rhs_;
+ int constant_rhs_;
+ bool specialized_on_rhs_;
+ BinaryOpIC::TypeInfo runtime_operands_type_;
+ char* name_;
+
+ static const int kMaxKnownRhs = 0x40000000;
+ static const int kKnownRhsKeyBits = 6;
+
+ // Minor key encoding in 16 bits.
+ class ModeBits: public BitField<OverwriteMode, 0, 2> {};
+ class OpBits: public BitField<Token::Value, 2, 6> {};
+ class TypeInfoBits: public BitField<int, 8, 3> {};
+ class RegisterBits: public BitField<bool, 11, 1> {};
+ class KnownIntBits: public BitField<int, 12, kKnownRhsKeyBits> {};
+
+ Major MajorKey() { return GenericBinaryOp; }
+ int MinorKey() {
+ ASSERT((lhs_.is(a0) && rhs_.is(a1)) ||
+ (lhs_.is(a1) && rhs_.is(a0)));
+ // Encode the parameters in a unique 16 bit value.
+ return OpBits::encode(op_)
+ | ModeBits::encode(mode_)
+ | KnownIntBits::encode(MinorKeyForKnownInt())
+ | TypeInfoBits::encode(runtime_operands_type_)
+ | RegisterBits::encode(lhs_.is(a0));
+ }
+
+ void Generate(MacroAssembler* masm);
+ void HandleNonSmiBitwiseOp(MacroAssembler* masm,
+ Register lhs,
+ Register rhs);
+ void HandleBinaryOpSlowCases(MacroAssembler* masm,
+ Label* not_smi,
+ Register lhs,
+ Register rhs,
+ const Builtins::JavaScript& builtin);
+ void GenerateTypeTransition(MacroAssembler* masm);
+
+ static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) {
+ if (constant_rhs == kUnknownIntValue) return false;
+ if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3;
+ if (op == Token::MOD) {
+ if (constant_rhs <= 1) return false;
+ if (constant_rhs <= 10) return true;
+ if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true;
+ return false;
+ }
+ return false;
+ }
+
+ int MinorKeyForKnownInt() {
+ if (!specialized_on_rhs_) return 0;
+ if (constant_rhs_ <= 10) return constant_rhs_ + 1;
+ ASSERT(IsPowerOf2(constant_rhs_));
+ int key = 12;
+ int d = constant_rhs_;
+ while ((d & 1) == 0) {
+ key++;
+ d >>= 1;
+ }
+ ASSERT(key >= 0 && key < (1 << kKnownRhsKeyBits));
+ return key;
+ }
+
+ int KnownBitsForMinorKey(int key) {
+ if (!key) return 0;
+ if (key <= 11) return key - 1;
+ int d = 1;
+ while (key != 12) {
+ key--;
+ d <<= 1;
+ }
+ return d;
+ }
+
+ Register LhsRegister(bool lhs_is_a0) {
+ return lhs_is_a0 ? a0 : a1;
+ }
+
+ Register RhsRegister(bool lhs_is_a0) {
+ return lhs_is_a0 ? a1 : a0;
+ }
+
+ bool HasSmiSmiFastPath() {
+ return op_ != Token::DIV;
+ }
+
+ bool ShouldGenerateSmiCode() {
+ return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) &&
+ runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS &&
+ runtime_operands_type_ != BinaryOpIC::STRINGS;
+ }
+
+ bool ShouldGenerateFPCode() {
+ return runtime_operands_type_ != BinaryOpIC::STRINGS;
+ }
+
+ virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
+
+ virtual InlineCacheState GetICState() {
+ return BinaryOpIC::ToState(runtime_operands_type_);
+ }
+
+ const char* GetName();
+
+ virtual void FinishCode(Code* code) {
+ code->set_binary_op_type(runtime_operands_type_);
+ }
+
+#ifdef DEBUG
+ void Print() {
+ if (!specialized_on_rhs_) {
+ PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_));
+ } else {
+ PrintF("GenericBinaryOpStub (%s by %d)\n",
+ Token::String(op_),
+ constant_rhs_);
+ }
+ }
+#endif
+};
+
+class TypeRecordingBinaryOpStub: public CodeStub {
+ public:
+ TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode)
+ : op_(op),
+ mode_(mode),
+ operands_type_(TRBinaryOpIC::UNINITIALIZED),
+ result_type_(TRBinaryOpIC::UNINITIALIZED),
+ name_(NULL) {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ TypeRecordingBinaryOpStub(
+ int key,
+ TRBinaryOpIC::TypeInfo operands_type,
+ TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED)
+ : op_(OpBits::decode(key)),
+ mode_(ModeBits::decode(key)),
+ use_fpu_(FPUBits::decode(key)),
+ operands_type_(operands_type),
+ result_type_(result_type),
+ name_(NULL) { }
+
+ private:
+ enum SmiCodeGenerateHeapNumberResults {
+ ALLOW_HEAPNUMBER_RESULTS,
+ NO_HEAPNUMBER_RESULTS
+ };
+
+ Token::Value op_;
+ OverwriteMode mode_;
+ bool use_fpu_;
+
+ // Operand type information determined at runtime.
+ TRBinaryOpIC::TypeInfo operands_type_;
+ TRBinaryOpIC::TypeInfo result_type_;
+
+ char* name_;
+
+ const char* GetName();
+
+#ifdef DEBUG
+ void Print() {
+ PrintF("TypeRecordingBinaryOpStub %d (op %s), "
+ "(mode %d, runtime_type_info %s)\n",
+ MinorKey(),
+ Token::String(op_),
+ static_cast<int>(mode_),
+ TRBinaryOpIC::GetName(operands_type_));
+ }
+#endif
+
+ // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
+ class ModeBits: public BitField<OverwriteMode, 0, 2> {};
+ class OpBits: public BitField<Token::Value, 2, 7> {};
+ class FPUBits: public BitField<bool, 9, 1> {};
+ class OperandTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 10, 3> {};
+ class ResultTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 13, 3> {};
+
+ Major MajorKey() { return TypeRecordingBinaryOp; }
+ int MinorKey() {
+ return OpBits::encode(op_)
+ | ModeBits::encode(mode_)
+ | FPUBits::encode(use_fpu_)
+ | OperandTypeInfoBits::encode(operands_type_)
+ | ResultTypeInfoBits::encode(result_type_);
+ }
+
+ void Generate(MacroAssembler* masm);
+ void GenerateGeneric(MacroAssembler* masm);
+ void GenerateSmiSmiOperation(MacroAssembler* masm);
+ void GenerateFPOperation(MacroAssembler* masm,
+ bool smi_operands,
+ Label* not_numbers,
+ Label* gc_required);
+ void GenerateSmiCode(MacroAssembler* masm,
+ Label* gc_required,
+ SmiCodeGenerateHeapNumberResults heapnumber_results);
+ void GenerateLoadArguments(MacroAssembler* masm);
+ void GenerateReturn(MacroAssembler* masm);
+ void GenerateUninitializedStub(MacroAssembler* masm);
+ void GenerateSmiStub(MacroAssembler* masm);
+ void GenerateInt32Stub(MacroAssembler* masm);
+ void GenerateHeapNumberStub(MacroAssembler* masm);
+ void GenerateStringStub(MacroAssembler* masm);
+ void GenerateGenericStub(MacroAssembler* masm);
+ void GenerateAddStrings(MacroAssembler* masm);
+ void GenerateCallRuntime(MacroAssembler* masm);
+
+ void GenerateHeapResultAllocation(MacroAssembler* masm,
+ Register result,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+ void GenerateRegisterArgsPush(MacroAssembler* masm);
+ void GenerateTypeTransition(MacroAssembler* masm);
+ void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
+
+ virtual int GetCodeKind() { return Code::TYPE_RECORDING_BINARY_OP_IC; }
+
+ virtual InlineCacheState GetICState() {
+ return TRBinaryOpIC::ToState(operands_type_);
+ }
+
+ virtual void FinishCode(Code* code) {
+ code->set_type_recording_binary_op_type(operands_type_);
+ code->set_type_recording_binary_op_result_type(result_type_);
+ }
+
+ friend class CodeGenerator;
+};
+
+
+// Flag that indicates how to generate code for the stub StringAddStub.
+enum StringAddFlags {
+ NO_STRING_ADD_FLAGS = 0,
+ NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub.
+};
+
+
+class StringAddStub: public CodeStub {
+ public:
+ explicit StringAddStub(StringAddFlags flags) {
+ string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
+ }
+
+ private:
+ Major MajorKey() { return StringAdd; }
+ int MinorKey() { return string_check_ ? 0 : 1; }
+
+ void Generate(MacroAssembler* masm);
+
+ // Should the stub check whether arguments are strings?
+ bool string_check_;
+};
+
+
+class SubStringStub: public CodeStub {
+ public:
+ SubStringStub() {}
+
+ private:
+ Major MajorKey() { return SubString; }
+ int MinorKey() { return 0; }
+
+ void Generate(MacroAssembler* masm);
+};
+
+
+class StringCompareStub: public CodeStub {
+ public:
+ StringCompareStub() { }
+
+ // Compare two flat ASCII strings and returns result in v0.
+ // Does not use the stack.
+ static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
+ Register left,
+ Register right,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Register scratch4);
+
+ private:
+ Major MajorKey() { return StringCompare; }
+ int MinorKey() { return 0; }
+
+ void Generate(MacroAssembler* masm);
+};
+
+
+// This stub can convert a signed int32 to a heap number (double). It does
+// not work for int32s that are in Smi range! No GC occurs during this stub
+// so you don't have to set up the frame.
+class WriteInt32ToHeapNumberStub : public CodeStub {
+ public:
+ WriteInt32ToHeapNumberStub(Register the_int,
+ Register the_heap_number,
+ Register scratch,
+ Register scratch2)
+ : the_int_(the_int),
+ the_heap_number_(the_heap_number),
+ scratch_(scratch),
+ sign_(scratch2) { }
+
+ private:
+ Register the_int_;
+ Register the_heap_number_;
+ Register scratch_;
+ Register sign_;
+
+ // Minor key encoding in 16 bits.
+ class IntRegisterBits: public BitField<int, 0, 4> {};
+ class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
+ class ScratchRegisterBits: public BitField<int, 8, 4> {};
+
+ Major MajorKey() { return WriteInt32ToHeapNumber; }
+ int MinorKey() {
+ // Encode the parameters in a unique 16 bit value.
+ return IntRegisterBits::encode(the_int_.code())
+ | HeapNumberRegisterBits::encode(the_heap_number_.code())
+ | ScratchRegisterBits::encode(scratch_.code());
+ }
+
+ void Generate(MacroAssembler* masm);
+
+ const char* GetName() { return "WriteInt32ToHeapNumberStub"; }
+
+#ifdef DEBUG
+ void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); }
+#endif
+};
+
+
+class NumberToStringStub: public CodeStub {
+ public:
+ NumberToStringStub() { }
+
+ // Generate code to do a lookup in the number string cache. If the number in
+ // the register object is found in the cache the generated code falls through
+ // with the result in the result register. The object and the result register
+ // can be the same. If the number is not found in the cache the code jumps to
+ // the label not_found with only the content of register object unchanged.
+ static void GenerateLookupNumberStringCache(MacroAssembler* masm,
+ Register object,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ bool object_is_smi,
+ Label* not_found);
+
+ private:
+ Major MajorKey() { return NumberToString; }
+ int MinorKey() { return 0; }
+
+ void Generate(MacroAssembler* masm);
+
+ const char* GetName() { return "NumberToStringStub"; }
+
+#ifdef DEBUG
+ void Print() {
+ PrintF("NumberToStringStub\n");
+ }
+#endif
+};
+
+
+// Enter C code from generated RegExp code in a way that allows
+// the C code to fix the return address in case of a GC.
+// Currently only needed on ARM and MIPS.
+class RegExpCEntryStub: public CodeStub {
+ public:
+ RegExpCEntryStub() {}
+ virtual ~RegExpCEntryStub() {}
+ void Generate(MacroAssembler* masm);
+
+ private:
+ Major MajorKey() { return RegExpCEntry; }
+ int MinorKey() { return 0; }
+
+ bool NeedsImmovableCode() { return true; }
+
+ const char* GetName() { return "RegExpCEntryStub"; }
+};
+
+
+// Generate code the to load an element from a pixel array. The receiver is
+// assumed to not be a smi and to have elements, the caller must guarantee this
+// precondition. If the receiver does not have elements that are pixel arrays,
+// the generated code jumps to not_pixel_array. If key is not a smi, then the
+// generated code branches to key_not_smi. Callers can specify NULL for
+// key_not_smi to signal that a smi check has already been performed on key so
+// that the smi check is not generated . If key is not a valid index within the
+// bounds of the pixel array, the generated code jumps to out_of_range.
+void GenerateFastPixelArrayLoad(MacroAssembler* masm,
+ Register receiver,
+ Register key,
+ Register elements_map,
+ Register elements,
+ Register scratch1,
+ Register scratch2,
+ Register result,
+ Label* not_pixel_array,
+ Label* key_not_smi,
+ Label* out_of_range);
+
+
+} } // namespace v8::internal
+
+#endif // V8_MIPS_CODE_STUBS_ARM_H_
diff --git a/src/mips/codegen-mips-inl.h b/src/mips/codegen-mips-inl.h
index 3a511b80..be9ae9ed 100644
--- a/src/mips/codegen-mips-inl.h
+++ b/src/mips/codegen-mips-inl.h
@@ -29,6 +29,8 @@
#ifndef V8_MIPS_CODEGEN_MIPS_INL_H_
#define V8_MIPS_CODEGEN_MIPS_INL_H_
+#include "virtual-frame-mips.h"
+
namespace v8 {
namespace internal {
@@ -42,23 +44,15 @@ void DeferredCode::Jump() {
}
-void Reference::GetValueAndSpill() {
- GetValue();
-}
-
-
-void CodeGenerator::VisitAndSpill(Statement* statement) {
- Visit(statement);
+// Note: this has been hacked for submisson. Mips branches require two
+// additional operands: Register src1, const Operand& src2.
+void DeferredCode::Branch(Condition cond) {
+ __ Branch(&entry_label_, cond, zero_reg, Operand(0));
}
-void CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) {
- VisitStatements(statements);
-}
-
-
-void CodeGenerator::LoadAndSpill(Expression* expression) {
- Load(expression);
+void Reference::GetValueAndSpill() {
+ GetValue();
}
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 79801f07..c1149dfd 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -31,36 +31,62 @@
#if defined(V8_TARGET_ARCH_MIPS)
#include "bootstrapper.h"
+#include "code-stubs.h"
#include "codegen-inl.h"
#include "compiler.h"
#include "debug.h"
#include "ic-inl.h"
+#include "jsregexp.h"
+#include "jump-target-inl.h"
#include "parser.h"
+#include "regexp-macro-assembler.h"
+#include "regexp-stack.h"
#include "register-allocator-inl.h"
#include "runtime.h"
#include "scopes.h"
+#include "stub-cache.h"
#include "virtual-frame-inl.h"
-
-
+#include "virtual-frame-mips-inl.h"
namespace v8 {
namespace internal {
-#define __ ACCESS_MASM(masm_)
-
+#define __ ACCESS_MASM(masm_)
-// -----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
// Platform-specific DeferredCode functions.
-
void DeferredCode::SaveRegisters() {
- UNIMPLEMENTED_MIPS();
+ // On MIPS you either have a completely spilled frame or you
+ // handle it yourself, but at the moment there's no automation
+ // of registers and deferred code.
}
void DeferredCode::RestoreRegisters() {
- UNIMPLEMENTED_MIPS();
+}
+
+
+// -------------------------------------------------------------------------
+// Platform-specific RuntimeCallHelper functions.
+
+void VirtualFrameRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
+ frame_state_->frame()->AssertIsSpilled();
+}
+
+
+void VirtualFrameRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
+}
+
+
+void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
+ masm->EnterInternalFrame();
+}
+
+
+void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
+ masm->LeaveInternalFrame();
}
@@ -69,21 +95,28 @@ void DeferredCode::RestoreRegisters() {
CodeGenState::CodeGenState(CodeGenerator* owner)
: owner_(owner),
- true_target_(NULL),
- false_target_(NULL),
- previous_(NULL) {
- owner_->set_state(this);
+ previous_(owner->state()) {
+ owner->set_state(this);
}
-CodeGenState::CodeGenState(CodeGenerator* owner,
+ConditionCodeGenState::ConditionCodeGenState(CodeGenerator* owner,
JumpTarget* true_target,
JumpTarget* false_target)
- : owner_(owner),
+ : CodeGenState(owner),
true_target_(true_target),
- false_target_(false_target),
- previous_(owner->state()) {
- owner_->set_state(this);
+ false_target_(false_target) {
+ owner->set_state(this);
+}
+
+
+TypeInfoCodeGenState::TypeInfoCodeGenState(CodeGenerator* owner,
+ Slot* slot,
+ TypeInfo type_info)
+ : CodeGenState(owner),
+ slot_(slot) {
+ owner->set_state(this);
+ old_type_info_ = owner->set_type_info(slot, type_info);
}
@@ -93,16 +126,25 @@ CodeGenState::~CodeGenState() {
}
+TypeInfoCodeGenState::~TypeInfoCodeGenState() {
+ owner()->set_type_info(slot_, old_type_info_);
+}
+
+
// -----------------------------------------------------------------------------
-// CodeGenerator implementation
+// CodeGenerator implementation.
CodeGenerator::CodeGenerator(MacroAssembler* masm)
: deferred_(8),
masm_(masm),
+ info_(NULL),
frame_(NULL),
allocator_(NULL),
cc_reg_(cc_always),
state_(NULL),
+ loop_nesting_(0),
+ type_info_(NULL),
+ function_return_(JumpTarget::BIDIRECTIONAL),
function_return_is_shadowed_(false) {
}
@@ -114,356 +156,249 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm)
// cp: callee's context
void CodeGenerator::Generate(CompilationInfo* info) {
- // Record the position for debugging purposes.
- CodeForFunctionPosition(info->function());
-
- // Initialize state.
- info_ = info;
- ASSERT(allocator_ == NULL);
- RegisterAllocator register_allocator(this);
- allocator_ = &register_allocator;
- ASSERT(frame_ == NULL);
- frame_ = new VirtualFrame();
- cc_reg_ = cc_always;
-
- {
- CodeGenState state(this);
-
- // Registers:
- // a1: called JS function
- // ra: return address
- // fp: caller's frame pointer
- // sp: stack pointer
- // cp: callee's context
- //
- // Stack:
- // arguments
- // receiver
-
- frame_->Enter();
-
- // Allocate space for locals and initialize them.
- frame_->AllocateStackSlots();
-
- // Initialize the function return target.
- function_return_.set_direction(JumpTarget::BIDIRECTIONAL);
- function_return_is_shadowed_ = false;
-
- VirtualFrame::SpilledScope spilled_scope;
- if (scope()->num_heap_slots() > 0) {
- UNIMPLEMENTED_MIPS();
- }
-
- {
- Comment cmnt2(masm_, "[ copy context parameters into .context");
-
- // Note that iteration order is relevant here! If we have the same
- // parameter twice (e.g., function (x, y, x)), and that parameter
- // needs to be copied into the context, it must be the last argument
- // passed to the parameter that needs to be copied. This is a rare
- // case so we don't check for it, instead we rely on the copying
- // order: such a parameter is copied repeatedly into the same
- // context location and thus the last value is what is seen inside
- // the function.
- for (int i = 0; i < scope()->num_parameters(); i++) {
- UNIMPLEMENTED_MIPS();
- }
- }
-
- // Store the arguments object. This must happen after context
- // initialization because the arguments object may be stored in the
- // context.
- if (scope()->arguments() != NULL) {
- UNIMPLEMENTED_MIPS();
- }
-
- // Generate code to 'execute' declarations and initialize functions
- // (source elements). In case of an illegal redeclaration we need to
- // handle that instead of processing the declarations.
- if (scope()->HasIllegalRedeclaration()) {
- Comment cmnt(masm_, "[ illegal redeclarations");
- scope()->VisitIllegalRedeclaration(this);
- } else {
- Comment cmnt(masm_, "[ declarations");
- ProcessDeclarations(scope()->declarations());
- // Bail out if a stack-overflow exception occurred when processing
- // declarations.
- if (HasStackOverflow()) return;
- }
-
- if (FLAG_trace) {
- UNIMPLEMENTED_MIPS();
- }
-
- // Compile the body of the function in a vanilla state. Don't
- // bother compiling all the code if the scope has an illegal
- // redeclaration.
- if (!scope()->HasIllegalRedeclaration()) {
- Comment cmnt(masm_, "[ function body");
-#ifdef DEBUG
- bool is_builtin = Bootstrapper::IsActive();
- bool should_trace =
- is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
- if (should_trace) {
- UNIMPLEMENTED_MIPS();
- }
-#endif
- VisitStatementsAndSpill(info->function()->body());
- }
- }
+ UNIMPLEMENTED_MIPS();
+}
- if (has_valid_frame() || function_return_.is_linked()) {
- if (!function_return_.is_linked()) {
- CodeForReturnPosition(info->function());
- }
- // Registers:
- // v0: result
- // sp: stack pointer
- // fp: frame pointer
- // cp: callee's context
-
- __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
-
- function_return_.Bind();
- if (FLAG_trace) {
- UNIMPLEMENTED_MIPS();
- }
-
- // Add a label for checking the size of the code used for returning.
- Label check_exit_codesize;
- masm_->bind(&check_exit_codesize);
-
- masm_->mov(sp, fp);
- masm_->lw(fp, MemOperand(sp, 0));
- masm_->lw(ra, MemOperand(sp, 4));
- masm_->addiu(sp, sp, 8);
-
- // Here we use masm_-> instead of the __ macro to avoid the code coverage
- // tool from instrumenting as we rely on the code size here.
- // TODO(MIPS): Should we be able to use more than 0x1ffe parameters?
- masm_->addiu(sp, sp, (scope()->num_parameters() + 1) * kPointerSize);
- masm_->Jump(ra);
- // The Jump automatically generates a nop in the branch delay slot.
-
- // Check that the size of the code used for returning matches what is
- // expected by the debugger.
- ASSERT_EQ(kJSReturnSequenceLength,
- masm_->InstructionsGeneratedSince(&check_exit_codesize));
- }
- // Code generation state must be reset.
- ASSERT(!has_cc());
- ASSERT(state_ == NULL);
- ASSERT(!function_return_is_shadowed_);
- function_return_.Unuse();
- DeleteFrame();
+int CodeGenerator::NumberOfSlot(Slot* slot) {
+ UNIMPLEMENTED_MIPS();
+ return 0;
+}
- // Process any deferred code using the register allocator.
- if (!HasStackOverflow()) {
- ProcessDeferred();
- }
- allocator_ = NULL;
+MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
+ UNIMPLEMENTED_MIPS();
+ return MemOperand(zero_reg, 0);
}
-void CodeGenerator::LoadReference(Reference* ref) {
- VirtualFrame::SpilledScope spilled_scope;
- Comment cmnt(masm_, "[ LoadReference");
- Expression* e = ref->expression();
- Property* property = e->AsProperty();
- Variable* var = e->AsVariableProxy()->AsVariable();
+MemOperand CodeGenerator::ContextSlotOperandCheckExtensions(
+ Slot* slot,
+ Register tmp,
+ Register tmp2,
+ JumpTarget* slow) {
+ UNIMPLEMENTED_MIPS();
+ return MemOperand(zero_reg, 0);
+}
- if (property != NULL) {
- UNIMPLEMENTED_MIPS();
- } else if (var != NULL) {
- // The expression is a variable proxy that does not rewrite to a
- // property. Global variables are treated as named property references.
- if (var->is_global()) {
- LoadGlobal();
- ref->set_type(Reference::NAMED);
- } else {
- ASSERT(var->slot() != NULL);
- ref->set_type(Reference::SLOT);
- }
- } else {
- UNIMPLEMENTED_MIPS();
- }
+
+void CodeGenerator::LoadCondition(Expression* x,
+ JumpTarget* true_target,
+ JumpTarget* false_target,
+ bool force_cc) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::Load(Expression* x) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::LoadGlobal() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::LoadGlobalReceiver(Register scratch) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+ArgumentsAllocationMode CodeGenerator::ArgumentsMode() {
+ UNIMPLEMENTED_MIPS();
+ return EAGER_ARGUMENTS_ALLOCATION;
+}
+
+
+void CodeGenerator::StoreArgumentsObject(bool initial) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::LoadTypeofExpression(Expression* x) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+Reference::Reference(CodeGenerator* cgen,
+ Expression* expression,
+ bool persist_after_get)
+ : cgen_(cgen),
+ expression_(expression),
+ type_(ILLEGAL),
+ persist_after_get_(persist_after_get) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+Reference::~Reference() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::LoadReference(Reference* ref) {
+ UNIMPLEMENTED_MIPS();
}
void CodeGenerator::UnloadReference(Reference* ref) {
- VirtualFrame::SpilledScope spilled_scope;
- // Pop a reference from the stack while preserving TOS.
- Comment cmnt(masm_, "[ UnloadReference");
- int size = ref->size();
- if (size > 0) {
- frame_->EmitPop(a0);
- frame_->Drop(size);
- frame_->EmitPush(a0);
- }
- ref->set_unloaded();
+ UNIMPLEMENTED_MIPS();
}
-MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
- // Currently, this assertion will fail if we try to assign to
- // a constant variable that is constant because it is read-only
- // (such as the variable referring to a named function expression).
- // We need to implement assignments to read-only variables.
- // Ideally, we should do this during AST generation (by converting
- // such assignments into expression statements); however, in general
- // we may not be able to make the decision until past AST generation,
- // that is when the entire program is known.
- ASSERT(slot != NULL);
- int index = slot->index();
- switch (slot->type()) {
- case Slot::PARAMETER:
- UNIMPLEMENTED_MIPS();
- return MemOperand(no_reg, 0);
-
- case Slot::LOCAL:
- return frame_->LocalAt(index);
-
- case Slot::CONTEXT: {
- UNIMPLEMENTED_MIPS();
- return MemOperand(no_reg, 0);
- }
-
- default:
- UNREACHABLE();
- return MemOperand(no_reg, 0);
- }
+// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given
+// register to a boolean in the condition code register. The code
+// may jump to 'false_target' in case the register converts to 'false'.
+void CodeGenerator::ToBoolean(JumpTarget* true_target,
+ JumpTarget* false_target) {
+ UNIMPLEMENTED_MIPS();
}
-// Loads a value on TOS. If it is a boolean value, the result may have been
-// (partially) translated into branches, or it may have set the condition
-// code register. If force_cc is set, the value is forced to set the
-// condition code register and no value is pushed. If the condition code
-// register was set, has_cc() is true and cc_reg_ contains the condition to
-// test for 'true'.
-void CodeGenerator::LoadCondition(Expression* x,
- JumpTarget* true_target,
- JumpTarget* false_target,
- bool force_cc) {
- ASSERT(!has_cc());
- int original_height = frame_->height();
-
- { CodeGenState new_state(this, true_target, false_target);
- Visit(x);
-
- // If we hit a stack overflow, we may not have actually visited
- // the expression. In that case, we ensure that we have a
- // valid-looking frame state because we will continue to generate
- // code as we unwind the C++ stack.
- //
- // It's possible to have both a stack overflow and a valid frame
- // state (eg, a subexpression overflowed, visiting it returned
- // with a dummied frame state, and visiting this expression
- // returned with a normal-looking state).
- if (HasStackOverflow() &&
- has_valid_frame() &&
- !has_cc() &&
- frame_->height() == original_height) {
- true_target->Jump();
- }
- }
- if (force_cc && frame_ != NULL && !has_cc()) {
- // Convert the TOS value to a boolean in the condition code register.
- UNIMPLEMENTED_MIPS();
+void CodeGenerator::GenericBinaryOperation(Token::Value op,
+ OverwriteMode overwrite_mode,
+ GenerateInlineSmi inline_smi,
+ int constant_rhs) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+class DeferredInlineSmiOperation: public DeferredCode {
+ public:
+ DeferredInlineSmiOperation(Token::Value op,
+ int value,
+ bool reversed,
+ OverwriteMode overwrite_mode,
+ Register tos)
+ : op_(op),
+ value_(value),
+ reversed_(reversed),
+ overwrite_mode_(overwrite_mode),
+ tos_register_(tos) {
+ set_comment("[ DeferredInlinedSmiOperation");
}
- ASSERT(!force_cc || !has_valid_frame() || has_cc());
- ASSERT(!has_valid_frame() ||
- (has_cc() && frame_->height() == original_height) ||
- (!has_cc() && frame_->height() == original_height + 1));
+
+ virtual void Generate();
+ // This stub makes explicit calls to SaveRegisters(), RestoreRegisters() and
+ // Exit(). Currently on MIPS SaveRegisters() and RestoreRegisters() are empty
+ // methods, it is the responsibility of the deferred code to save and restore
+ // registers.
+ virtual bool AutoSaveAndRestore() { return false; }
+
+ void JumpToNonSmiInput(Condition cond, Register cmp1, const Operand& cmp2);
+ void JumpToAnswerOutOfRange(Condition cond,
+ Register cmp1,
+ const Operand& cmp2);
+
+ private:
+ void GenerateNonSmiInput();
+ void GenerateAnswerOutOfRange();
+ void WriteNonSmiAnswer(Register answer,
+ Register heap_number,
+ Register scratch);
+
+ Token::Value op_;
+ int value_;
+ bool reversed_;
+ OverwriteMode overwrite_mode_;
+ Register tos_register_;
+ Label non_smi_input_;
+ Label answer_out_of_range_;
+};
+
+
+// For bit operations we try harder and handle the case where the input is not
+// a Smi but a 32bits integer without calling the generic stub.
+void DeferredInlineSmiOperation::JumpToNonSmiInput(Condition cond,
+ Register cmp1,
+ const Operand& cmp2) {
+ UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::Load(Expression* x) {
-#ifdef DEBUG
- int original_height = frame_->height();
-#endif
- JumpTarget true_target;
- JumpTarget false_target;
- LoadCondition(x, &true_target, &false_target, false);
+// For bit operations the result is always 32bits so we handle the case where
+// the result does not fit in a Smi without calling the generic stub.
+void DeferredInlineSmiOperation::JumpToAnswerOutOfRange(Condition cond,
+ Register cmp1,
+ const Operand& cmp2) {
+ UNIMPLEMENTED_MIPS();
+}
- if (has_cc()) {
- UNIMPLEMENTED_MIPS();
- }
- if (true_target.is_linked() || false_target.is_linked()) {
- UNIMPLEMENTED_MIPS();
- }
- ASSERT(has_valid_frame());
- ASSERT(!has_cc());
- ASSERT(frame_->height() == original_height + 1);
+// On entry the non-constant side of the binary operation is in tos_register_
+// and the constant smi side is nowhere. The tos_register_ is not used by the
+// virtual frame. On exit the answer is in the tos_register_ and the virtual
+// frame is unchanged.
+void DeferredInlineSmiOperation::Generate() {
+ UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::LoadGlobal() {
- VirtualFrame::SpilledScope spilled_scope;
- __ lw(a0, GlobalObject());
- frame_->EmitPush(a0);
+// Convert and write the integer answer into heap_number.
+void DeferredInlineSmiOperation::WriteNonSmiAnswer(Register answer,
+ Register heap_number,
+ Register scratch) {
+ UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
- VirtualFrame::SpilledScope spilled_scope;
- if (slot->type() == Slot::LOOKUP) {
- UNIMPLEMENTED_MIPS();
- } else {
- __ lw(a0, SlotOperand(slot, a2));
- frame_->EmitPush(a0);
- if (slot->var()->mode() == Variable::CONST) {
- UNIMPLEMENTED_MIPS();
- }
- }
+void DeferredInlineSmiOperation::GenerateNonSmiInput() {
+ UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
- ASSERT(slot != NULL);
- if (slot->type() == Slot::LOOKUP) {
- UNIMPLEMENTED_MIPS();
- } else {
- ASSERT(!slot->var()->is_dynamic());
-
- JumpTarget exit;
- if (init_state == CONST_INIT) {
- UNIMPLEMENTED_MIPS();
- }
-
- // We must execute the store. Storing a variable must keep the
- // (new) value on the stack. This is necessary for compiling
- // assignment expressions.
- //
- // Note: We will reach here even with slot->var()->mode() ==
- // Variable::CONST because of const declarations which will
- // initialize consts to 'the hole' value and by doing so, end up
- // calling this code. a2 may be loaded with context; used below in
- // RecordWrite.
- frame_->EmitPop(a0);
- __ sw(a0, SlotOperand(slot, a2));
- frame_->EmitPush(a0);
- if (slot->type() == Slot::CONTEXT) {
- UNIMPLEMENTED_MIPS();
- }
- // If we definitely did not jump over the assignment, we do not need
- // to bind the exit label. Doing so can defeat peephole
- // optimization.
- if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) {
- exit.Bind();
- }
- }
+void DeferredInlineSmiOperation::GenerateAnswerOutOfRange() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::SmiOperation(Token::Value op,
+ Handle<Object> value,
+ bool reversed,
+ OverwriteMode mode) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// On MIPS we load registers condReg1 and condReg2 with the values which should
+// be compared. With the CodeGenerator::cc_reg_ condition, functions will be
+// able to evaluate correctly the condition. (eg CodeGenerator::Branch)
+void CodeGenerator::Comparison(Condition cc,
+ Expression* left,
+ Expression* right,
+ bool strict) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
+ CallFunctionFlags flags,
+ int position) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::CallApplyLazy(Expression* applicand,
+ Expression* receiver,
+ VariableProxy* arguments,
+ int position) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::Branch(bool if_true, JumpTarget* target) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::CheckStack() {
+ UNIMPLEMENTED_MIPS();
}
void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
- VirtualFrame::SpilledScope spilled_scope;
- for (int i = 0; frame_ != NULL && i < statements->length(); i++) {
- VisitAndSpill(statements->at(i));
- }
+ UNIMPLEMENTED_MIPS();
}
@@ -473,14 +408,7 @@ void CodeGenerator::VisitBlock(Block* node) {
void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
- VirtualFrame::SpilledScope spilled_scope;
- frame_->EmitPush(cp);
- __ li(t0, Operand(pairs));
- frame_->EmitPush(t0);
- __ li(t0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
- frame_->EmitPush(t0);
- frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
- // The result is discarded.
+ UNIMPLEMENTED_MIPS();
}
@@ -490,17 +418,7 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
-#ifdef DEBUG
- int original_height = frame_->height();
-#endif
- VirtualFrame::SpilledScope spilled_scope;
- Comment cmnt(masm_, "[ ExpressionStatement");
- CodeForStatementPosition(node);
- Expression* expression = node->expression();
- expression->MarkAsStatement();
- LoadAndSpill(expression);
- frame_->Drop();
- ASSERT(frame_->height() == original_height);
+ UNIMPLEMENTED_MIPS();
}
@@ -525,22 +443,12 @@ void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
- VirtualFrame::SpilledScope spilled_scope;
- Comment cmnt(masm_, "[ ReturnStatement");
-
- CodeForStatementPosition(node);
- LoadAndSpill(node->expression());
- if (function_return_is_shadowed_) {
- frame_->EmitPop(v0);
- function_return_.Jump();
- } else {
- // Pop the result from the frame and prepare the frame for
- // returning thus making it easier to merge.
- frame_->EmitPop(v0);
- frame_->PrepareForReturn();
-
- function_return_.Jump();
- }
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::GenerateReturnSequence() {
+ UNIMPLEMENTED_MIPS();
}
@@ -594,6 +502,13 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
}
+void CodeGenerator::InstantiateFunction(
+ Handle<SharedFunctionInfo> function_info,
+ bool pretenure) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
UNIMPLEMENTED_MIPS();
}
@@ -610,46 +525,49 @@ void CodeGenerator::VisitConditional(Conditional* node) {
}
+void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot,
+ TypeofState state) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot,
+ TypeofState typeof_state,
+ JumpTarget* slow) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot,
+ TypeofState typeof_state,
+ JumpTarget* slow,
+ JumpTarget* done) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void CodeGenerator::VisitSlot(Slot* node) {
-#ifdef DEBUG
- int original_height = frame_->height();
-#endif
- VirtualFrame::SpilledScope spilled_scope;
- Comment cmnt(masm_, "[ Slot");
- LoadFromSlot(node, typeof_state());
- ASSERT(frame_->height() == original_height + 1);
+ UNIMPLEMENTED_MIPS();
}
void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
-#ifdef DEBUG
- int original_height = frame_->height();
-#endif
- VirtualFrame::SpilledScope spilled_scope;
- Comment cmnt(masm_, "[ VariableProxy");
-
- Variable* var = node->var();
- Expression* expr = var->rewrite();
- if (expr != NULL) {
- Visit(expr);
- } else {
- ASSERT(var->is_global());
- Reference ref(this, node);
- ref.GetValueAndSpill();
- }
- ASSERT(frame_->height() == original_height + 1);
+ UNIMPLEMENTED_MIPS();
}
void CodeGenerator::VisitLiteral(Literal* node) {
-#ifdef DEBUG
- int original_height = frame_->height();
-#endif
- VirtualFrame::SpilledScope spilled_scope;
- Comment cmnt(masm_, "[ Literal");
- __ li(t0, Operand(node->handle()));
- frame_->EmitPush(t0);
- ASSERT(frame_->height() == original_height + 1);
+ UNIMPLEMENTED_MIPS();
}
@@ -673,48 +591,23 @@ void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) {
}
+void CodeGenerator::EmitSlotAssignment(Assignment* node) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void CodeGenerator::VisitAssignment(Assignment* node) {
-#ifdef DEBUG
- int original_height = frame_->height();
-#endif
- VirtualFrame::SpilledScope spilled_scope;
- Comment cmnt(masm_, "[ Assignment");
-
- { Reference target(this, node->target());
- if (target.is_illegal()) {
- // Fool the virtual frame into thinking that we left the assignment's
- // value on the frame.
- frame_->EmitPush(zero_reg);
- ASSERT(frame_->height() == original_height + 1);
- return;
- }
-
- if (node->op() == Token::ASSIGN ||
- node->op() == Token::INIT_VAR ||
- node->op() == Token::INIT_CONST) {
- LoadAndSpill(node->value());
- } else {
- UNIMPLEMENTED_MIPS();
- }
-
- Variable* var = node->target()->AsVariableProxy()->AsVariable();
- if (var != NULL &&
- (var->mode() == Variable::CONST) &&
- node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
- // Assignment ignored - leave the value on the stack.
- } else {
- CodeForSourcePosition(node->position());
- if (node->op() == Token::INIT_CONST) {
- // Dynamic constant initializations must use the function context
- // and initialize the actual constant declared. Dynamic variable
- // initializations are simply assignments and use SetValue.
- target.SetValue(CONST_INIT);
- } else {
- target.SetValue(NOT_CONST_INIT);
- }
- }
- }
- ASSERT(frame_->height() == original_height + 1);
+ UNIMPLEMENTED_MIPS();
}
@@ -729,73 +622,7 @@ void CodeGenerator::VisitProperty(Property* node) {
void CodeGenerator::VisitCall(Call* node) {
-#ifdef DEBUG
- int original_height = frame_->height();
-#endif
- VirtualFrame::SpilledScope spilled_scope;
- Comment cmnt(masm_, "[ Call");
-
- Expression* function = node->expression();
- ZoneList<Expression*>* args = node->arguments();
-
- // Standard function call.
- // Check if the function is a variable or a property.
- Variable* var = function->AsVariableProxy()->AsVariable();
- Property* property = function->AsProperty();
-
- // ------------------------------------------------------------------------
- // Fast-case: Use inline caching.
- // ---
- // According to ECMA-262, section 11.2.3, page 44, the function to call
- // must be resolved after the arguments have been evaluated. The IC code
- // automatically handles this by loading the arguments before the function
- // is resolved in cache misses (this also holds for megamorphic calls).
- // ------------------------------------------------------------------------
-
- if (var != NULL && var->is_possibly_eval()) {
- UNIMPLEMENTED_MIPS();
- } else if (var != NULL && !var->is_this() && var->is_global()) {
- // ----------------------------------
- // JavaScript example: 'foo(1, 2, 3)' // foo is global
- // ----------------------------------
-
- int arg_count = args->length();
-
- // We need sp to be 8 bytes aligned when calling the stub.
- __ SetupAlignedCall(t0, arg_count);
-
- // Pass the global object as the receiver and let the IC stub
- // patch the stack to use the global proxy as 'this' in the
- // invoked function.
- LoadGlobal();
-
- // Load the arguments.
- for (int i = 0; i < arg_count; i++) {
- LoadAndSpill(args->at(i));
- }
-
- // Setup the receiver register and call the IC initialization code.
- __ li(a2, Operand(var->name()));
- InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
- CodeForSourcePosition(node->position());
- frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
- arg_count + 1);
- __ ReturnFromAlignedCall();
- __ lw(cp, frame_->Context());
- // Remove the function from the stack.
- frame_->EmitPush(v0);
-
- } else if (var != NULL && var->slot() != NULL &&
- var->slot()->type() == Slot::LOOKUP) {
- UNIMPLEMENTED_MIPS();
- } else if (property != NULL) {
- UNIMPLEMENTED_MIPS();
- } else {
- UNIMPLEMENTED_MIPS();
- }
-
- ASSERT(frame_->height() == original_height + 1);
+ UNIMPLEMENTED_MIPS();
}
@@ -839,30 +666,112 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
}
-void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
+class DeferredStringCharCodeAt : public DeferredCode {
+ public:
+ DeferredStringCharCodeAt(Register object,
+ Register index,
+ Register scratch,
+ Register result)
+ : result_(result),
+ char_code_at_generator_(object,
+ index,
+ scratch,
+ result,
+ &need_conversion_,
+ &need_conversion_,
+ &index_out_of_range_,
+ STRING_INDEX_IS_NUMBER) {}
+
+ StringCharCodeAtGenerator* fast_case_generator() {
+ return &char_code_at_generator_;
+ }
+
+ virtual void Generate() {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ private:
+ Register result_;
+
+ Label need_conversion_;
+ Label index_out_of_range_;
+
+ StringCharCodeAtGenerator char_code_at_generator_;
+};
+
+
+void CodeGenerator::GenerateStringCharCodeAt(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
+class DeferredStringCharFromCode : public DeferredCode {
+ public:
+ DeferredStringCharFromCode(Register code,
+ Register result)
+ : char_from_code_generator_(code, result) {}
+
+ StringCharFromCodeGenerator* fast_case_generator() {
+ return &char_from_code_generator_;
+ }
+
+ virtual void Generate() {
+ VirtualFrameRuntimeCallHelper call_helper(frame_state());
+ char_from_code_generator_.GenerateSlow(masm(), call_helper);
+ }
+
+ private:
+ StringCharFromCodeGenerator char_from_code_generator_;
+};
+
+
+void CodeGenerator::GenerateStringCharFromCode(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-// This should generate code that performs a charCodeAt() call or returns
-// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
-// It is not yet implemented on ARM, so it always goes to the slow case.
-void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
+class DeferredStringCharAt : public DeferredCode {
+ public:
+ DeferredStringCharAt(Register object,
+ Register index,
+ Register scratch1,
+ Register scratch2,
+ Register result)
+ : result_(result),
+ char_at_generator_(object,
+ index,
+ scratch1,
+ scratch2,
+ result,
+ &need_conversion_,
+ &need_conversion_,
+ &index_out_of_range_,
+ STRING_INDEX_IS_NUMBER) {}
+
+ StringCharAtGenerator* fast_case_generator() {
+ return &char_at_generator_;
+ }
+
+ virtual void Generate() {
UNIMPLEMENTED_MIPS();
}
+ private:
+ Register result_;
-void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
+ Label need_conversion_;
+ Label index_out_of_range_;
+
+ StringCharAtGenerator char_at_generator_;
+};
+
+
+void CodeGenerator::GenerateStringCharAt(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
@@ -877,47 +786,72 @@ void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
}
-void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsSpecObject(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
+class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
+ public:
+ DeferredIsStringWrapperSafeForDefaultValueOf(Register object,
+ Register map_result,
+ Register scratch1,
+ Register scratch2)
+ : object_(object),
+ map_result_(map_result),
+ scratch1_(scratch1),
+ scratch2_(scratch2) { }
+
+ virtual void Generate() {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ private:
+ Register object_;
+ Register map_result_;
+ Register scratch1_;
+ Register scratch2_;
+};
+
+
+void CodeGenerator::GenerateIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateRandomHeapNumber(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateIsSpecObject(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateRandomHeapNumber(
+ ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
@@ -942,491 +876,333 @@ void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) {
}
-void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
+class DeferredSearchCache: public DeferredCode {
+ public:
+ DeferredSearchCache(Register dst, Register cache, Register key)
+ : dst_(dst), cache_(cache), key_(key) {
+ set_comment("[ DeferredSearchCache");
+ }
+
+ virtual void Generate();
+
+ private:
+ Register dst_, cache_, key_;
+};
+
+
+void DeferredSearchCache::Generate() {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
+void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::VisitCountOperation(CountOperation* node) {
+void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
+class DeferredSwapElements: public DeferredCode {
+ public:
+ DeferredSwapElements(Register object, Register index1, Register index2)
+ : object_(object), index1_(index1), index2_(index2) {
+ set_comment("[ DeferredSwapElements");
+ }
+
+ virtual void Generate();
+
+ private:
+ Register object_, index1_, index2_;
+};
+
+
+void DeferredSwapElements::Generate() {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::VisitThisFunction(ThisFunction* node) {
+void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
+void CodeGenerator::GenerateCallFunction(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
-#ifdef DEBUG
-bool CodeGenerator::HasValidEntryRegisters() { return true; }
-#endif
+void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
-#undef __
-#define __ ACCESS_MASM(masm)
+void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
-// -----------------------------------------------------------------------------
-// Reference support
-Reference::Reference(CodeGenerator* cgen,
- Expression* expression,
- bool persist_after_get)
- : cgen_(cgen),
- expression_(expression),
- type_(ILLEGAL),
- persist_after_get_(persist_after_get) {
- cgen->LoadReference(this);
+void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
}
-Reference::~Reference() {
- ASSERT(is_unloaded() || is_illegal());
+void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
}
-Handle<String> Reference::GetName() {
- ASSERT(type_ == NAMED);
- Property* property = expression_->AsProperty();
- if (property == NULL) {
- // Global variable reference treated as a named property reference.
- VariableProxy* proxy = expression_->AsVariableProxy();
- ASSERT(proxy->AsVariable() != NULL);
- ASSERT(proxy->AsVariable()->is_global());
- return proxy->name();
- } else {
- Literal* raw_name = property->key()->AsLiteral();
- ASSERT(raw_name != NULL);
- return Handle<String>(String::cast(*raw_name->handle()));
- }
+void CodeGenerator::GenerateIsRegExpEquivalent(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
}
-void Reference::GetValue() {
- ASSERT(cgen_->HasValidEntryRegisters());
- ASSERT(!is_illegal());
- ASSERT(!cgen_->has_cc());
- Property* property = expression_->AsProperty();
- if (property != NULL) {
- cgen_->CodeForSourcePosition(property->position());
- }
+void CodeGenerator::GenerateHasCachedArrayIndex(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
- switch (type_) {
- case SLOT: {
- UNIMPLEMENTED_MIPS();
- break;
- }
- case NAMED: {
- UNIMPLEMENTED_MIPS();
- break;
- }
+void CodeGenerator::GenerateGetCachedArrayIndex(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
- case KEYED: {
- UNIMPLEMENTED_MIPS();
- break;
- }
- default:
- UNREACHABLE();
- }
+void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
}
-void Reference::SetValue(InitState init_state) {
- ASSERT(!is_illegal());
- ASSERT(!cgen_->has_cc());
- MacroAssembler* masm = cgen_->masm();
- Property* property = expression_->AsProperty();
- if (property != NULL) {
- cgen_->CodeForSourcePosition(property->position());
- }
+void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
+ UNIMPLEMENTED_MIPS();
+}
+
- switch (type_) {
- case SLOT: {
- Comment cmnt(masm, "[ Store to Slot");
- Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
- cgen_->StoreToSlot(slot, init_state);
- cgen_->UnloadReference(this);
- break;
- }
-
- case NAMED: {
- UNIMPLEMENTED_MIPS();
- break;
- }
-
- case KEYED: {
- UNIMPLEMENTED_MIPS();
- break;
- }
-
- default:
- UNREACHABLE();
+void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+class DeferredCountOperation: public DeferredCode {
+ public:
+ DeferredCountOperation(Register value,
+ bool is_increment,
+ bool is_postfix,
+ int target_size)
+ : value_(value),
+ is_increment_(is_increment),
+ is_postfix_(is_postfix),
+ target_size_(target_size) {}
+
+ virtual void Generate() {
+ UNIMPLEMENTED_MIPS();
}
+
+ private:
+ Register value_;
+ bool is_increment_;
+ bool is_postfix_;
+ int target_size_;
+};
+
+
+void CodeGenerator::VisitCountOperation(CountOperation* node) {
+ UNIMPLEMENTED_MIPS();
}
-// On entry a0 and a1 are the things to be compared. On exit v0 is 0,
-// positive or negative to indicate the result of the comparison.
-void CompareStub::Generate(MacroAssembler* masm) {
+void CodeGenerator::GenerateLogicalBooleanOperation(BinaryOperation* node) {
UNIMPLEMENTED_MIPS();
- __ break_(0x765);
}
-Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
+void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
UNIMPLEMENTED_MIPS();
- return Handle<Code>::null();
}
-void StackCheckStub::Generate(MacroAssembler* masm) {
+void CodeGenerator::VisitThisFunction(ThisFunction* node) {
UNIMPLEMENTED_MIPS();
- __ break_(0x790);
}
-void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
+void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
UNIMPLEMENTED_MIPS();
- __ break_(0x808);
}
-void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
- UncatchableExceptionType type) {
+void CodeGenerator::VisitCompareToNull(CompareToNull* node) {
UNIMPLEMENTED_MIPS();
- __ break_(0x815);
}
-void CEntryStub::GenerateCore(MacroAssembler* masm,
- Label* throw_normal_exception,
- Label* throw_termination_exception,
- Label* throw_out_of_memory_exception,
- bool do_gc,
- bool always_allocate) {
- // s0: number of arguments including receiver (C callee-saved)
- // s1: pointer to the first argument (C callee-saved)
- // s2: pointer to builtin function (C callee-saved)
- if (do_gc) {
- UNIMPLEMENTED_MIPS();
+class DeferredReferenceGetNamedValue: public DeferredCode {
+ public:
+ explicit DeferredReferenceGetNamedValue(Register receiver,
+ Handle<String> name,
+ bool is_contextual)
+ : receiver_(receiver),
+ name_(name),
+ is_contextual_(is_contextual),
+ is_dont_delete_(false) {
+ set_comment(is_contextual
+ ? "[ DeferredReferenceGetNamedValue (contextual)"
+ : "[ DeferredReferenceGetNamedValue");
}
- ExternalReference scope_depth =
- ExternalReference::heap_always_allocate_scope_depth();
- if (always_allocate) {
- UNIMPLEMENTED_MIPS();
+ virtual void Generate();
+
+ void set_is_dont_delete(bool value) {
+ ASSERT(is_contextual_);
+ is_dont_delete_ = value;
}
- // Call C built-in.
- // a0 = argc, a1 = argv
- __ mov(a0, s0);
- __ mov(a1, s1);
+ private:
+ Register receiver_;
+ Handle<String> name_;
+ bool is_contextual_;
+ bool is_dont_delete_;
+};
- __ CallBuiltin(s2);
- if (always_allocate) {
- UNIMPLEMENTED_MIPS();
+
+void DeferredReferenceGetNamedValue::Generate() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+class DeferredReferenceGetKeyedValue: public DeferredCode {
+ public:
+ DeferredReferenceGetKeyedValue(Register key, Register receiver)
+ : key_(key), receiver_(receiver) {
+ set_comment("[ DeferredReferenceGetKeyedValue");
}
- // Check for failure result.
- Label failure_returned;
- ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
- __ addiu(a2, v0, 1);
- __ andi(t0, a2, kFailureTagMask);
- __ Branch(eq, &failure_returned, t0, Operand(zero_reg));
-
- // Exit C frame and return.
- // v0:v1: result
- // sp: stack pointer
- // fp: frame pointer
- __ LeaveExitFrame(mode_);
-
- // Check if we should retry or throw exception.
- Label retry;
- __ bind(&failure_returned);
- ASSERT(Failure::RETRY_AFTER_GC == 0);
- __ andi(t0, v0, ((1 << kFailureTypeTagSize) - 1) << kFailureTagSize);
- __ Branch(eq, &retry, t0, Operand(zero_reg));
-
- // Special handling of out of memory exceptions.
- Failure* out_of_memory = Failure::OutOfMemoryException();
- __ Branch(eq, throw_out_of_memory_exception,
- v0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
-
- // Retrieve the pending exception and clear the variable.
- __ LoadExternalReference(t0, ExternalReference::the_hole_value_location());
- __ lw(a3, MemOperand(t0));
- __ LoadExternalReference(t0,
- ExternalReference(Top::k_pending_exception_address));
- __ lw(v0, MemOperand(t0));
- __ sw(a3, MemOperand(t0));
-
- // Special handling of termination exceptions which are uncatchable
- // by javascript code.
- __ Branch(eq, throw_termination_exception,
- v0, Operand(Factory::termination_exception()));
-
- // Handle normal exception.
- __ b(throw_normal_exception);
- __ nop(); // Branch delay slot nop.
-
- __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying
-}
-
-void CEntryStub::Generate(MacroAssembler* masm) {
- // Called from JavaScript; parameters are on stack as if calling JS function
- // a0: number of arguments including receiver
- // a1: pointer to builtin function
- // fp: frame pointer (restored after C call)
- // sp: stack pointer (restored as callee's sp after C call)
- // cp: current context (C callee-saved)
-
- // NOTE: Invocations of builtins may return failure objects
- // instead of a proper result. The builtin entry handles
- // this by performing a garbage collection and retrying the
- // builtin once.
-
- // Enter the exit frame that transitions from JavaScript to C++.
- __ EnterExitFrame(mode_, s0, s1, s2);
-
- // s0: number of arguments (C callee-saved)
- // s1: pointer to first argument (C callee-saved)
- // s2: pointer to builtin function (C callee-saved)
-
- Label throw_normal_exception;
- Label throw_termination_exception;
- Label throw_out_of_memory_exception;
-
- // Call into the runtime system.
- GenerateCore(masm,
- &throw_normal_exception,
- &throw_termination_exception,
- &throw_out_of_memory_exception,
- false,
- false);
-
- // Do space-specific GC and retry runtime call.
- GenerateCore(masm,
- &throw_normal_exception,
- &throw_termination_exception,
- &throw_out_of_memory_exception,
- true,
- false);
-
- // Do full GC and retry runtime call one final time.
- Failure* failure = Failure::InternalError();
- __ li(v0, Operand(reinterpret_cast<int32_t>(failure)));
- GenerateCore(masm,
- &throw_normal_exception,
- &throw_termination_exception,
- &throw_out_of_memory_exception,
- true,
- true);
-
- __ bind(&throw_out_of_memory_exception);
- GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
-
- __ bind(&throw_termination_exception);
- GenerateThrowUncatchable(masm, TERMINATION);
-
- __ bind(&throw_normal_exception);
- GenerateThrowTOS(masm);
-}
-
-void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
- Label invoke, exit;
-
- // Registers:
- // a0: entry address
- // a1: function
- // a2: reveiver
- // a3: argc
- //
- // Stack:
- // 4 args slots
- // args
-
- // Save callee saved registers on the stack.
- __ MultiPush((kCalleeSaved | ra.bit()) & ~sp.bit());
-
- // We build an EntryFrame.
- __ li(t3, Operand(-1)); // Push a bad frame pointer to fail if it is used.
- int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
- __ li(t2, Operand(Smi::FromInt(marker)));
- __ li(t1, Operand(Smi::FromInt(marker)));
- __ LoadExternalReference(t0, ExternalReference(Top::k_c_entry_fp_address));
- __ lw(t0, MemOperand(t0));
- __ MultiPush(t0.bit() | t1.bit() | t2.bit() | t3.bit());
-
- // Setup frame pointer for the frame to be pushed.
- __ addiu(fp, sp, -EntryFrameConstants::kCallerFPOffset);
-
- // Load argv in s0 register.
- __ lw(s0, MemOperand(sp, (kNumCalleeSaved + 1) * kPointerSize +
- StandardFrameConstants::kCArgsSlotsSize));
-
- // Registers:
- // a0: entry_address
- // a1: function
- // a2: reveiver_pointer
- // a3: argc
- // s0: argv
- //
- // Stack:
- // caller fp |
- // function slot | entry frame
- // context slot |
- // bad fp (0xff...f) |
- // callee saved registers + ra
- // 4 args slots
- // args
-
- // Call a faked try-block that does the invoke.
- __ bal(&invoke);
- __ nop(); // Branch delay slot nop.
-
- // Caught exception: Store result (exception) in the pending
- // exception field in the JSEnv and return a failure sentinel.
- // Coming in here the fp will be invalid because the PushTryHandler below
- // sets it to 0 to signal the existence of the JSEntry frame.
- __ LoadExternalReference(t0,
- ExternalReference(Top::k_pending_exception_address));
- __ sw(v0, MemOperand(t0)); // We come back from 'invoke'. result is in v0.
- __ li(v0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
- __ b(&exit);
- __ nop(); // Branch delay slot nop.
-
- // Invoke: Link this frame into the handler chain.
- __ bind(&invoke);
- __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
- // If an exception not caught by another handler occurs, this handler
- // returns control to the code after the bal(&invoke) above, which
- // restores all kCalleeSaved registers (including cp and fp) to their
- // saved values before returning a failure to C.
-
- // Clear any pending exceptions.
- __ LoadExternalReference(t0, ExternalReference::the_hole_value_location());
- __ lw(t1, MemOperand(t0));
- __ LoadExternalReference(t0,
- ExternalReference(Top::k_pending_exception_address));
- __ sw(t1, MemOperand(t0));
-
- // Invoke the function by calling through JS entry trampoline builtin.
- // Notice that we cannot store a reference to the trampoline code directly in
- // this stub, because runtime stubs are not traversed when doing GC.
-
- // Registers:
- // a0: entry_address
- // a1: function
- // a2: reveiver_pointer
- // a3: argc
- // s0: argv
- //
- // Stack:
- // handler frame
- // entry frame
- // callee saved registers + ra
- // 4 args slots
- // args
-
- if (is_construct) {
- ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
- __ LoadExternalReference(t0, construct_entry);
- } else {
- ExternalReference entry(Builtins::JSEntryTrampoline);
- __ LoadExternalReference(t0, entry);
+ virtual void Generate();
+
+ private:
+ Register key_;
+ Register receiver_;
+};
+
+
+void DeferredReferenceGetKeyedValue::Generate() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+class DeferredReferenceSetKeyedValue: public DeferredCode {
+ public:
+ DeferredReferenceSetKeyedValue(Register value,
+ Register key,
+ Register receiver)
+ : value_(value), key_(key), receiver_(receiver) {
+ set_comment("[ DeferredReferenceSetKeyedValue");
}
- __ lw(t9, MemOperand(t0)); // deref address
- // Call JSEntryTrampoline.
- __ addiu(t9, t9, Code::kHeaderSize - kHeapObjectTag);
- __ CallBuiltin(t9);
+ virtual void Generate();
- // Unlink this frame from the handler chain. When reading the
- // address of the next handler, there is no need to use the address
- // displacement since the current stack pointer (sp) points directly
- // to the stack handler.
- __ lw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset));
- __ LoadExternalReference(t0, ExternalReference(Top::k_handler_address));
- __ sw(t1, MemOperand(t0));
+ private:
+ Register value_;
+ Register key_;
+ Register receiver_;
+};
- // This restores sp to its position before PushTryHandler.
- __ addiu(sp, sp, StackHandlerConstants::kSize);
- __ bind(&exit); // v0 holds result
- // Restore the top frame descriptors from the stack.
- __ Pop(t1);
- __ LoadExternalReference(t0, ExternalReference(Top::k_c_entry_fp_address));
- __ sw(t1, MemOperand(t0));
+void DeferredReferenceSetKeyedValue::Generate() {
+ UNIMPLEMENTED_MIPS();
+}
+
- // Reset the stack to the callee saved registers.
- __ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
+class DeferredReferenceSetNamedValue: public DeferredCode {
+ public:
+ DeferredReferenceSetNamedValue(Register value,
+ Register receiver,
+ Handle<String> name)
+ : value_(value), receiver_(receiver), name_(name) {
+ set_comment("[ DeferredReferenceSetNamedValue");
+ }
- // Restore callee saved registers from the stack.
- __ MultiPop((kCalleeSaved | ra.bit()) & ~sp.bit());
- // Return.
- __ Jump(ra);
+ virtual void Generate();
+
+ private:
+ Register value_;
+ Register receiver_;
+ Handle<String> name_;
+};
+
+
+void DeferredReferenceSetNamedValue::Generate() {
+ UNIMPLEMENTED_MIPS();
}
-// This stub performs an instanceof, calling the builtin function if
-// necessary. Uses a1 for the object, a0 for the function that it may
-// be an instance of (these are fetched from the stack).
-void InstanceofStub::Generate(MacroAssembler* masm) {
+void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
UNIMPLEMENTED_MIPS();
- __ break_(0x845);
}
-void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
+void CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
UNIMPLEMENTED_MIPS();
- __ break_(0x851);
}
-void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
+void CodeGenerator::EmitKeyedLoad() {
UNIMPLEMENTED_MIPS();
- __ break_(0x857);
}
-void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
+void CodeGenerator::EmitKeyedStore(StaticType* key_type,
+ WriteBarrierCharacter wb_info) {
UNIMPLEMENTED_MIPS();
- __ break_(0x863);
}
-const char* CompareStub::GetName() {
+#ifdef DEBUG
+bool CodeGenerator::HasValidEntryRegisters() {
UNIMPLEMENTED_MIPS();
- return NULL; // UNIMPLEMENTED RETURN
+ return false;
}
+#endif
-int CompareStub::MinorKey() {
- // Encode the two parameters in a unique 16 bit value.
- ASSERT(static_cast<unsigned>(cc_) >> 28 < (1 << 15));
- return (static_cast<unsigned>(cc_) >> 27) | (strict_ ? 1 : 0);
+#undef __
+#define __ ACCESS_MASM(masm)
+
+// -----------------------------------------------------------------------------
+// Reference support.
+
+
+Handle<String> Reference::GetName() {
+ UNIMPLEMENTED_MIPS();
+ return Handle<String>();
+}
+
+
+void Reference::DupIfPersist() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void Reference::GetValue() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void Reference::SetValue(InitState init_state, WriteBarrierCharacter wb_info) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+const char* GenericBinaryOpStub::GetName() {
+ UNIMPLEMENTED_MIPS();
+ return name_;
}
diff --git a/src/mips/codegen-mips.h b/src/mips/codegen-mips.h
index 66f891bd..0a2cd458 100644
--- a/src/mips/codegen-mips.h
+++ b/src/mips/codegen-mips.h
@@ -29,17 +29,37 @@
#ifndef V8_MIPS_CODEGEN_MIPS_H_
#define V8_MIPS_CODEGEN_MIPS_H_
+
+#include "ast.h"
+#include "code-stubs-mips.h"
+#include "ic-inl.h"
+
namespace v8 {
namespace internal {
+#if(defined(__mips_hard_float) && __mips_hard_float != 0)
+// Use floating-point coprocessor instructions. This flag is raised when
+// -mhard-float is passed to the compiler.
+static const bool IsMipsSoftFloatABI = false;
+#elif(defined(__mips_soft_float) && __mips_soft_float != 0)
+// Not using floating-point coprocessor instructions. This flag is raised when
+// -msoft-float is passed to the compiler.
+static const bool IsMipsSoftFloatABI = true;
+#else
+static const bool IsMipsSoftFloatABI = true;
+#endif
+
// Forward declarations
class CompilationInfo;
class DeferredCode;
+class JumpTarget;
class RegisterAllocator;
class RegisterFile;
enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
+enum GenerateInlineSmi { DONT_GENERATE_INLINE_SMI, GENERATE_INLINE_SMI };
+enum WriteBarrierCharacter { UNLIKELY_SMI, LIKELY_SMI, NEVER_NEWSPACE };
// -----------------------------------------------------------------------------
@@ -101,7 +121,12 @@ class Reference BASE_EMBEDDED {
// on the expression stack. The value is stored in the location specified
// by the reference, and is left on top of the stack, after the reference
// is popped from beneath it (unloaded).
- void SetValue(InitState init_state);
+ void SetValue(InitState init_state, WriteBarrierCharacter wb);
+
+ // This is in preparation for something that uses the reference on the stack.
+ // If we need this reference afterwards get then dup it now. Otherwise mark
+ // it as used.
+ inline void DupIfPersist();
private:
CodeGenerator* cgen_;
@@ -126,31 +151,24 @@ class CodeGenState BASE_EMBEDDED {
// leaves the code generator with a NULL state.
explicit CodeGenState(CodeGenerator* owner);
- // Create a code generator state based on a code generator's current
- // state. The new state has its own typeof state and pair of branch
- // labels.
- CodeGenState(CodeGenerator* owner,
- JumpTarget* true_target,
- JumpTarget* false_target);
+
// Destroy a code generator state and restore the owning code generator's
// previous state.
- ~CodeGenState();
+ virtual ~CodeGenState();
- TypeofState typeof_state() const { return typeof_state_; }
- JumpTarget* true_target() const { return true_target_; }
- JumpTarget* false_target() const { return false_target_; }
+ virtual JumpTarget* true_target() const { return NULL; }
+ virtual JumpTarget* false_target() const { return NULL; }
+
+ protected:
+ inline CodeGenerator* owner() { return owner_; }
+ inline CodeGenState* previous() const { return previous_; }
private:
// The owning code generator.
CodeGenerator* owner_;
- // A flag indicating whether we are compiling the immediate subexpression
- // of a typeof expression.
- TypeofState typeof_state_;
- JumpTarget* true_target_;
- JumpTarget* false_target_;
// The previous state of the owning code generator, restored when
// this state is destroyed.
@@ -158,6 +176,50 @@ class CodeGenState BASE_EMBEDDED {
};
+class ConditionCodeGenState : public CodeGenState {
+ public:
+ // Create a code generator state based on a code generator's current
+ // state. The new state has its own pair of branch labels.
+ ConditionCodeGenState(CodeGenerator* owner,
+ JumpTarget* true_target,
+ JumpTarget* false_target);
+
+ virtual JumpTarget* true_target() const { return true_target_; }
+ virtual JumpTarget* false_target() const { return false_target_; }
+
+ private:
+ JumpTarget* true_target_;
+ JumpTarget* false_target_;
+};
+
+
+class TypeInfoCodeGenState : public CodeGenState {
+ public:
+ TypeInfoCodeGenState(CodeGenerator* owner,
+ Slot* slot_number,
+ TypeInfo info);
+ virtual ~TypeInfoCodeGenState();
+
+ virtual JumpTarget* true_target() const { return previous()->true_target(); }
+ virtual JumpTarget* false_target() const {
+ return previous()->false_target();
+ }
+
+ private:
+ Slot* slot_;
+ TypeInfo old_type_info_;
+};
+
+
+// -------------------------------------------------------------------------
+// Arguments allocation mode
+
+enum ArgumentsAllocationMode {
+ NO_ARGUMENTS_ALLOCATION,
+ EAGER_ARGUMENTS_ALLOCATION,
+ LAZY_ARGUMENTS_ALLOCATION
+};
+
// -----------------------------------------------------------------------------
// CodeGenerator
@@ -173,9 +235,7 @@ class CodeGenerator: public AstVisitor {
SECONDARY
};
- // Takes a function literal, generates code for it. This function should only
- // be called by compiler.cc.
- static Handle<Code> MakeCode(CompilationInfo* info);
+ static bool MakeCode(CompilationInfo* info);
// Printing of AST, etc. as requested by flags.
static void MakeCodePrologue(CompilationInfo* info);
@@ -185,6 +245,9 @@ class CodeGenerator: public AstVisitor {
Code::Flags flags,
CompilationInfo* info);
+ // Print the code after compiling it.
+ static void PrintCode(Handle<Code> code, CompilationInfo* info);
+
#ifdef ENABLE_LOGGING_AND_PROFILING
static bool ShouldGenerateLog(Expression* type);
#endif
@@ -194,7 +257,9 @@ class CodeGenerator: public AstVisitor {
bool is_toplevel,
Handle<Script> script);
- static void RecordPositions(MacroAssembler* masm, int pos);
+ static bool RecordPositions(MacroAssembler* masm,
+ int pos,
+ bool right_here = false);
// Accessors
MacroAssembler* masm() { return masm_; }
@@ -216,73 +281,105 @@ class CodeGenerator: public AstVisitor {
CodeGenState* state() { return state_; }
void set_state(CodeGenState* state) { state_ = state; }
+ TypeInfo type_info(Slot* slot) {
+ int index = NumberOfSlot(slot);
+ if (index == kInvalidSlotNumber) return TypeInfo::Unknown();
+ return (*type_info_)[index];
+ }
+
+ TypeInfo set_type_info(Slot* slot, TypeInfo info) {
+ int index = NumberOfSlot(slot);
+ ASSERT(index >= kInvalidSlotNumber);
+ if (index != kInvalidSlotNumber) {
+ TypeInfo previous_value = (*type_info_)[index];
+ (*type_info_)[index] = info;
+ return previous_value;
+ }
+ return TypeInfo::Unknown();
+ }
void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
- static const int kUnknownIntValue = -1;
+ // Constants related to patching of inlined load/store.
+ static int GetInlinedKeyedLoadInstructionsAfterPatch() {
+ // This is in correlation with the padding in MacroAssembler::Abort.
+ return FLAG_debug_code ? 45 : 20;
+ }
+ static const int kInlinedKeyedStoreInstructionsAfterPatch = 9;
+ static int GetInlinedNamedStoreInstructionsAfterPatch() {
+ ASSERT(Isolate::Current()->inlined_write_barrier_size() != -1);
+ // Magic number 5: instruction count after patched map load:
+ // li: 2 (liu & ori), Branch : 2 (bne & nop), sw : 1
+ return Isolate::Current()->inlined_write_barrier_size() + 5;
+ }
- // Number of instructions used for the JS return sequence. The constant is
- // used by the debugger to patch the JS return sequence.
- static const int kJSReturnSequenceLength = 7;
+ private:
+ // Type of a member function that generates inline code for a native function.
+ typedef void (CodeGenerator::*InlineFunctionGenerator)
+ (ZoneList<Expression*>*);
+
+ static const InlineFunctionGenerator kInlineFunctionGenerators[];
- // If the name is an inline runtime function call return the number of
- // expected arguments. Otherwise return -1.
- static int InlineRuntimeCallArgumentsCount(Handle<String> name);
- private:
// Construction/Destruction.
explicit CodeGenerator(MacroAssembler* masm);
// Accessors.
inline bool is_eval();
inline Scope* scope();
+ inline bool is_strict_mode();
+ inline StrictModeFlag strict_mode_flag();
// Generating deferred code.
void ProcessDeferred();
+ static const int kInvalidSlotNumber = -1;
+
+ int NumberOfSlot(Slot* slot);
// State
bool has_cc() const { return cc_reg_ != cc_always; }
- TypeofState typeof_state() const { return state_->typeof_state(); }
+
JumpTarget* true_target() const { return state_->true_target(); }
JumpTarget* false_target() const { return state_->false_target(); }
- // We don't track loop nesting level on mips yet.
- int loop_nesting() const { return 0; }
+ // Track loop nesting level.
+ int loop_nesting() const { return loop_nesting_; }
+ void IncrementLoopNesting() { loop_nesting_++; }
+ void DecrementLoopNesting() { loop_nesting_--; }
// Node visitors.
void VisitStatements(ZoneList<Statement*>* statements);
+ virtual void VisitSlot(Slot* node);
#define DEF_VISIT(type) \
- void Visit##type(type* node);
+ virtual void Visit##type(type* node);
AST_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
- // Visit a statement and then spill the virtual frame if control flow can
- // reach the end of the statement (ie, it does not exit via break,
- // continue, return, or throw). This function is used temporarily while
- // the code generator is being transformed.
- inline void VisitAndSpill(Statement* statement);
-
- // Visit a list of statements and then spill the virtual frame if control
- // flow can reach the end of the list.
- inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
-
// Main code generation function
void Generate(CompilationInfo* info);
+ // Generate the return sequence code. Should be called no more than
+ // once per compiled function, immediately after binding the return
+ // target (which can not be done more than once). The return value should
+ // be in v0.
+ void GenerateReturnSequence();
+
+ // Returns the arguments allocation mode.
+ ArgumentsAllocationMode ArgumentsMode();
+
+ // Store the arguments object and allocate it if necessary.
+ void StoreArgumentsObject(bool initial);
+
// The following are used by class Reference.
void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
- MemOperand ContextOperand(Register context, int index) const {
- return MemOperand(context, Context::SlotOffset(index));
- }
-
MemOperand SlotOperand(Slot* slot, Register tmp);
- // Expressions
- MemOperand GlobalObject() const {
- return ContextOperand(cp, Context::GLOBAL_INDEX);
- }
+ MemOperand ContextSlotOperandCheckExtensions(Slot* slot,
+ Register tmp,
+ Register tmp2,
+ JumpTarget* slow);
void LoadCondition(Expression* x,
JumpTarget* true_target,
@@ -290,35 +387,113 @@ class CodeGenerator: public AstVisitor {
bool force_cc);
void Load(Expression* x);
void LoadGlobal();
+ void LoadGlobalReceiver(Register scratch);
+
+
+ // Special code for typeof expressions: Unfortunately, we must
+ // be careful when loading the expression in 'typeof'
+ // expressions. We are not allowed to throw reference errors for
+ // non-existing properties of the global object, so we must make it
+ // look like an explicit property access, instead of an access
+ // through the context chain.
+ void LoadTypeofExpression(Expression* x);
- // Generate code to push the value of an expression on top of the frame
- // and then spill the frame fully to memory. This function is used
- // temporarily while the code generator is being transformed.
- inline void LoadAndSpill(Expression* expression);
+ // Store a keyed property. Key and receiver are on the stack and the value is
+ // in a0. Result is returned in r0.
+ void EmitKeyedStore(StaticType* key_type, WriteBarrierCharacter wb_info);
// Read a value from a slot and leave it on top of the expression stack.
void LoadFromSlot(Slot* slot, TypeofState typeof_state);
+ void LoadFromGlobalSlotCheckExtensions(Slot* slot,
+ TypeofState typeof_state,
+ JumpTarget* slow);
+ void LoadFromSlotCheckForArguments(Slot* slot, TypeofState state);
+
+ // Support for loading from local/global variables and arguments
+ // whose location is known unless they are shadowed by
+ // eval-introduced bindings. Generates no code for unsupported slot
+ // types and therefore expects to fall through to the slow jump target.
+ void EmitDynamicLoadFromSlotFastCase(Slot* slot,
+ TypeofState typeof_state,
+ JumpTarget* slow,
+ JumpTarget* done);
+
// Store the value on top of the stack to a slot.
void StoreToSlot(Slot* slot, InitState init_state);
- struct InlineRuntimeLUT {
- void (CodeGenerator::*method)(ZoneList<Expression*>*);
- const char* name;
- int nargs;
- };
+ // Support for compiling assignment expressions.
+ void EmitSlotAssignment(Assignment* node);
+ void EmitNamedPropertyAssignment(Assignment* node);
+ void EmitKeyedPropertyAssignment(Assignment* node);
+
+ // Load a named property, returning it in v0. The receiver is passed on the
+ // stack, and remains there.
+ void EmitNamedLoad(Handle<String> name, bool is_contextual);
+
+ // Store to a named property. If the store is contextual, value is passed on
+ // the frame and consumed. Otherwise, receiver and value are passed on the
+ // frame and consumed. The result is returned in v0.
+ void EmitNamedStore(Handle<String> name, bool is_contextual);
+
+ // Load a keyed property, leaving it in v0. The receiver and key are
+ // passed on the stack, and remain there.
+ void EmitKeyedLoad();
+
+ void ToBoolean(JumpTarget* true_target, JumpTarget* false_target);
+
+ // Generate code that computes a shortcutting logical operation.
+ void GenerateLogicalBooleanOperation(BinaryOperation* node);
+
+ void GenericBinaryOperation(Token::Value op,
+ OverwriteMode overwrite_mode,
+ GenerateInlineSmi inline_smi,
+ int known_rhs =
+ GenericBinaryOpStub::kUnknownIntValue);
+
+ void VirtualFrameBinaryOperation(Token::Value op,
+ OverwriteMode overwrite_mode,
+ int known_rhs =
+ GenericBinaryOpStub::kUnknownIntValue);
+
+ void SmiOperation(Token::Value op,
+ Handle<Object> value,
+ bool reversed,
+ OverwriteMode mode);
+
+ void Comparison(Condition cc,
+ Expression* left,
+ Expression* right,
+ bool strict = false);
+
+ void CallWithArguments(ZoneList<Expression*>* arguments,
+ CallFunctionFlags flags,
+ int position);
+
+ // An optimized implementation of expressions of the form
+ // x.apply(y, arguments). We call x the applicand and y the receiver.
+ // The optimization avoids allocating an arguments object if possible.
+ void CallApplyLazy(Expression* applicand,
+ Expression* receiver,
+ VariableProxy* arguments,
+ int position);
+
+ // Control flow
+ void Branch(bool if_true, JumpTarget* target);
+ void CheckStack();
- static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
bool CheckForInlineRuntimeCall(CallRuntime* node);
static Handle<Code> ComputeLazyCompile(int argc);
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
- Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
-
// Declare global variables and functions in the given array of
// name/value pairs.
void DeclareGlobals(Handle<FixedArray> pairs);
+ // Instantiate the function based on the shared function info.
+ void InstantiateFunction(Handle<SharedFunctionInfo> function_info,
+ bool pretenure);
+
// Support for type checks.
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
@@ -338,10 +513,13 @@ class CodeGenerator: public AstVisitor {
void GenerateSetValueOf(ZoneList<Expression*>* args);
// Fast support for charCodeAt(n).
- void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
+ void GenerateStringCharCodeAt(ZoneList<Expression*>* args);
// Fast support for string.charAt(n) and string[n].
- void GenerateCharFromCode(ZoneList<Expression*>* args);
+ void GenerateStringCharFromCode(ZoneList<Expression*>* args);
+
+ // Fast support for string.charAt(n) and string[n].
+ void GenerateStringCharAt(ZoneList<Expression*>* args);
// Fast support for object equality testing.
void GenerateObjectEquals(ZoneList<Expression*>* args);
@@ -358,14 +536,38 @@ class CodeGenerator: public AstVisitor {
void GenerateStringAdd(ZoneList<Expression*>* args);
void GenerateSubString(ZoneList<Expression*>* args);
void GenerateStringCompare(ZoneList<Expression*>* args);
+ void GenerateIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args);
+
+ // Support for direct calls from JavaScript to native RegExp code.
void GenerateRegExpExec(ZoneList<Expression*>* args);
+
+ void GenerateRegExpConstructResult(ZoneList<Expression*>* args);
+
+ // Support for fast native caches.
+ void GenerateGetFromCache(ZoneList<Expression*>* args);
+
+ // Fast support for number to string.
void GenerateNumberToString(ZoneList<Expression*>* args);
+ // Fast swapping of elements.
+ void GenerateSwapElements(ZoneList<Expression*>* args);
+
+ // Fast call for custom callbacks.
+ void GenerateCallFunction(ZoneList<Expression*>* args);
+
// Fast call to math functions.
void GenerateMathPow(ZoneList<Expression*>* args);
void GenerateMathSin(ZoneList<Expression*>* args);
void GenerateMathCos(ZoneList<Expression*>* args);
void GenerateMathSqrt(ZoneList<Expression*>* args);
+ void GenerateMathLog(ZoneList<Expression*>* args);
+
+ void GenerateIsRegExpEquivalent(ZoneList<Expression*>* args);
+
+ void GenerateHasCachedArrayIndex(ZoneList<Expression*>* args);
+ void GenerateGetCachedArrayIndex(ZoneList<Expression*>* args);
+ void GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis {
@@ -389,9 +591,6 @@ class CodeGenerator: public AstVisitor {
bool HasValidEntryRegisters();
#endif
- bool is_eval_; // Tells whether code is generated for eval.
-
- Handle<Script> script_;
List<DeferredCode*> deferred_;
// Assembler
@@ -404,7 +603,9 @@ class CodeGenerator: public AstVisitor {
RegisterAllocator* allocator_;
Condition cc_reg_;
CodeGenState* state_;
+ int loop_nesting_;
+ Vector<TypeInfo>* type_info_;
// Jump targets
BreakTarget function_return_;
@@ -413,14 +614,15 @@ class CodeGenerator: public AstVisitor {
// to some unlinking code).
bool function_return_is_shadowed_;
- static InlineRuntimeLUT kInlineRuntimeLUT[];
-
friend class VirtualFrame;
+ friend class Isolate;
friend class JumpTarget;
friend class Reference;
friend class FastCodeGenerator;
friend class FullCodeGenerator;
friend class FullCodeGenSyntaxChecker;
+ friend class InlineRuntimeFunctionsTable;
+ friend class LCodeGen;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
diff --git a/src/mips/constants-mips.cc b/src/mips/constants-mips.cc
index 49502bde..16e49c9c 100644
--- a/src/mips/constants-mips.cc
+++ b/src/mips/constants-mips.cc
@@ -31,10 +31,8 @@
#include "constants-mips.h"
-namespace assembler {
-namespace mips {
-
-namespace v8i = v8::internal;
+namespace v8 {
+namespace internal {
// -----------------------------------------------------------------------------
@@ -102,20 +100,20 @@ int Registers::Number(const char* name) {
}
-const char* FPURegister::names_[kNumFPURegister] = {
+const char* FPURegisters::names_[kNumFPURegisters] = {
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11",
"f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21",
"f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
};
// List of alias names which can be used when referring to MIPS registers.
-const FPURegister::RegisterAlias FPURegister::aliases_[] = {
+const FPURegisters::RegisterAlias FPURegisters::aliases_[] = {
{kInvalidRegister, NULL}
};
-const char* FPURegister::Name(int creg) {
+const char* FPURegisters::Name(int creg) {
const char* result;
- if ((0 <= creg) && (creg < kNumFPURegister)) {
+ if ((0 <= creg) && (creg < kNumFPURegisters)) {
result = names_[creg];
} else {
result = "nocreg";
@@ -124,9 +122,9 @@ const char* FPURegister::Name(int creg) {
}
-int FPURegister::Number(const char* name) {
+int FPURegisters::Number(const char* name) {
// Look through the canonical names.
- for (int i = 0; i < kNumSimuRegisters; i++) {
+ for (int i = 0; i < kNumFPURegisters; i++) {
if (strcmp(names_[i], name) == 0) {
return i;
}
@@ -149,8 +147,8 @@ int FPURegister::Number(const char* name) {
// -----------------------------------------------------------------------------
// Instruction
-bool Instruction::IsForbiddenInBranchDelay() {
- int op = OpcodeFieldRaw();
+bool Instruction::IsForbiddenInBranchDelay() const {
+ const int op = OpcodeFieldRaw();
switch (op) {
case J:
case JAL:
@@ -189,13 +187,18 @@ bool Instruction::IsForbiddenInBranchDelay() {
}
-bool Instruction::IsLinkingInstruction() {
- int op = OpcodeFieldRaw();
+bool Instruction::IsLinkingInstruction() const {
+ const int op = OpcodeFieldRaw();
switch (op) {
case JAL:
- case BGEZAL:
- case BLTZAL:
- return true;
+ case REGIMM:
+ switch (RtFieldRaw()) {
+ case BGEZAL:
+ case BLTZAL:
+ return true;
+ default:
+ return false;
+ };
case SPECIAL:
switch (FunctionFieldRaw()) {
case JALR:
@@ -209,7 +212,7 @@ bool Instruction::IsLinkingInstruction() {
}
-bool Instruction::IsTrap() {
+bool Instruction::IsTrap() const {
if (OpcodeFieldRaw() != SPECIAL) {
return false;
} else {
@@ -264,6 +267,9 @@ Instruction::Type Instruction::InstructionType() const {
case TLTU:
case TEQ:
case TNE:
+ case MOVZ:
+ case MOVN:
+ case MOVCI:
return kRegisterType;
default:
UNREACHABLE();
@@ -272,13 +278,23 @@ Instruction::Type Instruction::InstructionType() const {
case SPECIAL2:
switch (FunctionFieldRaw()) {
case MUL:
+ case CLZ:
return kRegisterType;
default:
UNREACHABLE();
};
break;
- case COP1: // Coprocessor instructions
+ case SPECIAL3:
switch (FunctionFieldRaw()) {
+ case INS:
+ case EXT:
+ return kRegisterType;
+ default:
+ UNREACHABLE();
+ };
+ break;
+ case COP1: // Coprocessor instructions
+ switch (RsFieldRawNoAssert()) {
case BC1: // branch on coprocessor condition
return kImmediateType;
default:
@@ -304,10 +320,17 @@ Instruction::Type Instruction::InstructionType() const {
case BLEZL:
case BGTZL:
case LB:
+ case LH:
+ case LWL:
case LW:
case LBU:
+ case LHU:
+ case LWR:
case SB:
+ case SH:
+ case SWL:
case SW:
+ case SWR:
case LWC1:
case LDC1:
case SWC1:
@@ -323,6 +346,7 @@ Instruction::Type Instruction::InstructionType() const {
return kUnsupported;
}
-} } // namespace assembler::mips
+
+} } // namespace v8::internal
#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h
index d0fdf88d..b20e9a28 100644
--- a/src/mips/constants-mips.h
+++ b/src/mips/constants-mips.h
@@ -28,15 +28,25 @@
#ifndef V8_MIPS_CONSTANTS_H_
#define V8_MIPS_CONSTANTS_H_
-#include "checks.h"
-
// UNIMPLEMENTED_ macro for MIPS.
+#ifdef DEBUG
#define UNIMPLEMENTED_MIPS() \
v8::internal::PrintF("%s, \tline %d: \tfunction %s not implemented. \n", \
__FILE__, __LINE__, __func__)
+#else
+#define UNIMPLEMENTED_MIPS()
+#endif
+
#define UNSUPPORTED_MIPS() v8::internal::PrintF("Unsupported instruction.\n")
+#ifdef _MIPS_ARCH_MIPS32R2
+ #define mips32r2 1
+#else
+ #define mips32r2 0
+#endif
+
+
// Defines constants and accessor classes to assemble, disassemble and
// simulate MIPS32 instructions.
//
@@ -44,8 +54,8 @@
// Volume II: The MIPS32 Instruction Set
// Try www.cs.cornell.edu/courses/cs3410/2008fa/MIPS_Vol2.pdf.
-namespace assembler {
-namespace mips {
+namespace v8 {
+namespace internal {
// -----------------------------------------------------------------------------
// Registers and FPURegister.
@@ -61,9 +71,18 @@ static const int kNumSimuRegisters = 35;
static const int kPCRegister = 34;
// Number coprocessor registers.
-static const int kNumFPURegister = 32;
+static const int kNumFPURegisters = 32;
static const int kInvalidFPURegister = -1;
+// FPU (coprocessor 1) control registers. Currently only FCSR is implemented.
+static const int kFCSRRegister = 31;
+static const int kInvalidFPUControlRegister = -1;
+static const uint32_t kFPUInvalidResult = (uint32_t) (1 << 31) - 1;
+
+// FCSR constants.
+static const uint32_t kFCSRFlagMask = (1 << 6) - 1;
+static const uint32_t kFCSRFlagShift = 2;
+
// Helper functions for converting between register numbers and names.
class Registers {
public:
@@ -88,7 +107,7 @@ class Registers {
};
// Helper functions for converting between register numbers and names.
-class FPURegister {
+class FPURegisters {
public:
// Return the name of the register.
static const char* Name(int reg);
@@ -103,7 +122,7 @@ class FPURegister {
private:
- static const char* names_[kNumFPURegister];
+ static const char* names_[kNumFPURegisters];
static const RegisterAlias aliases_[];
};
@@ -136,6 +155,7 @@ static const int kSaShift = 6;
static const int kSaBits = 5;
static const int kFunctionShift = 0;
static const int kFunctionBits = 6;
+static const int kLuiShift = 16;
static const int kImm16Shift = 0;
static const int kImm16Bits = 16;
@@ -146,6 +166,14 @@ static const int kFsShift = 11;
static const int kFsBits = 5;
static const int kFtShift = 16;
static const int kFtBits = 5;
+static const int kFdShift = 6;
+static const int kFdBits = 5;
+static const int kFCccShift = 8;
+static const int kFCccBits = 3;
+static const int kFBccShift = 18;
+static const int kFBccBits = 3;
+static const int kFBtrueShift = 16;
+static const int kFBtrueBits = 1;
// ----- Miscellianous useful masks.
// Instruction bit masks.
@@ -159,9 +187,9 @@ static const int kSaFieldMask = ((1 << kSaBits) - 1) << kSaShift;
static const int kFunctionFieldMask =
((1 << kFunctionBits) - 1) << kFunctionShift;
// Misc masks.
-static const int HIMask = 0xffff << 16;
-static const int LOMask = 0xffff;
-static const int signMask = 0x80000000;
+static const int kHiMask = 0xffff << 16;
+static const int kLoMask = 0xffff;
+static const int kSignMask = 0x80000000;
// ----- MIPS Opcodes and Function Fields.
@@ -194,12 +222,20 @@ enum Opcode {
BGTZL = ((2 << 3) + 7) << kOpcodeShift,
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
+ SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
LB = ((4 << 3) + 0) << kOpcodeShift,
+ LH = ((4 << 3) + 1) << kOpcodeShift,
+ LWL = ((4 << 3) + 2) << kOpcodeShift,
LW = ((4 << 3) + 3) << kOpcodeShift,
LBU = ((4 << 3) + 4) << kOpcodeShift,
+ LHU = ((4 << 3) + 5) << kOpcodeShift,
+ LWR = ((4 << 3) + 6) << kOpcodeShift,
SB = ((5 << 3) + 0) << kOpcodeShift,
+ SH = ((5 << 3) + 1) << kOpcodeShift,
+ SWL = ((5 << 3) + 2) << kOpcodeShift,
SW = ((5 << 3) + 3) << kOpcodeShift,
+ SWR = ((5 << 3) + 6) << kOpcodeShift,
LWC1 = ((6 << 3) + 1) << kOpcodeShift,
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
@@ -216,9 +252,12 @@ enum SecondaryField {
SLLV = ((0 << 3) + 4),
SRLV = ((0 << 3) + 6),
SRAV = ((0 << 3) + 7),
+ MOVCI = ((0 << 3) + 1),
JR = ((1 << 3) + 0),
JALR = ((1 << 3) + 1),
+ MOVZ = ((1 << 3) + 2),
+ MOVN = ((1 << 3) + 3),
BREAK = ((1 << 3) + 5),
MFHI = ((2 << 3) + 0),
@@ -250,6 +289,12 @@ enum SecondaryField {
// SPECIAL2 Encoding of Function Field.
MUL = ((0 << 3) + 2),
+ CLZ = ((4 << 3) + 0),
+ CLO = ((4 << 3) + 1),
+
+ // SPECIAL3 Encoding of Function Field.
+ EXT = ((0 << 3) + 0),
+ INS = ((0 << 3) + 4),
// REGIMM encoding of rt Field.
BLTZ = ((0 << 3) + 0) << 16,
@@ -259,8 +304,10 @@ enum SecondaryField {
// COP1 Encoding of rs Field.
MFC1 = ((0 << 3) + 0) << 21,
+ CFC1 = ((0 << 3) + 2) << 21,
MFHC1 = ((0 << 3) + 3) << 21,
MTC1 = ((0 << 3) + 4) << 21,
+ CTC1 = ((0 << 3) + 6) << 21,
MTHC1 = ((0 << 3) + 7) << 21,
BC1 = ((1 << 3) + 0) << 21,
S = ((2 << 3) + 0) << 21,
@@ -269,14 +316,46 @@ enum SecondaryField {
L = ((2 << 3) + 5) << 21,
PS = ((2 << 3) + 6) << 21,
// COP1 Encoding of Function Field When rs=S.
+ ROUND_L_S = ((1 << 3) + 0),
+ TRUNC_L_S = ((1 << 3) + 1),
+ CEIL_L_S = ((1 << 3) + 2),
+ FLOOR_L_S = ((1 << 3) + 3),
+ ROUND_W_S = ((1 << 3) + 4),
+ TRUNC_W_S = ((1 << 3) + 5),
+ CEIL_W_S = ((1 << 3) + 6),
+ FLOOR_W_S = ((1 << 3) + 7),
CVT_D_S = ((4 << 3) + 1),
CVT_W_S = ((4 << 3) + 4),
CVT_L_S = ((4 << 3) + 5),
CVT_PS_S = ((4 << 3) + 6),
// COP1 Encoding of Function Field When rs=D.
+ ADD_D = ((0 << 3) + 0),
+ SUB_D = ((0 << 3) + 1),
+ MUL_D = ((0 << 3) + 2),
+ DIV_D = ((0 << 3) + 3),
+ SQRT_D = ((0 << 3) + 4),
+ ABS_D = ((0 << 3) + 5),
+ MOV_D = ((0 << 3) + 6),
+ NEG_D = ((0 << 3) + 7),
+ ROUND_L_D = ((1 << 3) + 0),
+ TRUNC_L_D = ((1 << 3) + 1),
+ CEIL_L_D = ((1 << 3) + 2),
+ FLOOR_L_D = ((1 << 3) + 3),
+ ROUND_W_D = ((1 << 3) + 4),
+ TRUNC_W_D = ((1 << 3) + 5),
+ CEIL_W_D = ((1 << 3) + 6),
+ FLOOR_W_D = ((1 << 3) + 7),
CVT_S_D = ((4 << 3) + 0),
CVT_W_D = ((4 << 3) + 4),
CVT_L_D = ((4 << 3) + 5),
+ C_F_D = ((6 << 3) + 0),
+ C_UN_D = ((6 << 3) + 1),
+ C_EQ_D = ((6 << 3) + 2),
+ C_UEQ_D = ((6 << 3) + 3),
+ C_OLT_D = ((6 << 3) + 4),
+ C_ULT_D = ((6 << 3) + 5),
+ C_OLE_D = ((6 << 3) + 6),
+ C_ULE_D = ((6 << 3) + 7),
// COP1 Encoding of Function Field When rs=W or L.
CVT_S_W = ((4 << 3) + 0),
CVT_D_W = ((4 << 3) + 1),
@@ -293,7 +372,7 @@ enum SecondaryField {
// the 'U' prefix is used to specify unsigned comparisons.
enum Condition {
// Any value < 0 is considered no_condition.
- no_condition = -1,
+ kNoCondition = -1,
overflow = 0,
no_overflow = 1,
@@ -321,12 +400,59 @@ enum Condition {
eq = equal,
not_zero = not_equal,
ne = not_equal,
+ nz = not_equal,
sign = negative,
not_sign = positive,
-
- cc_default = no_condition
+ mi = negative,
+ pl = positive,
+ hi = Ugreater,
+ ls = Uless_equal,
+ ge = greater_equal,
+ lt = less,
+ gt = greater,
+ le = less_equal,
+ hs = Ugreater_equal,
+ lo = Uless,
+ al = cc_always,
+
+ cc_default = kNoCondition
};
+
+// Returns the equivalent of !cc.
+// Negation of the default kNoCondition (-1) results in a non-default
+// no_condition value (-2). As long as tests for no_condition check
+// for condition < 0, this will work as expected.
+inline Condition NegateCondition(Condition cc) {
+ ASSERT(cc != cc_always);
+ return static_cast<Condition>(cc ^ 1);
+}
+
+
+inline Condition ReverseCondition(Condition cc) {
+ switch (cc) {
+ case Uless:
+ return Ugreater;
+ case Ugreater:
+ return Uless;
+ case Ugreater_equal:
+ return Uless_equal;
+ case Uless_equal:
+ return Ugreater_equal;
+ case less:
+ return greater;
+ case greater:
+ return less;
+ case greater_equal:
+ return less_equal;
+ case less_equal:
+ return greater_equal;
+ default:
+ return cc;
+ };
+}
+
+
// ----- Coprocessor conditions.
enum FPUCondition {
F, // False
@@ -340,6 +466,46 @@ enum FPUCondition {
};
+// -----------------------------------------------------------------------------
+// Hints.
+
+// Branch hints are not used on the MIPS. They are defined so that they can
+// appear in shared function signatures, but will be ignored in MIPS
+// implementations.
+enum Hint {
+ no_hint = 0
+};
+
+
+inline Hint NegateHint(Hint hint) {
+ return no_hint;
+}
+
+
+// -----------------------------------------------------------------------------
+// Specific instructions, constants, and masks.
+// These constants are declared in assembler-mips.cc, as they use named
+// registers and other constants.
+
+// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
+// operations as post-increment of sp.
+extern const Instr kPopInstruction;
+// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
+extern const Instr kPushInstruction;
+// sw(r, MemOperand(sp, 0))
+extern const Instr kPushRegPattern;
+// lw(r, MemOperand(sp, 0))
+extern const Instr kPopRegPattern;
+extern const Instr kLwRegFpOffsetPattern;
+extern const Instr kSwRegFpOffsetPattern;
+extern const Instr kLwRegFpNegOffsetPattern;
+extern const Instr kSwRegFpNegOffsetPattern;
+// A mask for the Rt register for push, pop, lw, sw instructions.
+extern const Instr kRtMask;
+extern const Instr kLwSwInstrTypeMask;
+extern const Instr kLwSwInstrArgumentMask;
+extern const Instr kLwSwOffsetMask;
+
// Break 0xfffff, reserved for redirected real time call.
const Instr rtCallRedirInstr = SPECIAL | BREAK | call_rt_redirected << 6;
// A nop instruction. (Encoding of sll 0 0 0).
@@ -348,10 +514,10 @@ const Instr nopInstr = 0;
class Instruction {
public:
enum {
- kInstructionSize = 4,
- kInstructionSizeLog2 = 2,
+ kInstrSize = 4,
+ kInstrSizeLog2 = 2,
// On MIPS PC cannot actually be directly accessed. We behave as if PC was
- // always the value of the current instruction being exectued.
+ // always the value of the current instruction being executed.
kPCReadOffset = 0
};
@@ -388,45 +554,64 @@ class Instruction {
// Accessors for the different named fields used in the MIPS encoding.
- inline Opcode OpcodeField() const {
+ inline Opcode OpcodeValue() const {
return static_cast<Opcode>(
Bits(kOpcodeShift + kOpcodeBits - 1, kOpcodeShift));
}
- inline int RsField() const {
+ inline int RsValue() const {
ASSERT(InstructionType() == kRegisterType ||
InstructionType() == kImmediateType);
return Bits(kRsShift + kRsBits - 1, kRsShift);
}
- inline int RtField() const {
+ inline int RtValue() const {
ASSERT(InstructionType() == kRegisterType ||
InstructionType() == kImmediateType);
return Bits(kRtShift + kRtBits - 1, kRtShift);
}
- inline int RdField() const {
+ inline int RdValue() const {
ASSERT(InstructionType() == kRegisterType);
return Bits(kRdShift + kRdBits - 1, kRdShift);
}
- inline int SaField() const {
+ inline int SaValue() const {
ASSERT(InstructionType() == kRegisterType);
return Bits(kSaShift + kSaBits - 1, kSaShift);
}
- inline int FunctionField() const {
+ inline int FunctionValue() const {
ASSERT(InstructionType() == kRegisterType ||
InstructionType() == kImmediateType);
return Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift);
}
- inline int FsField() const {
- return Bits(kFsShift + kRsBits - 1, kFsShift);
+ inline int FdValue() const {
+ return Bits(kFdShift + kFdBits - 1, kFdShift);
+ }
+
+ inline int FsValue() const {
+ return Bits(kFsShift + kFsBits - 1, kFsShift);
+ }
+
+ inline int FtValue() const {
+ return Bits(kFtShift + kFtBits - 1, kFtShift);
}
- inline int FtField() const {
- return Bits(kFtShift + kRsBits - 1, kFtShift);
+ // Float Compare condition code instruction bits.
+ inline int FCccValue() const {
+ return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
+ }
+
+ // Float Branch condition code instruction bits.
+ inline int FBccValue() const {
+ return Bits(kFBccShift + kFBccBits - 1, kFBccShift);
+ }
+
+ // Float Branch true/false instruction bit.
+ inline int FBtrueValue() const {
+ return Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift);
}
// Return the fields at their original place in the instruction encoding.
@@ -440,6 +625,11 @@ class Instruction {
return InstructionBits() & kRsFieldMask;
}
+ // Same as above function, but safe to call within InstructionType().
+ inline int RsFieldRawNoAssert() const {
+ return InstructionBits() & kRsFieldMask;
+ }
+
inline int RtFieldRaw() const {
ASSERT(InstructionType() == kRegisterType ||
InstructionType() == kImmediateType);
@@ -461,37 +651,37 @@ class Instruction {
}
// Get the secondary field according to the opcode.
- inline int SecondaryField() const {
+ inline int SecondaryValue() const {
Opcode op = OpcodeFieldRaw();
switch (op) {
case SPECIAL:
case SPECIAL2:
- return FunctionField();
+ return FunctionValue();
case COP1:
- return RsField();
+ return RsValue();
case REGIMM:
- return RtField();
+ return RtValue();
default:
return NULLSF;
}
}
- inline int32_t Imm16Field() const {
+ inline int32_t Imm16Value() const {
ASSERT(InstructionType() == kImmediateType);
return Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
}
- inline int32_t Imm26Field() const {
+ inline int32_t Imm26Value() const {
ASSERT(InstructionType() == kJumpType);
return Bits(kImm16Shift + kImm26Bits - 1, kImm26Shift);
}
// Say if the instruction should not be used in a branch delay slot.
- bool IsForbiddenInBranchDelay();
+ bool IsForbiddenInBranchDelay() const;
// Say if the instruction 'links'. eg: jal, bal.
- bool IsLinkingInstruction();
+ bool IsLinkingInstruction() const;
// Say if the instruction is a break or a trap.
- bool IsTrap();
+ bool IsTrap() const;
// Instructions are read of out a code stream. The only way to get a
// reference to an instruction is to convert a pointer. There is no way
@@ -510,16 +700,24 @@ class Instruction {
// -----------------------------------------------------------------------------
// MIPS assembly various constants.
-static const int kArgsSlotsSize = 4 * Instruction::kInstructionSize;
+
+static const int kArgsSlotsSize = 4 * Instruction::kInstrSize;
static const int kArgsSlotsNum = 4;
+// C/C++ argument slots size.
+static const int kCArgsSlotsSize = 4 * Instruction::kInstrSize;
+// JS argument slots size.
+static const int kJSArgsSlotsSize = 0 * Instruction::kInstrSize;
+// Assembly builtins argument slots size.
+static const int kBArgsSlotsSize = 0 * Instruction::kInstrSize;
-static const int kBranchReturnOffset = 2 * Instruction::kInstructionSize;
+static const int kBranchReturnOffset = 2 * Instruction::kInstrSize;
-static const int kDoubleAlignment = 2 * 8;
-static const int kDoubleAlignmentMask = kDoubleAlignmentMask - 1;
+static const int kDoubleAlignmentBits = 3;
+static const int kDoubleAlignment = (1 << kDoubleAlignmentBits);
+static const int kDoubleAlignmentMask = kDoubleAlignment - 1;
-} } // namespace assembler::mips
+} } // namespace v8::internal
#endif // #ifndef V8_MIPS_CONSTANTS_H_
diff --git a/src/mips/cpu-mips.cc b/src/mips/cpu-mips.cc
index 659fc01c..36f577bd 100644
--- a/src/mips/cpu-mips.cc
+++ b/src/mips/cpu-mips.cc
@@ -39,16 +39,25 @@
#if defined(V8_TARGET_ARCH_MIPS)
#include "cpu.h"
+#include "macro-assembler.h"
+
+#include "simulator.h" // For cache flushing.
namespace v8 {
namespace internal {
+
void CPU::Setup() {
- // Nothing to do.
+ CpuFeatures* cpu_features = Isolate::Current()->cpu_features();
+ cpu_features->Probe(true);
+ if (!cpu_features->IsSupported(FPU) || Serializer::enabled()) {
+ V8::DisableCrankshaft();
+ }
}
+
void CPU::FlushICache(void* start, size_t size) {
-#ifdef __mips
+#if !defined (USE_SIMULATOR)
int res;
// See http://www.linux-mips.org/wiki/Cacheflush_Syscall
@@ -58,7 +67,14 @@ void CPU::FlushICache(void* start, size_t size) {
V8_Fatal(__FILE__, __LINE__, "Failed to flush the instruction cache");
}
-#endif // #ifdef __mips
+#else // USE_SIMULATOR.
+ // Not generating mips instructions for C-code. This means that we are
+ // building a mips emulator based target. We should notify the simulator
+ // that the Icache was flushed.
+ // None of this code ends up in the snapshot so there are no issues
+ // around whether or not to generate the code when building snapshots.
+ Simulator::FlushICache(Isolate::Current()->simulator_i_cache(), start, size);
+#endif // USE_SIMULATOR.
}
@@ -68,6 +84,7 @@ void CPU::DebugBreak() {
#endif // #ifdef __mips
}
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/mips/debug-mips.cc b/src/mips/debug-mips.cc
index b8ae68e3..35df69b8 100644
--- a/src/mips/debug-mips.cc
+++ b/src/mips/debug-mips.cc
@@ -38,8 +38,10 @@ namespace v8 {
namespace internal {
#ifdef ENABLE_DEBUGGER_SUPPORT
+
bool BreakLocationIterator::IsDebugBreakAtReturn() {
- return Debug::IsDebugBreakAtReturn(rinfo());
+ UNIMPLEMENTED_MIPS();
+ return false;
}
@@ -54,16 +56,31 @@ void BreakLocationIterator::ClearDebugBreakAtReturn() {
}
-// A debug break in the exit code is identified by a call.
+// A debug break in the exit code is identified by the JS frame exit code
+// having been patched with li/call psuedo-instrunction (liu/ori/jalr)
bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
- ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
- return rinfo->IsPatchedReturnSequence();
+ UNIMPLEMENTED_MIPS();
+ return false;
}
-#define __ ACCESS_MASM(masm)
+bool BreakLocationIterator::IsDebugBreakAtSlot() {
+ UNIMPLEMENTED_MIPS();
+ return false;
+}
+
+
+void BreakLocationIterator::SetDebugBreakAtSlot() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void BreakLocationIterator::ClearDebugBreakAtSlot() {
+ UNIMPLEMENTED_MIPS();
+}
+#define __ ACCESS_MASM(masm)
void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
@@ -106,12 +123,23 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
}
+void Debug::GenerateSlot(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
- masm->Abort("LiveEdit frame dropping is not supported on mips");
+ UNIMPLEMENTED_MIPS();
}
+
void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
- masm->Abort("LiveEdit frame dropping is not supported on mips");
+ UNIMPLEMENTED_MIPS();
}
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
new file mode 100644
index 00000000..4b69859a
--- /dev/null
+++ b/src/mips/deoptimizer-mips.cc
@@ -0,0 +1,91 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "codegen.h"
+#include "deoptimizer.h"
+#include "full-codegen.h"
+#include "safepoint-table.h"
+
+// Note: this file was taken from the X64 version. ARM has a partially working
+// lithium implementation, but for now it is not ported to mips.
+
+namespace v8 {
+namespace internal {
+
+
+int Deoptimizer::table_entry_size_ = 10;
+
+
+int Deoptimizer::patch_size() {
+ const int kCallInstructionSizeInWords = 3;
+ return kCallInstructionSizeInWords * Assembler::kInstrSize;
+}
+
+
+void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
+ UNIMPLEMENTED();
+}
+
+
+void Deoptimizer::PatchStackCheckCodeAt(Address pc_after,
+ Code* check_code,
+ Code* replacement_code) {
+ UNIMPLEMENTED();
+}
+
+
+void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
+ Code* check_code,
+ Code* replacement_code) {
+ UNIMPLEMENTED();
+}
+
+
+void Deoptimizer::DoComputeOsrOutputFrame() {
+ UNIMPLEMENTED();
+}
+
+
+void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
+ int frame_index) {
+ UNIMPLEMENTED();
+}
+
+
+void Deoptimizer::EntryGenerator::Generate() {
+ UNIMPLEMENTED();
+}
+
+
+void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
+ UNIMPLEMENTED();
+}
+
+
+} } // namespace v8::internal
diff --git a/src/mips/disasm-mips.cc b/src/mips/disasm-mips.cc
index 959a4a22..b7ceb2b1 100644
--- a/src/mips/disasm-mips.cc
+++ b/src/mips/disasm-mips.cc
@@ -34,10 +34,9 @@
// NameConverter converter;
// Disassembler d(converter);
// for (byte_* pc = begin; pc < end;) {
-// char buffer[128];
-// buffer[0] = '\0';
-// byte_* prev_pc = pc;
-// pc += d.InstructionDecode(buffer, sizeof buffer, pc);
+// v8::internal::EmbeddedVector<char, 256> buffer;
+// byte* prev_pc = pc;
+// pc += d.InstructionDecode(buffer, pc);
// printf("%p %08x %s\n",
// prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
// }
@@ -59,17 +58,13 @@
#if defined(V8_TARGET_ARCH_MIPS)
-#include "constants-mips.h"
+#include "mips/constants-mips.h"
#include "disasm.h"
#include "macro-assembler.h"
#include "platform.h"
-namespace assembler {
-namespace mips {
-
-
-namespace v8i = v8::internal;
-
+namespace v8 {
+namespace internal {
//------------------------------------------------------------------------------
@@ -99,7 +94,7 @@ class Decoder {
// Printing of common values.
void PrintRegister(int reg);
- void PrintCRegister(int creg);
+ void PrintFPURegister(int freg);
void PrintRs(Instruction* instr);
void PrintRt(Instruction* instr);
void PrintRd(Instruction* instr);
@@ -107,6 +102,9 @@ class Decoder {
void PrintFt(Instruction* instr);
void PrintFd(Instruction* instr);
void PrintSa(Instruction* instr);
+ void PrintSd(Instruction* instr);
+ void PrintBc(Instruction* instr);
+ void PrintCc(Instruction* instr);
void PrintFunction(Instruction* instr);
void PrintSecondaryField(Instruction* instr);
void PrintUImm16(Instruction* instr);
@@ -119,7 +117,7 @@ class Decoder {
// Handle formatting of instructions and their options.
int FormatRegister(Instruction* instr, const char* option);
- int FormatCRegister(Instruction* instr, const char* option);
+ int FormatFPURegister(Instruction* instr, const char* option);
int FormatOption(Instruction* instr, const char* option);
void Format(Instruction* instr, const char* format);
void Unknown(Instruction* instr);
@@ -166,84 +164,100 @@ void Decoder::PrintRegister(int reg) {
void Decoder::PrintRs(Instruction* instr) {
- int reg = instr->RsField();
+ int reg = instr->RsValue();
PrintRegister(reg);
}
void Decoder::PrintRt(Instruction* instr) {
- int reg = instr->RtField();
+ int reg = instr->RtValue();
PrintRegister(reg);
}
void Decoder::PrintRd(Instruction* instr) {
- int reg = instr->RdField();
+ int reg = instr->RdValue();
PrintRegister(reg);
}
-// Print the Cregister name according to the active name converter.
-void Decoder::PrintCRegister(int creg) {
- Print(converter_.NameOfXMMRegister(creg));
+// Print the FPUregister name according to the active name converter.
+void Decoder::PrintFPURegister(int freg) {
+ Print(converter_.NameOfXMMRegister(freg));
}
void Decoder::PrintFs(Instruction* instr) {
- int creg = instr->RsField();
- PrintCRegister(creg);
+ int freg = instr->RsValue();
+ PrintFPURegister(freg);
}
void Decoder::PrintFt(Instruction* instr) {
- int creg = instr->RtField();
- PrintCRegister(creg);
+ int freg = instr->RtValue();
+ PrintFPURegister(freg);
}
void Decoder::PrintFd(Instruction* instr) {
- int creg = instr->RdField();
- PrintCRegister(creg);
+ int freg = instr->RdValue();
+ PrintFPURegister(freg);
}
// Print the integer value of the sa field.
void Decoder::PrintSa(Instruction* instr) {
- int sa = instr->SaField();
- out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
- "%d", sa);
+ int sa = instr->SaValue();
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
+}
+
+
+// Print the integer value of the rd field, (when it is not used as reg).
+void Decoder::PrintSd(Instruction* instr) {
+ int sd = instr->RdValue();
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sd);
+}
+
+
+// Print the integer value of the cc field for the bc1t/f instructions.
+void Decoder::PrintBc(Instruction* instr) {
+ int cc = instr->FBccValue();
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", cc);
+}
+
+
+// Print the integer value of the cc field for the FP compare instructions.
+void Decoder::PrintCc(Instruction* instr) {
+ int cc = instr->FCccValue();
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
}
// Print 16-bit unsigned immediate value.
void Decoder::PrintUImm16(Instruction* instr) {
- int32_t imm = instr->Imm16Field();
- out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
- "%u", imm);
+ int32_t imm = instr->Imm16Value();
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
}
// Print 16-bit signed immediate value.
void Decoder::PrintSImm16(Instruction* instr) {
- int32_t imm = ((instr->Imm16Field())<<16)>>16;
- out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
- "%d", imm);
+ int32_t imm = ((instr->Imm16Value())<<16)>>16;
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
}
// Print 16-bit hexa immediate value.
void Decoder::PrintXImm16(Instruction* instr) {
- int32_t imm = instr->Imm16Field();
- out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
- "0x%x", imm);
+ int32_t imm = instr->Imm16Value();
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
// Print 26-bit immediate value.
void Decoder::PrintImm26(Instruction* instr) {
- int32_t imm = instr->Imm26Field();
- out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
- "%d", imm);
+ int32_t imm = instr->Imm26Value();
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
}
@@ -254,8 +268,8 @@ void Decoder::PrintCode(Instruction* instr) {
switch (instr->FunctionFieldRaw()) {
case BREAK: {
int32_t code = instr->Bits(25, 6);
- out_buffer_pos_ +=
- v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%05x", code);
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+ "0x%05x (%d)", code, code);
break;
}
case TGE:
@@ -266,7 +280,7 @@ void Decoder::PrintCode(Instruction* instr) {
case TNE: {
int32_t code = instr->Bits(15, 6);
out_buffer_pos_ +=
- v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
+ OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
break;
}
default: // Not a break or trap instruction.
@@ -285,15 +299,15 @@ void Decoder::PrintInstructionName(Instruction* instr) {
int Decoder::FormatRegister(Instruction* instr, const char* format) {
ASSERT(format[0] == 'r');
if (format[1] == 's') { // 'rs: Rs register
- int reg = instr->RsField();
+ int reg = instr->RsValue();
PrintRegister(reg);
return 2;
} else if (format[1] == 't') { // 'rt: rt register
- int reg = instr->RtField();
+ int reg = instr->RtValue();
PrintRegister(reg);
return 2;
} else if (format[1] == 'd') { // 'rd: rd register
- int reg = instr->RdField();
+ int reg = instr->RdValue();
PrintRegister(reg);
return 2;
}
@@ -302,21 +316,21 @@ int Decoder::FormatRegister(Instruction* instr, const char* format) {
}
-// Handle all Cregister based formatting in this function to reduce the
+// Handle all FPUregister based formatting in this function to reduce the
// complexity of FormatOption.
-int Decoder::FormatCRegister(Instruction* instr, const char* format) {
+int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
ASSERT(format[0] == 'f');
if (format[1] == 's') { // 'fs: fs register
- int reg = instr->RsField();
- PrintCRegister(reg);
+ int reg = instr->FsValue();
+ PrintFPURegister(reg);
return 2;
} else if (format[1] == 't') { // 'ft: ft register
- int reg = instr->RtField();
- PrintCRegister(reg);
+ int reg = instr->FtValue();
+ PrintFPURegister(reg);
return 2;
} else if (format[1] == 'd') { // 'fd: fd register
- int reg = instr->RdField();
- PrintCRegister(reg);
+ int reg = instr->FdValue();
+ PrintFPURegister(reg);
return 2;
}
UNREACHABLE();
@@ -359,12 +373,31 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
case 'r': { // 'r: registers
return FormatRegister(instr, format);
}
- case 'f': { // 'f: Cregisters
- return FormatCRegister(instr, format);
+ case 'f': { // 'f: FPUregisters
+ return FormatFPURegister(instr, format);
}
case 's': { // 'sa
- ASSERT(STRING_STARTS_WITH(format, "sa"));
- PrintSa(instr);
+ switch (format[1]) {
+ case 'a': {
+ ASSERT(STRING_STARTS_WITH(format, "sa"));
+ PrintSa(instr);
+ return 2;
+ }
+ case 'd': {
+ ASSERT(STRING_STARTS_WITH(format, "sd"));
+ PrintSd(instr);
+ return 2;
+ }
+ }
+ }
+ case 'b': { // 'bc - Special for bc1 cc field.
+ ASSERT(STRING_STARTS_WITH(format, "bc"));
+ PrintBc(instr);
+ return 2;
+ }
+ case 'C': { // 'Cc - Special for c.xx.d cc field.
+ ASSERT(STRING_STARTS_WITH(format, "Cc"));
+ PrintCc(instr);
return 2;
}
};
@@ -401,45 +434,160 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
switch (instr->OpcodeFieldRaw()) {
case COP1: // Coprocessor instructions
switch (instr->RsFieldRaw()) {
- case BC1: // branch on coprocessor condition
+ case BC1: // bc1 handled in DecodeTypeImmediate.
UNREACHABLE();
break;
case MFC1:
- Format(instr, "mfc1 'rt, 'fs");
+ Format(instr, "mfc1 'rt, 'fs");
break;
case MFHC1:
- Format(instr, "mfhc1 rt, 'fs");
+ Format(instr, "mfhc1 'rt, 'fs");
break;
case MTC1:
- Format(instr, "mtc1 'rt, 'fs");
+ Format(instr, "mtc1 'rt, 'fs");
+ break;
+ // These are called "fs" too, although they are not FPU registers.
+ case CTC1:
+ Format(instr, "ctc1 'rt, 'fs");
+ break;
+ case CFC1:
+ Format(instr, "cfc1 'rt, 'fs");
break;
case MTHC1:
- Format(instr, "mthc1 rt, 'fs");
+ Format(instr, "mthc1 'rt, 'fs");
break;
- case S:
case D:
+ switch (instr->FunctionFieldRaw()) {
+ case ADD_D:
+ Format(instr, "add.d 'fd, 'fs, 'ft");
+ break;
+ case SUB_D:
+ Format(instr, "sub.d 'fd, 'fs, 'ft");
+ break;
+ case MUL_D:
+ Format(instr, "mul.d 'fd, 'fs, 'ft");
+ break;
+ case DIV_D:
+ Format(instr, "div.d 'fd, 'fs, 'ft");
+ break;
+ case ABS_D:
+ Format(instr, "abs.d 'fd, 'fs");
+ break;
+ case MOV_D:
+ Format(instr, "mov.d 'fd, 'fs");
+ break;
+ case NEG_D:
+ Format(instr, "neg.d 'fd, 'fs");
+ break;
+ case SQRT_D:
+ Format(instr, "sqrt.d 'fd, 'fs");
+ break;
+ case CVT_W_D:
+ Format(instr, "cvt.w.d 'fd, 'fs");
+ break;
+ case CVT_L_D: {
+ if (mips32r2) {
+ Format(instr, "cvt.l.d 'fd, 'fs");
+ } else {
+ Unknown(instr);
+ }
+ break;
+ }
+ case TRUNC_W_D:
+ Format(instr, "trunc.w.d 'fd, 'fs");
+ break;
+ case TRUNC_L_D: {
+ if (mips32r2) {
+ Format(instr, "trunc.l.d 'fd, 'fs");
+ } else {
+ Unknown(instr);
+ }
+ break;
+ }
+ case ROUND_W_D:
+ Format(instr, "round.w.d 'fd, 'fs");
+ break;
+ case FLOOR_W_D:
+ Format(instr, "floor.w.d 'fd, 'fs");
+ break;
+ case CEIL_W_D:
+ Format(instr, "ceil.w.d 'fd, 'fs");
+ break;
+ case CVT_S_D:
+ Format(instr, "cvt.s.d 'fd, 'fs");
+ break;
+ case C_F_D:
+ Format(instr, "c.f.d 'fs, 'ft, 'Cc");
+ break;
+ case C_UN_D:
+ Format(instr, "c.un.d 'fs, 'ft, 'Cc");
+ break;
+ case C_EQ_D:
+ Format(instr, "c.eq.d 'fs, 'ft, 'Cc");
+ break;
+ case C_UEQ_D:
+ Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
+ break;
+ case C_OLT_D:
+ Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
+ break;
+ case C_ULT_D:
+ Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
+ break;
+ case C_OLE_D:
+ Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
+ break;
+ case C_ULE_D:
+ Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
+ break;
+ default:
+ Format(instr, "unknown.cop1.d");
+ break;
+ }
+ break;
+ case S:
UNIMPLEMENTED_MIPS();
break;
case W:
switch (instr->FunctionFieldRaw()) {
- case CVT_S_W:
- UNIMPLEMENTED_MIPS();
+ case CVT_S_W: // Convert word to float (single).
+ Format(instr, "cvt.s.w 'fd, 'fs");
break;
case CVT_D_W: // Convert word to double.
- Format(instr, "cvt.d.w 'fd, 'fs");
+ Format(instr, "cvt.d.w 'fd, 'fs");
break;
default:
UNREACHABLE();
- };
+ }
break;
case L:
+ switch (instr->FunctionFieldRaw()) {
+ case CVT_D_L: {
+ if (mips32r2) {
+ Format(instr, "cvt.d.l 'fd, 'fs");
+ } else {
+ Unknown(instr);
+ }
+ break;
+ }
+ case CVT_S_L: {
+ if (mips32r2) {
+ Format(instr, "cvt.s.l 'fd, 'fs");
+ } else {
+ Unknown(instr);
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ break;
case PS:
UNIMPLEMENTED_MIPS();
break;
- break;
default:
UNREACHABLE();
- };
+ }
break;
case SPECIAL:
switch (instr->FunctionFieldRaw()) {
@@ -456,7 +604,15 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
Format(instr, "sll 'rd, 'rt, 'sa");
break;
case SRL:
- Format(instr, "srl 'rd, 'rt, 'sa");
+ if (instr->RsValue() == 0) {
+ Format(instr, "srl 'rd, 'rt, 'sa");
+ } else {
+ if (mips32r2) {
+ Format(instr, "rotr 'rd, 'rt, 'sa");
+ } else {
+ Unknown(instr);
+ }
+ }
break;
case SRA:
Format(instr, "sra 'rd, 'rt, 'sa");
@@ -465,7 +621,15 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
Format(instr, "sllv 'rd, 'rt, 'rs");
break;
case SRLV:
- Format(instr, "srlv 'rd, 'rt, 'rs");
+ if (instr->SaValue() == 0) {
+ Format(instr, "srlv 'rd, 'rt, 'rs");
+ } else {
+ if (mips32r2) {
+ Format(instr, "rotrv 'rd, 'rt, 'rs");
+ } else {
+ Unknown(instr);
+ }
+ }
break;
case SRAV:
Format(instr, "srav 'rd, 'rt, 'rs");
@@ -504,9 +668,9 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
Format(instr, "and 'rd, 'rs, 'rt");
break;
case OR:
- if (0 == instr->RsField()) {
+ if (0 == instr->RsValue()) {
Format(instr, "mov 'rd, 'rt");
- } else if (0 == instr->RtField()) {
+ } else if (0 == instr->RtValue()) {
Format(instr, "mov 'rd, 'rs");
} else {
Format(instr, "or 'rd, 'rs, 'rt");
@@ -545,27 +709,79 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
case TNE:
Format(instr, "tne 'rs, 'rt, code: 'code");
break;
+ case MOVZ:
+ Format(instr, "movz 'rd, 'rs, 'rt");
+ break;
+ case MOVN:
+ Format(instr, "movn 'rd, 'rs, 'rt");
+ break;
+ case MOVCI:
+ if (instr->Bit(16)) {
+ Format(instr, "movt 'rd, 'rs, 'Cc");
+ } else {
+ Format(instr, "movf 'rd, 'rs, 'Cc");
+ }
+ break;
default:
UNREACHABLE();
- };
+ }
break;
case SPECIAL2:
switch (instr->FunctionFieldRaw()) {
case MUL:
+ Format(instr, "mul 'rd, 'rs, 'rt");
+ break;
+ case CLZ:
+ Format(instr, "clz 'rd, 'rs");
break;
default:
UNREACHABLE();
- };
+ }
+ break;
+ case SPECIAL3:
+ switch (instr->FunctionFieldRaw()) {
+ case INS: {
+ if (mips32r2) {
+ Format(instr, "ins 'rt, 'rs, 'sd, 'sa");
+ } else {
+ Unknown(instr);
+ }
+ break;
+ }
+ case EXT: {
+ if (mips32r2) {
+ Format(instr, "ext 'rt, 'rs, 'sd, 'sa");
+ } else {
+ Unknown(instr);
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
break;
default:
UNREACHABLE();
- };
+ }
}
void Decoder::DecodeTypeImmediate(Instruction* instr) {
switch (instr->OpcodeFieldRaw()) {
// ------------- REGIMM class.
+ case COP1:
+ switch (instr->RsFieldRaw()) {
+ case BC1:
+ if (instr->FBtrueValue()) {
+ Format(instr, "bc1t 'bc, 'imm16u");
+ } else {
+ Format(instr, "bc1f 'bc, 'imm16u");
+ }
+ break;
+ default:
+ UNREACHABLE();
+ };
+ break; // Case COP1.
case REGIMM:
switch (instr->RtFieldRaw()) {
case BLTZ:
@@ -582,8 +798,8 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
break;
default:
UNREACHABLE();
- };
- break; // case REGIMM
+ }
+ break; // Case REGIMM.
// ------------- Branch instructions.
case BEQ:
Format(instr, "beq 'rs, 'rt, 'imm16u");
@@ -626,18 +842,39 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
case LB:
Format(instr, "lb 'rt, 'imm16s('rs)");
break;
+ case LH:
+ Format(instr, "lh 'rt, 'imm16s('rs)");
+ break;
+ case LWL:
+ Format(instr, "lwl 'rt, 'imm16s('rs)");
+ break;
case LW:
Format(instr, "lw 'rt, 'imm16s('rs)");
break;
case LBU:
Format(instr, "lbu 'rt, 'imm16s('rs)");
break;
+ case LHU:
+ Format(instr, "lhu 'rt, 'imm16s('rs)");
+ break;
+ case LWR:
+ Format(instr, "lwr 'rt, 'imm16s('rs)");
+ break;
case SB:
Format(instr, "sb 'rt, 'imm16s('rs)");
break;
+ case SH:
+ Format(instr, "sh 'rt, 'imm16s('rs)");
+ break;
+ case SWL:
+ Format(instr, "swl 'rt, 'imm16s('rs)");
+ break;
case SW:
Format(instr, "sw 'rt, 'imm16s('rs)");
break;
+ case SWR:
+ Format(instr, "swr 'rt, 'imm16s('rs)");
+ break;
case LWC1:
Format(instr, "lwc1 'ft, 'imm16s('rs)");
break;
@@ -645,10 +882,10 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
Format(instr, "ldc1 'ft, 'imm16s('rs)");
break;
case SWC1:
- Format(instr, "swc1 'rt, 'imm16s('fs)");
+ Format(instr, "swc1 'ft, 'imm16s('rs)");
break;
case SDC1:
- Format(instr, "sdc1 'rt, 'imm16s('fs)");
+ Format(instr, "sdc1 'ft, 'imm16s('rs)");
break;
default:
UNREACHABLE();
@@ -675,7 +912,7 @@ void Decoder::DecodeTypeJump(Instruction* instr) {
int Decoder::InstructionDecode(byte_* instr_ptr) {
Instruction* instr = Instruction::At(instr_ptr);
// Print raw instruction bytes.
- out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"%08x ",
instr->InstructionBits());
switch (instr->InstructionType()) {
@@ -695,11 +932,11 @@ int Decoder::InstructionDecode(byte_* instr_ptr) {
UNSUPPORTED_MIPS();
}
}
- return Instruction::kInstructionSize;
+ return Instruction::kInstrSize;
}
-} } // namespace assembler::mips
+} } // namespace v8::internal
@@ -707,13 +944,11 @@ int Decoder::InstructionDecode(byte_* instr_ptr) {
namespace disasm {
-namespace v8i = v8::internal;
-
+using v8::internal::byte_;
const char* NameConverter::NameOfAddress(byte_* addr) const {
- static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
- v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
- return tmp_buffer.start();
+ v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
+ return tmp_buffer_.start();
}
@@ -723,12 +958,12 @@ const char* NameConverter::NameOfConstant(byte_* addr) const {
const char* NameConverter::NameOfCPURegister(int reg) const {
- return assembler::mips::Registers::Name(reg);
+ return v8::internal::Registers::Name(reg);
}
const char* NameConverter::NameOfXMMRegister(int reg) const {
- return assembler::mips::FPURegister::Name(reg);
+ return v8::internal::FPURegisters::Name(reg);
}
@@ -756,13 +991,13 @@ Disassembler::~Disassembler() {}
int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
byte_* instruction) {
- assembler::mips::Decoder d(converter_, buffer);
+ v8::internal::Decoder d(converter_, buffer);
return d.InstructionDecode(instruction);
}
+// The MIPS assembler does not currently use constant pools.
int Disassembler::ConstantPoolSizeAt(byte_* instruction) {
- UNIMPLEMENTED_MIPS();
return -1;
}
@@ -780,6 +1015,7 @@ void Disassembler::Disassemble(FILE* f, byte_* begin, byte_* end) {
}
}
+
#undef UNSUPPORTED
} // namespace disasm
diff --git a/src/mips/frames-mips.cc b/src/mips/frames-mips.cc
index d6305629..e2e0c919 100644
--- a/src/mips/frames-mips.cc
+++ b/src/mips/frames-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -37,57 +37,9 @@ namespace v8 {
namespace internal {
-StackFrame::Type StackFrame::ComputeType(State* state) {
- ASSERT(state->fp != NULL);
- if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
- return ARGUMENTS_ADAPTOR;
- }
- // The marker and function offsets overlap. If the marker isn't a
- // smi then the frame is a JavaScript frame -- and the marker is
- // really the function.
- const int offset = StandardFrameConstants::kMarkerOffset;
- Object* marker = Memory::Object_at(state->fp + offset);
- if (!marker->IsSmi()) return JAVA_SCRIPT;
- return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
-}
-
-
Address ExitFrame::ComputeStackPointer(Address fp) {
- Address sp = fp + ExitFrameConstants::kSPDisplacement;
- const int offset = ExitFrameConstants::kCodeOffset;
- Object* code = Memory::Object_at(fp + offset);
- bool is_debug_exit = code->IsSmi();
- if (is_debug_exit) {
- sp -= kNumJSCallerSaved * kPointerSize;
- }
- return sp;
-}
-
-
-void ExitFrame::Iterate(ObjectVisitor* v) const {
- // Do nothing
-}
-
-
-int JavaScriptFrame::GetProvidedParametersCount() const {
- return ComputeParametersCount();
-}
-
-
-Address JavaScriptFrame::GetCallerStackPointer() const {
UNIMPLEMENTED_MIPS();
- return static_cast<Address>(NULL); // UNIMPLEMENTED RETURN
-}
-
-
-Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
- UNIMPLEMENTED_MIPS();
- return static_cast<Address>(NULL); // UNIMPLEMENTED RETURN
-}
-
-
-Address InternalFrame::GetCallerStackPointer() const {
- return fp() + StandardFrameConstants::kCallerSPOffset;
+ return fp;
}
diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h
index 06e9979c..64414703 100644
--- a/src/mips/frames-mips.h
+++ b/src/mips/frames-mips.h
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -40,16 +40,17 @@ namespace internal {
static const int kNumRegs = 32;
static const RegList kJSCallerSaved =
+ 1 << 2 | // v0
1 << 4 | // a0
1 << 5 | // a1
1 << 6 | // a2
1 << 7; // a3
-static const int kNumJSCallerSaved = 4;
+static const int kNumJSCallerSaved = 5;
// Return the code of the n-th caller-saved register available to JavaScript
-// e.g. JSCallerSavedReg(0) returns r0.code() == 0.
+// e.g. JSCallerSavedReg(0) returns a0.code() == 4.
int JSCallerSavedCode(int n);
@@ -64,6 +65,18 @@ static const RegList kCalleeSaved =
static const int kNumCalleeSaved = 11;
+// Number of registers for which space is reserved in safepoints. Must be a
+// multiple of 8.
+// TODO(mips): Only 8 registers may actually be sufficient. Revisit.
+static const int kNumSafepointRegisters = 16;
+
+// Define the list of registers actually saved at safepoints.
+// Note that the number of saved registers may be smaller than the reserved
+// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
+static const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
+static const int kNumSafepointSavedRegisters =
+ kNumJSCallerSaved + kNumCalleeSaved;
+
typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
@@ -88,15 +101,14 @@ class EntryFrameConstants : public AllStatic {
class ExitFrameConstants : public AllStatic {
public:
- // Exit frames have a debug marker on the stack.
- static const int kSPDisplacement = -1 * kPointerSize;
-
- // The debug marker is just above the frame pointer.
static const int kDebugMarkOffset = -1 * kPointerSize;
// Must be the same as kDebugMarkOffset. Alias introduced when upgrading.
static const int kCodeOffset = -1 * kPointerSize;
+ static const int kSPOffset = -1 * kPointerSize;
- static const int kSavedRegistersOffset = 0 * kPointerSize;
+ // TODO(mips): Use a patched sp value on the stack instead.
+ // A marker of 0 indicates that double registers are saved.
+ static const int kMarkerOffset = -2 * kPointerSize;
// The caller fields are below the frame pointer on the stack.
static const int kCallerFPOffset = +0 * kPointerSize;
@@ -126,6 +138,8 @@ class StandardFrameConstants : public AllStatic {
static const int kCArgsSlotsSize = 4 * kPointerSize;
// JS argument slots size.
static const int kJSArgsSlotsSize = 0 * kPointerSize;
+ // Assembly builtins argument slots size.
+ static const int kBArgsSlotsSize = 0 * kPointerSize;
};
@@ -159,6 +173,7 @@ inline Object* JavaScriptFrame::function_slot_object() const {
return Memory::Object_at(fp() + offset);
}
+
} } // namespace v8::internal
#endif
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 17ee531a..87507ff1 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -29,18 +29,55 @@
#if defined(V8_TARGET_ARCH_MIPS)
+// Note on Mips implementation:
+//
+// The result_register() for mips is the 'v0' register, which is defined
+// by the ABI to contain function return values. However, the first
+// parameter to a function is defined to be 'a0'. So there are many
+// places where we have to move a previous result in v0 to a0 for the
+// next call: mov(a0, v0). This is not needed on the other architectures.
+
+#include "code-stubs.h"
#include "codegen-inl.h"
#include "compiler.h"
#include "debug.h"
#include "full-codegen.h"
#include "parser.h"
+#include "scopes.h"
+#include "stub-cache.h"
+
+#include "mips/code-stubs-mips.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm_)
-void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) {
+// Generate code for a JS function. On entry to the function the receiver
+// and arguments have been pushed on the stack left to right. The actual
+// argument count matches the formal parameter count expected by the
+// function.
+//
+// The live registers are:
+// o a1: the JS function object being called (ie, ourselves)
+// o cp: our context
+// o fp: our caller's frame pointer
+// o sp: stack pointer
+// o ra: return address
+//
+// The function builds a JS frame. Please see JavaScriptFrameConstants in
+// frames-mips.h for its layout.
+void FullCodeGenerator::Generate(CompilationInfo* info) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::ClearAccumulator() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
UNIMPLEMENTED_MIPS();
}
@@ -50,47 +87,165 @@ void FullCodeGenerator::EmitReturnSequence() {
}
-void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
+void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Heap::RootListIndex index) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(
+ Heap::RootListIndex index) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Handle<Object> lit) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EffectContext::DropAndPlug(int count,
+ Register reg) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
+ int count,
+ Register reg) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
+ Register reg) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::TestContext::DropAndPlug(int count,
+ Register reg) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
+ Label* materialize_false) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Label* materialize_true,
+ Label* materialize_false) const {
UNIMPLEMENTED_MIPS();
}
-void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
+void FullCodeGenerator::StackValueContext::Plug(
+ Label* materialize_true,
+ Label* materialize_false) const {
UNIMPLEMENTED_MIPS();
}
-void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
+
+void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
+ Label* materialize_false) const {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(bool flag) const {
UNIMPLEMENTED_MIPS();
}
-void FullCodeGenerator::ApplyTOS(Expression::Context context) {
+void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
UNIMPLEMENTED_MIPS();
}
-void FullCodeGenerator::DropAndApply(int count,
- Expression::Context context,
- Register reg) {
+void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
UNIMPLEMENTED_MIPS();
}
-void FullCodeGenerator::Apply(Expression::Context context,
- Label* materialize_true,
- Label* materialize_false) {
+void FullCodeGenerator::TestContext::Plug(bool flag) const {
UNIMPLEMENTED_MIPS();
}
-void FullCodeGenerator::DoTest(Expression::Context context) {
+void FullCodeGenerator::DoTest(Label* if_true,
+ Label* if_false,
+ Label* fall_through) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// Original prototype for mips, needs arch-indep change. Leave out for now.
+// void FullCodeGenerator::Split(Condition cc,
+// Register lhs,
+// const Operand& rhs,
+// Label* if_true,
+// Label* if_false,
+// Label* fall_through) {
+void FullCodeGenerator::Split(Condition cc,
+ Label* if_true,
+ Label* if_false,
+ Label* fall_through) {
UNIMPLEMENTED_MIPS();
}
MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
UNIMPLEMENTED_MIPS();
- return MemOperand(zero_reg, 0); // UNIMPLEMENTED RETURN
+ return MemOperand(zero_reg, 0);
}
@@ -99,6 +254,14 @@ void FullCodeGenerator::Move(Register destination, Slot* source) {
}
+void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
+ bool should_normalize,
+ Label* if_true,
+ Label* if_false) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void FullCodeGenerator::Move(Slot* dst,
Register src,
Register scratch1,
@@ -107,6 +270,13 @@ void FullCodeGenerator::Move(Slot* dst,
}
+void FullCodeGenerator::EmitDeclaration(Variable* variable,
+ Variable::Mode mode,
+ FunctionLiteral* function) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
UNIMPLEMENTED_MIPS();
}
@@ -117,7 +287,18 @@ void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
}
-void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
+void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
+ bool pretenure) {
UNIMPLEMENTED_MIPS();
}
@@ -127,8 +308,32 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
}
-void FullCodeGenerator::EmitVariableLoad(Variable* var,
- Expression::Context context) {
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
+ Slot* slot,
+ Label* slow) {
+ UNIMPLEMENTED_MIPS();
+ return MemOperand(zero_reg, 0);
+}
+
+
+void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
+ Slot* slot,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
+ Slot* slot,
+ TypeofState typeof_state,
+ Label* slow) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitVariableLoad(Variable* var) {
UNIMPLEMENTED_MIPS();
}
@@ -163,14 +368,28 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
}
+void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
+ Token::Value op,
+ OverwriteMode mode,
+ Expression* left,
+ Expression* right) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void FullCodeGenerator::EmitBinaryOp(Token::Value op,
- Expression::Context context) {
+ OverwriteMode mode) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
UNIMPLEMENTED_MIPS();
}
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
- Expression::Context context) {
+ Token::Value op) {
UNIMPLEMENTED_MIPS();
}
@@ -189,13 +408,21 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
UNIMPLEMENTED_MIPS();
}
+
void FullCodeGenerator::EmitCallWithIC(Call* expr,
- Handle<Object> ignored,
+ Handle<Object> name,
RelocInfo::Mode mode) {
UNIMPLEMENTED_MIPS();
}
+void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
+ Expression* key,
+ RelocInfo::Mode mode) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void FullCodeGenerator::EmitCallWithStub(Call* expr) {
UNIMPLEMENTED_MIPS();
}
@@ -211,6 +438,202 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
}
+void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
+ ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
UNIMPLEMENTED_MIPS();
}
@@ -226,25 +649,52 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
-void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
+void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
UNIMPLEMENTED_MIPS();
}
+bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
+ Expression* left,
+ Expression* right,
+ Label* if_true,
+ Label* if_false,
+ Label* fall_through) {
+ UNIMPLEMENTED_MIPS();
+ return false;
+}
+
+
void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
UNIMPLEMENTED_MIPS();
}
+void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
UNIMPLEMENTED_MIPS();
}
-Register FullCodeGenerator::result_register() { return v0; }
+Register FullCodeGenerator::result_register() {
+ UNIMPLEMENTED_MIPS();
+ return v0;
+}
-Register FullCodeGenerator::context_register() { return cp; }
+Register FullCodeGenerator::context_register() {
+ UNIMPLEMENTED_MIPS();
+ return cp;
+}
+
+
+void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
+ UNIMPLEMENTED_MIPS();
+}
void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index e5c2ad80..fa8a7bb7 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -32,6 +32,7 @@
#if defined(V8_TARGET_ARCH_MIPS)
#include "codegen-inl.h"
+#include "code-stubs.h"
#include "ic-inl.h"
#include "runtime.h"
#include "stub-cache.h"
@@ -52,7 +53,7 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
}
-void LoadIC::GenerateStringLength(MacroAssembler* masm) {
+void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
UNIMPLEMENTED_MIPS();
}
@@ -65,60 +66,37 @@ void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
// Defined in ic.cc.
Object* CallIC_Miss(Arguments args);
-void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
+
+void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
UNIMPLEMENTED_MIPS();
}
-void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
+void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
UNIMPLEMENTED_MIPS();
}
-void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
- UNIMPLEMENTED_MIPS();
- // Registers:
- // a2: name
- // ra: return address
-
- // Get the receiver of the function from the stack.
- __ lw(a3, MemOperand(sp, argc*kPointerSize));
- __ EnterInternalFrame();
-
- // Push the receiver and the name of the function.
- __ MultiPush(a2.bit() | a3.bit());
+void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
+ UNIMPLEMENTED_MIPS();
+}
- // Call the entry.
- __ li(a0, Operand(2));
- __ li(a1, Operand(ExternalReference(IC_Utility(kCallIC_Miss))));
- CEntryStub stub(1);
- __ CallStub(&stub);
+void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
+ UNIMPLEMENTED_MIPS();
+}
- // Move result to r1 and leave the internal frame.
- __ mov(a1, v0);
- __ LeaveInternalFrame();
- // Check if the receiver is a global object of some sort.
- Label invoke, global;
- __ lw(a2, MemOperand(sp, argc * kPointerSize));
- __ andi(t0, a2, kSmiTagMask);
- __ Branch(eq, &invoke, t0, Operand(zero_reg));
- __ GetObjectType(a2, a3, a3);
- __ Branch(eq, &global, a3, Operand(JS_GLOBAL_OBJECT_TYPE));
- __ Branch(ne, &invoke, a3, Operand(JS_BUILTINS_OBJECT_TYPE));
+void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
+ UNIMPLEMENTED_MIPS();
+}
- // Patch the receiver on the stack.
- __ bind(&global);
- __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset));
- __ sw(a2, MemOperand(sp, argc * kPointerSize));
- // Invoke the function.
- ParameterCount actual(argc);
- __ bind(&invoke);
- __ InvokeFunction(a1, actual, JUMP_FUNCTION);
+void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
+ UNIMPLEMENTED_MIPS();
}
+
// Defined in ic.cc.
Object* LoadIC_Miss(Arguments args);
@@ -137,19 +115,35 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
}
-void LoadIC::ClearInlinedVersion(Address address) {}
bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
+ UNIMPLEMENTED_MIPS();
+ return false;
+}
+
+
+bool LoadIC::PatchInlinedContextualLoad(Address address,
+ Object* map,
+ Object* cell,
+ bool is_dont_delete) {
+ UNIMPLEMENTED_MIPS();
return false;
}
-void KeyedLoadIC::ClearInlinedVersion(Address address) {}
+
+bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
+ UNIMPLEMENTED_MIPS();
+ return false;
+}
+
+
bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
+ UNIMPLEMENTED_MIPS();
return false;
}
-void KeyedStoreIC::ClearInlinedVersion(Address address) {}
-void KeyedStoreIC::RestoreInlinedVersion(Address address) {}
+
bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
+ UNIMPLEMENTED_MIPS();
return false;
}
@@ -162,6 +156,11 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
}
+void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
UNIMPLEMENTED_MIPS();
}
@@ -172,7 +171,14 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
}
-void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
+void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
+ StrictModeFlag strict_mode) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
+ StrictModeFlag strict_mode) {
UNIMPLEMENTED_MIPS();
}
@@ -187,7 +193,8 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
}
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
+void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
+ StrictModeFlag strict_mode) {
UNIMPLEMENTED_MIPS();
}
@@ -201,8 +208,37 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
UNIMPLEMENTED_MIPS();
}
+
+void StoreIC::GenerateNormal(MacroAssembler* masm) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
+ StrictModeFlag strict_mode) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
#undef __
+
+Condition CompareIC::ComputeCondition(Token::Value op) {
+ UNIMPLEMENTED_MIPS();
+ return kNoCondition;
+}
+
+
+void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void PatchInlinedSmiCode(Address address) {
+ // Currently there is no smi inlining in the MIPS full code generator.
+}
+
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/mips/jump-target-mips.cc b/src/mips/jump-target-mips.cc
index 408f75e7..bd6d60ba 100644
--- a/src/mips/jump-target-mips.cc
+++ b/src/mips/jump-target-mips.cc
@@ -43,41 +43,19 @@ namespace internal {
#define __ ACCESS_MASM(cgen()->masm())
+// BRANCH_ARGS_CHECK checks that conditional jump arguments are correct.
+#define BRANCH_ARGS_CHECK(cond, rs, rt) ASSERT( \
+ (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \
+ (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg))))
+
+
void JumpTarget::DoJump() {
- ASSERT(cgen()->has_valid_frame());
- // Live non-frame registers are not allowed at unconditional jumps
- // because we have no way of invalidating the corresponding results
- // which are still live in the C++ code.
- ASSERT(cgen()->HasValidEntryRegisters());
-
- if (is_bound()) {
- // Backward jump. There already a frame expectation at the target.
- ASSERT(direction_ == BIDIRECTIONAL);
- cgen()->frame()->MergeTo(entry_frame_);
- cgen()->DeleteFrame();
- } else {
- // Use the current frame as the expected one at the target if necessary.
- if (entry_frame_ == NULL) {
- entry_frame_ = cgen()->frame();
- RegisterFile empty;
- cgen()->SetFrame(NULL, &empty);
- } else {
- cgen()->frame()->MergeTo(entry_frame_);
- cgen()->DeleteFrame();
- }
-
- // The predicate is_linked() should be made true. Its implementation
- // detects the presence of a frame pointer in the reaching_frames_ list.
- if (!is_linked()) {
- reaching_frames_.Add(NULL);
- ASSERT(is_linked());
- }
- }
- __ b(&entry_label_);
- __ nop(); // Branch delay slot nop.
+ UNIMPLEMENTED_MIPS();
}
-
+// Original prototype for mips, needs arch-indep change. Leave out for now.
+// void JumpTarget::DoBranch(Condition cc, Hint ignored,
+// Register src1, const Operand& src2) {
void JumpTarget::DoBranch(Condition cc, Hint ignored) {
UNIMPLEMENTED_MIPS();
}
@@ -89,85 +67,12 @@ void JumpTarget::Call() {
void JumpTarget::DoBind() {
- ASSERT(!is_bound());
-
- // Live non-frame registers are not allowed at the start of a basic
- // block.
- ASSERT(!cgen()->has_valid_frame() || cgen()->HasValidEntryRegisters());
-
- if (cgen()->has_valid_frame()) {
- // If there is a current frame we can use it on the fall through.
- if (entry_frame_ == NULL) {
- entry_frame_ = new VirtualFrame(cgen()->frame());
- } else {
- ASSERT(cgen()->frame()->Equals(entry_frame_));
- }
- } else {
- // If there is no current frame we must have an entry frame which we can
- // copy.
- ASSERT(entry_frame_ != NULL);
- RegisterFile empty;
- cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
- }
-
- // The predicate is_linked() should be made false. Its implementation
- // detects the presence (or absence) of frame pointers in the
- // reaching_frames_ list. If we inserted a bogus frame to make
- // is_linked() true, remove it now.
- if (is_linked()) {
- reaching_frames_.Clear();
- }
-
- __ bind(&entry_label_);
-}
-
-
-void BreakTarget::Jump() {
- // On ARM we do not currently emit merge code for jumps, so we need to do
- // it explicitly here. The only merging necessary is to drop extra
- // statement state from the stack.
- ASSERT(cgen()->has_valid_frame());
- int count = cgen()->frame()->height() - expected_height_;
- cgen()->frame()->Drop(count);
- DoJump();
-}
-
-
-void BreakTarget::Jump(Result* arg) {
- UNIMPLEMENTED_MIPS();
-}
-
-
-void BreakTarget::Bind() {
-#ifdef DEBUG
- // All the forward-reaching frames should have been adjusted at the
- // jumps to this target.
- for (int i = 0; i < reaching_frames_.length(); i++) {
- ASSERT(reaching_frames_[i] == NULL ||
- reaching_frames_[i]->height() == expected_height_);
- }
-#endif
- // Drop leftover statement state from the frame before merging, even
- // on the fall through. This is so we can bind the return target
- // with state on the frame.
- if (cgen()->has_valid_frame()) {
- int count = cgen()->frame()->height() - expected_height_;
- // On ARM we do not currently emit merge code at binding sites, so we need
- // to do it explicitly here. The only merging necessary is to drop extra
- // statement state from the stack.
- cgen()->frame()->Drop(count);
- }
-
- DoBind();
-}
-
-
-void BreakTarget::Bind(Result* arg) {
UNIMPLEMENTED_MIPS();
}
#undef __
+#undef BRANCH_ARGS_CHECK
} } // namespace v8::internal
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
new file mode 100644
index 00000000..345d912c
--- /dev/null
+++ b/src/mips/lithium-codegen-mips.h
@@ -0,0 +1,65 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_MIPS_LITHIUM_CODEGEN_MIPS_H_
+#define V8_MIPS_LITHIUM_CODEGEN_MIPS_H_
+
+#include "mips/lithium-mips.h"
+
+#include "deoptimizer.h"
+#include "safepoint-table.h"
+#include "scopes.h"
+
+// Note: this file was taken from the X64 version. ARM has a partially working
+// lithium implementation, but for now it is not ported to mips.
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class LDeferredCode;
+
+class LCodeGen BASE_EMBEDDED {
+ public:
+ LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) { }
+
+ // Try to generate code for the entire chunk, but it may fail if the
+ // chunk contains constructs we cannot handle. Returns true if the
+ // code generation attempt succeeded.
+ bool GenerateCode() {
+ UNIMPLEMENTED();
+ return false;
+ }
+
+ // Finish the code by setting stack height, safepoint, and bailout
+ // information on it.
+ void FinishCode(Handle<Code> code) { UNIMPLEMENTED(); }
+};
+
+} } // namespace v8::internal
+
+#endif // V8_MIPS_LITHIUM_CODEGEN_MIPS_H_
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
new file mode 100644
index 00000000..e11dfabb
--- /dev/null
+++ b/src/mips/lithium-mips.h
@@ -0,0 +1,304 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_MIPS_LITHIUM_MIPS_H_
+#define V8_MIPS_LITHIUM_MIPS_H_
+
+#include "hydrogen.h"
+#include "lithium-allocator.h"
+#include "lithium.h"
+#include "safepoint-table.h"
+
+// Note: this file was taken from the X64 version. ARM has a partially working
+// lithium implementation, but for now it is not ported to mips.
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class LCodeGen;
+class LEnvironment;
+class Translation;
+
+class LInstruction: public ZoneObject {
+ public:
+ LInstruction() { }
+ virtual ~LInstruction() { }
+
+ // Predicates should be generated by macro as in lithium-ia32.h.
+ virtual bool IsLabel() const {
+ UNIMPLEMENTED();
+ return false;
+ }
+ virtual bool IsOsrEntry() const {
+ UNIMPLEMENTED();
+ return false;
+ }
+
+ LPointerMap* pointer_map() const {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ bool HasPointerMap() const {
+ UNIMPLEMENTED();
+ return false;
+ }
+
+ void set_environment(LEnvironment* env) { UNIMPLEMENTED(); }
+
+ LEnvironment* environment() const {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ bool HasEnvironment() const {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ virtual void PrintTo(StringStream* stream) const { UNIMPLEMENTED(); }
+
+ virtual bool IsControl() const {
+ UNIMPLEMENTED();
+ return false;
+ }
+
+ void MarkAsCall() { UNIMPLEMENTED(); }
+ void MarkAsSaveDoubles() { UNIMPLEMENTED(); }
+
+ // Interface to the register allocator and iterators.
+ bool IsMarkedAsCall() const {
+ UNIMPLEMENTED();
+ return false;
+ }
+
+ bool IsMarkedAsSaveDoubles() const {
+ UNIMPLEMENTED();
+ return false;
+ }
+
+ virtual bool HasResult() const {
+ UNIMPLEMENTED();
+ return false;
+ }
+
+ virtual LOperand* result() {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ virtual int InputCount() {
+ UNIMPLEMENTED();
+ return 0;
+ }
+
+ virtual LOperand* InputAt(int i) {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ virtual int TempCount() {
+ UNIMPLEMENTED();
+ return 0;
+ }
+
+ virtual LOperand* TempAt(int i) {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ LOperand* FirstInput() {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ LOperand* Output() {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+#ifdef DEBUG
+ void VerifyCall() { UNIMPLEMENTED(); }
+#endif
+};
+
+
+class LGap: public LInstruction {
+ public:
+ explicit LGap(HBasicBlock* block) { }
+
+ HBasicBlock* block() const {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ enum InnerPosition {
+ BEFORE,
+ START,
+ END,
+ AFTER,
+ FIRST_INNER_POSITION = BEFORE,
+ LAST_INNER_POSITION = AFTER
+ };
+
+ LParallelMove* GetOrCreateParallelMove(InnerPosition pos) {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ LParallelMove* GetParallelMove(InnerPosition pos) {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+};
+
+
+class LLabel: public LGap {
+ public:
+ explicit LLabel(HBasicBlock* block) : LGap(block) { }
+};
+
+
+class LOsrEntry: public LInstruction {
+ public:
+ // Function could be generated by a macro as in lithium-ia32.h.
+ static LOsrEntry* cast(LInstruction* instr) {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ LOperand** SpilledRegisterArray() {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+ LOperand** SpilledDoubleRegisterArray() {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ void MarkSpilledRegister(int allocation_index, LOperand* spill_operand) {
+ UNIMPLEMENTED();
+ }
+ void MarkSpilledDoubleRegister(int allocation_index,
+ LOperand* spill_operand) {
+ UNIMPLEMENTED();
+ }
+};
+
+
+class LChunk: public ZoneObject {
+ public:
+ explicit LChunk(CompilationInfo* info, HGraph* graph) { }
+
+ HGraph* graph() const {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ CompilationInfo* info() const { return NULL; }
+
+ const ZoneList<LPointerMap*>* pointer_maps() const {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ LOperand* GetNextSpillSlot(bool double_slot) {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ LConstantOperand* DefineConstantOperand(HConstant* constant) {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ LLabel* GetLabel(int block_id) const {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ const ZoneList<LInstruction*>* instructions() const {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ int GetParameterStackSlot(int index) const {
+ UNIMPLEMENTED();
+ return 0;
+ }
+
+ void AddGapMove(int index, LOperand* from, LOperand* to) { UNIMPLEMENTED(); }
+
+ LGap* GetGapAt(int index) const {
+ UNIMPLEMENTED();
+ return NULL;
+ }
+
+ bool IsGapAt(int index) const {
+ UNIMPLEMENTED();
+ return false;
+ }
+
+ int NearestGapPos(int index) const {
+ UNIMPLEMENTED();
+ return 0;
+ }
+
+ void MarkEmptyBlocks() { UNIMPLEMENTED(); }
+
+#ifdef DEBUG
+ void Verify() { UNIMPLEMENTED(); }
+#endif
+};
+
+
+class LChunkBuilder BASE_EMBEDDED {
+ public:
+ LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator) { }
+
+ // Build the sequence for the graph.
+ LChunk* Build() {
+ UNIMPLEMENTED();
+ return NULL;
+ };
+
+ // Declare methods that deal with the individual node types.
+#define DECLARE_DO(type) LInstruction* Do##type(H##type* node) { \
+ UNIMPLEMENTED(); \
+ return NULL; \
+ }
+ HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
+#undef DECLARE_DO
+
+ DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_MIPS_LITHIUM_MIPS_H_
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index e096028e..bd4ab480 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
+#include <limits.h> // For LONG_MIN, LONG_MAX
#include "v8.h"
@@ -41,68 +41,90 @@ namespace internal {
MacroAssembler::MacroAssembler(void* buffer, int size)
: Assembler(buffer, size),
- unresolved_(0),
generating_stub_(false),
allow_stub_calls_(true),
- code_object_(Heap::undefined_value()) {
+ code_object_(HEAP->undefined_value()) {
}
+// Arguments macros
+#define COND_TYPED_ARGS Condition cond, Register r1, const Operand& r2
+#define COND_ARGS cond, r1, r2
-void MacroAssembler::Jump(Register target, Condition cond,
- Register r1, const Operand& r2) {
- Jump(Operand(target), cond, r1, r2);
+#define REGISTER_TARGET_BODY(Name) \
+void MacroAssembler::Name(Register target, \
+ BranchDelaySlot bd) { \
+ Name(Operand(target), bd); \
+} \
+void MacroAssembler::Name(Register target, COND_TYPED_ARGS, \
+ BranchDelaySlot bd) { \
+ Name(Operand(target), COND_ARGS, bd); \
}
-void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
- Condition cond, Register r1, const Operand& r2) {
- Jump(Operand(target, rmode), cond, r1, r2);
+#define INT_PTR_TARGET_BODY(Name) \
+void MacroAssembler::Name(intptr_t target, RelocInfo::Mode rmode, \
+ BranchDelaySlot bd) { \
+ Name(Operand(target, rmode), bd); \
+} \
+void MacroAssembler::Name(intptr_t target, \
+ RelocInfo::Mode rmode, \
+ COND_TYPED_ARGS, \
+ BranchDelaySlot bd) { \
+ Name(Operand(target, rmode), COND_ARGS, bd); \
}
-void MacroAssembler::Jump(byte* target, RelocInfo::Mode rmode,
- Condition cond, Register r1, const Operand& r2) {
- ASSERT(!RelocInfo::IsCodeTarget(rmode));
- Jump(reinterpret_cast<intptr_t>(target), rmode, cond, r1, r2);
+#define BYTE_PTR_TARGET_BODY(Name) \
+void MacroAssembler::Name(byte* target, RelocInfo::Mode rmode, \
+ BranchDelaySlot bd) { \
+ Name(reinterpret_cast<intptr_t>(target), rmode, bd); \
+} \
+void MacroAssembler::Name(byte* target, \
+ RelocInfo::Mode rmode, \
+ COND_TYPED_ARGS, \
+ BranchDelaySlot bd) { \
+ Name(reinterpret_cast<intptr_t>(target), rmode, COND_ARGS, bd); \
}
-void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
- Condition cond, Register r1, const Operand& r2) {
- ASSERT(RelocInfo::IsCodeTarget(rmode));
- Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
+#define CODE_TARGET_BODY(Name) \
+void MacroAssembler::Name(Handle<Code> target, RelocInfo::Mode rmode, \
+ BranchDelaySlot bd) { \
+ Name(reinterpret_cast<intptr_t>(target.location()), rmode, bd); \
+} \
+void MacroAssembler::Name(Handle<Code> target, \
+ RelocInfo::Mode rmode, \
+ COND_TYPED_ARGS, \
+ BranchDelaySlot bd) { \
+ Name(reinterpret_cast<intptr_t>(target.location()), rmode, COND_ARGS, bd); \
}
-void MacroAssembler::Call(Register target,
- Condition cond, Register r1, const Operand& r2) {
- Call(Operand(target), cond, r1, r2);
-}
+REGISTER_TARGET_BODY(Jump)
+REGISTER_TARGET_BODY(Call)
+INT_PTR_TARGET_BODY(Jump)
+INT_PTR_TARGET_BODY(Call)
+BYTE_PTR_TARGET_BODY(Jump)
+BYTE_PTR_TARGET_BODY(Call)
+CODE_TARGET_BODY(Jump)
+CODE_TARGET_BODY(Call)
+#undef COND_TYPED_ARGS
+#undef COND_ARGS
+#undef REGISTER_TARGET_BODY
+#undef BYTE_PTR_TARGET_BODY
+#undef CODE_TARGET_BODY
-void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
- Condition cond, Register r1, const Operand& r2) {
- Call(Operand(target, rmode), cond, r1, r2);
-}
-
-void MacroAssembler::Call(byte* target, RelocInfo::Mode rmode,
- Condition cond, Register r1, const Operand& r2) {
- ASSERT(!RelocInfo::IsCodeTarget(rmode));
- Call(reinterpret_cast<intptr_t>(target), rmode, cond, r1, r2);
+void MacroAssembler::Ret(BranchDelaySlot bd) {
+ Jump(Operand(ra), bd);
}
-void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
- Condition cond, Register r1, const Operand& r2) {
- ASSERT(RelocInfo::IsCodeTarget(rmode));
- Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond, r1, r2);
-}
-
-
-void MacroAssembler::Ret(Condition cond, Register r1, const Operand& r2) {
- Jump(Operand(ra), cond, r1, r2);
+void MacroAssembler::Ret(Condition cond, Register r1, const Operand& r2,
+ BranchDelaySlot bd) {
+ Jump(Operand(ra), cond, r1, r2, bd);
}
@@ -111,51 +133,248 @@ void MacroAssembler::LoadRoot(Register destination,
lw(destination, MemOperand(s6, index << kPointerSizeLog2));
}
+
void MacroAssembler::LoadRoot(Register destination,
Heap::RootListIndex index,
Condition cond,
Register src1, const Operand& src2) {
- Branch(NegateCondition(cond), 2, src1, src2);
+ Branch(2, NegateCondition(cond), src1, src2);
lw(destination, MemOperand(s6, index << kPointerSizeLog2));
}
-void MacroAssembler::RecordWrite(Register object, Register offset,
+void MacroAssembler::StoreRoot(Register source,
+ Heap::RootListIndex index) {
+ sw(source, MemOperand(s6, index << kPointerSizeLog2));
+}
+
+
+void MacroAssembler::StoreRoot(Register source,
+ Heap::RootListIndex index,
+ Condition cond,
+ Register src1, const Operand& src2) {
+ Branch(2, NegateCondition(cond), src1, src2);
+ sw(source, MemOperand(s6, index << kPointerSizeLog2));
+}
+
+
+void MacroAssembler::RecordWriteHelper(Register object,
+ Register address,
+ Register scratch) {
+ if (FLAG_debug_code) {
+ // Check that the object is not in new space.
+ Label not_in_new_space;
+ InNewSpace(object, scratch, ne, &not_in_new_space);
+ Abort("new-space object passed to RecordWriteHelper");
+ bind(&not_in_new_space);
+ }
+
+ // Calculate page address: Clear bits from 0 to kPageSizeBits.
+ if (mips32r2) {
+ Ins(object, zero_reg, 0, kPageSizeBits);
+ } else {
+ // The Ins macro is slow on r1, so use shifts instead.
+ srl(object, object, kPageSizeBits);
+ sll(object, object, kPageSizeBits);
+ }
+
+ // Calculate region number.
+ Ext(address, address, Page::kRegionSizeLog2,
+ kPageSizeBits - Page::kRegionSizeLog2);
+
+ // Mark region dirty.
+ lw(scratch, MemOperand(object, Page::kDirtyFlagOffset));
+ li(at, Operand(1));
+ sllv(at, at, address);
+ or_(scratch, scratch, at);
+ sw(scratch, MemOperand(object, Page::kDirtyFlagOffset));
+}
+
+
+void MacroAssembler::InNewSpace(Register object,
+ Register scratch,
+ Condition cc,
+ Label* branch) {
+ ASSERT(cc == eq || cc == ne);
+ And(scratch, object, Operand(ExternalReference::new_space_mask(isolate())));
+ Branch(branch, cc, scratch,
+ Operand(ExternalReference::new_space_start(isolate())));
+}
+
+
+// Will clobber 4 registers: object, scratch0, scratch1, at. The
+// register 'object' contains a heap object pointer. The heap object
+// tag is shifted away.
+void MacroAssembler::RecordWrite(Register object,
+ Operand offset,
+ Register scratch0,
+ Register scratch1) {
+ // The compiled code assumes that record write doesn't change the
+ // context register, so we check that none of the clobbered
+ // registers are cp.
+ ASSERT(!object.is(cp) && !scratch0.is(cp) && !scratch1.is(cp));
+
+ Label done;
+
+ // First, test that the object is not in the new space. We cannot set
+ // region marks for new space pages.
+ InNewSpace(object, scratch0, eq, &done);
+
+ // Add offset into the object.
+ Addu(scratch0, object, offset);
+
+ // Record the actual write.
+ RecordWriteHelper(object, scratch0, scratch1);
+
+ bind(&done);
+
+ // Clobber all input registers when running with the debug-code flag
+ // turned on to provoke errors.
+ if (FLAG_debug_code) {
+ li(object, Operand(BitCast<int32_t>(kZapValue)));
+ li(scratch0, Operand(BitCast<int32_t>(kZapValue)));
+ li(scratch1, Operand(BitCast<int32_t>(kZapValue)));
+ }
+}
+
+
+// Will clobber 4 registers: object, address, scratch, ip. The
+// register 'object' contains a heap object pointer. The heap object
+// tag is shifted away.
+void MacroAssembler::RecordWrite(Register object,
+ Register address,
Register scratch) {
- UNIMPLEMENTED_MIPS();
+ // The compiled code assumes that record write doesn't change the
+ // context register, so we check that none of the clobbered
+ // registers are cp.
+ ASSERT(!object.is(cp) && !address.is(cp) && !scratch.is(cp));
+
+ Label done;
+
+ // First, test that the object is not in the new space. We cannot set
+ // region marks for new space pages.
+ InNewSpace(object, scratch, eq, &done);
+
+ // Record the actual write.
+ RecordWriteHelper(object, address, scratch);
+
+ bind(&done);
+
+ // Clobber all input registers when running with the debug-code flag
+ // turned on to provoke errors.
+ if (FLAG_debug_code) {
+ li(object, Operand(BitCast<int32_t>(kZapValue)));
+ li(address, Operand(BitCast<int32_t>(kZapValue)));
+ li(scratch, Operand(BitCast<int32_t>(kZapValue)));
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+// Allocation support
+
+
+void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
+ Register scratch,
+ Label* miss) {
+ Label same_contexts;
+
+ ASSERT(!holder_reg.is(scratch));
+ ASSERT(!holder_reg.is(at));
+ ASSERT(!scratch.is(at));
+
+ // Load current lexical context from the stack frame.
+ lw(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ // In debug mode, make sure the lexical context is set.
+#ifdef DEBUG
+ Check(ne, "we should not have an empty lexical context",
+ scratch, Operand(zero_reg));
+#endif
+
+ // Load the global context of the current context.
+ int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+ lw(scratch, FieldMemOperand(scratch, offset));
+ lw(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+ // Check the context is a global context.
+ if (FLAG_debug_code) {
+ // TODO(119): Avoid push(holder_reg)/pop(holder_reg).
+ Push(holder_reg); // Temporarily save holder on the stack.
+ // Read the first word and compare to the global_context_map.
+ lw(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
+ LoadRoot(at, Heap::kGlobalContextMapRootIndex);
+ Check(eq, "JSGlobalObject::global_context should be a global context.",
+ holder_reg, Operand(at));
+ Pop(holder_reg); // Restore holder.
+ }
+
+ // Check if both contexts are the same.
+ lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset));
+ Branch(&same_contexts, eq, scratch, Operand(at));
+
+ // Check the context is a global context.
+ if (FLAG_debug_code) {
+ // TODO(119): Avoid push(holder_reg)/pop(holder_reg).
+ Push(holder_reg); // Temporarily save holder on the stack.
+ mov(holder_reg, at); // Move at to its holding place.
+ LoadRoot(at, Heap::kNullValueRootIndex);
+ Check(ne, "JSGlobalProxy::context() should not be null.",
+ holder_reg, Operand(at));
+
+ lw(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
+ LoadRoot(at, Heap::kGlobalContextMapRootIndex);
+ Check(eq, "JSGlobalObject::global_context should be a global context.",
+ holder_reg, Operand(at));
+ // Restore at is not needed. at is reloaded below.
+ Pop(holder_reg); // Restore holder.
+ // Restore at to holder's context.
+ lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset));
+ }
+
+ // Check that the security token in the calling global object is
+ // compatible with the security token in the receiving global
+ // object.
+ int token_offset = Context::kHeaderSize +
+ Context::SECURITY_TOKEN_INDEX * kPointerSize;
+
+ lw(scratch, FieldMemOperand(scratch, token_offset));
+ lw(at, FieldMemOperand(at, token_offset));
+ Branch(miss, ne, scratch, Operand(at));
+
+ bind(&same_contexts);
}
// ---------------------------------------------------------------------------
// Instruction macros
-void MacroAssembler::Add(Register rd, Register rs, const Operand& rt) {
+void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
- add(rd, rs, rt.rm());
+ addu(rd, rs, rt.rm());
} else {
- if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
- addi(rd, rs, rt.imm32_);
+ if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) {
+ addiu(rd, rs, rt.imm32_);
} else {
// li handles the relocation.
ASSERT(!rs.is(at));
li(at, rt);
- add(rd, rs, at);
+ addu(rd, rs, at);
}
}
}
-void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) {
+void MacroAssembler::Subu(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
- addu(rd, rs, rt.rm());
+ subu(rd, rs, rt.rm());
} else {
- if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
- addiu(rd, rs, rt.imm32_);
+ if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) {
+ addiu(rd, rs, -rt.imm32_); // No subiu instr, use addiu(x, y, -imm).
} else {
// li handles the relocation.
ASSERT(!rs.is(at));
li(at, rt);
- addu(rd, rs, at);
+ subu(rd, rs, at);
}
}
}
@@ -225,7 +444,7 @@ void MacroAssembler::And(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
and_(rd, rs, rt.rm());
} else {
- if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
+ if (is_uint16(rt.imm32_) && !MustUseReg(rt.rmode_)) {
andi(rd, rs, rt.imm32_);
} else {
// li handles the relocation.
@@ -241,7 +460,7 @@ void MacroAssembler::Or(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
or_(rd, rs, rt.rm());
} else {
- if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
+ if (is_uint16(rt.imm32_) && !MustUseReg(rt.rmode_)) {
ori(rd, rs, rt.imm32_);
} else {
// li handles the relocation.
@@ -257,7 +476,7 @@ void MacroAssembler::Xor(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
xor_(rd, rs, rt.rm());
} else {
- if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
+ if (is_uint16(rt.imm32_) && !MustUseReg(rt.rmode_)) {
xori(rd, rs, rt.imm32_);
} else {
// li handles the relocation.
@@ -285,7 +504,7 @@ void MacroAssembler::Slt(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
slt(rd, rs, rt.rm());
} else {
- if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
+ if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) {
slti(rd, rs, rt.imm32_);
} else {
// li handles the relocation.
@@ -301,7 +520,7 @@ void MacroAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
sltu(rd, rs, rt.rm());
} else {
- if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
+ if (is_uint16(rt.imm32_) && !MustUseReg(rt.rmode_)) {
sltiu(rd, rs, rt.imm32_);
} else {
// li handles the relocation.
@@ -313,31 +532,51 @@ void MacroAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
}
-//------------Pseudo-instructions-------------
-
-void MacroAssembler::movn(Register rd, Register rt) {
- addiu(at, zero_reg, -1); // Fill at with ones.
- xor_(rd, rt, at);
+void MacroAssembler::Ror(Register rd, Register rs, const Operand& rt) {
+ if (mips32r2) {
+ if (rt.is_reg()) {
+ rotrv(rd, rs, rt.rm());
+ } else {
+ rotr(rd, rs, rt.imm32_);
+ }
+ } else {
+ if (rt.is_reg()) {
+ subu(at, zero_reg, rt.rm());
+ sllv(at, rs, at);
+ srlv(rd, rs, rt.rm());
+ or_(rd, rd, at);
+ } else {
+ if (rt.imm32_ == 0) {
+ srl(rd, rs, 0);
+ } else {
+ srl(at, rs, rt.imm32_);
+ sll(rd, rs, (0x20 - rt.imm32_) & 0x1f);
+ or_(rd, rd, at);
+ }
+ }
+ }
}
+//------------Pseudo-instructions-------------
+
void MacroAssembler::li(Register rd, Operand j, bool gen2instr) {
ASSERT(!j.is_reg());
-
- if (!MustUseAt(j.rmode_) && !gen2instr) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ if (!MustUseReg(j.rmode_) && !gen2instr) {
// Normal load of an immediate value which does not need Relocation Info.
if (is_int16(j.imm32_)) {
addiu(rd, zero_reg, j.imm32_);
- } else if (!(j.imm32_ & HIMask)) {
+ } else if (!(j.imm32_ & kHiMask)) {
ori(rd, zero_reg, j.imm32_);
- } else if (!(j.imm32_ & LOMask)) {
- lui(rd, (HIMask & j.imm32_) >> 16);
+ } else if (!(j.imm32_ & kImm16Mask)) {
+ lui(rd, (j.imm32_ & kHiMask) >> kLuiShift);
} else {
- lui(rd, (HIMask & j.imm32_) >> 16);
- ori(rd, rd, (LOMask & j.imm32_));
+ lui(rd, (j.imm32_ & kHiMask) >> kLuiShift);
+ ori(rd, rd, (j.imm32_ & kImm16Mask));
}
- } else if (MustUseAt(j.rmode_) || gen2instr) {
- if (MustUseAt(j.rmode_)) {
+ } else if (MustUseReg(j.rmode_) || gen2instr) {
+ if (MustUseReg(j.rmode_)) {
RecordRelocInfo(j.rmode_, j.imm32_);
}
// We need always the same number of instructions as we may need to patch
@@ -345,15 +584,15 @@ void MacroAssembler::li(Register rd, Operand j, bool gen2instr) {
if (is_int16(j.imm32_)) {
nop();
addiu(rd, zero_reg, j.imm32_);
- } else if (!(j.imm32_ & HIMask)) {
+ } else if (!(j.imm32_ & kHiMask)) {
nop();
ori(rd, zero_reg, j.imm32_);
- } else if (!(j.imm32_ & LOMask)) {
+ } else if (!(j.imm32_ & kImm16Mask)) {
nop();
- lui(rd, (HIMask & j.imm32_) >> 16);
+ lui(rd, (j.imm32_ & kHiMask) >> kLuiShift);
} else {
- lui(rd, (HIMask & j.imm32_) >> 16);
- ori(rd, rd, (LOMask & j.imm32_));
+ lui(rd, (j.imm32_ & kHiMask) >> kLuiShift);
+ ori(rd, rd, (j.imm32_ & kImm16Mask));
}
}
}
@@ -417,153 +656,772 @@ void MacroAssembler::MultiPopReversed(RegList regs) {
}
-// Emulated condtional branches do not emit a nop in the branch delay slot.
+void MacroAssembler::Ext(Register rt,
+ Register rs,
+ uint16_t pos,
+ uint16_t size) {
+ ASSERT(pos < 32);
+ ASSERT(pos + size < 32);
-// Trashes the at register if no scratch register is provided.
-void MacroAssembler::Branch(Condition cond, int16_t offset, Register rs,
- const Operand& rt, Register scratch) {
- Register r2 = no_reg;
- if (rt.is_reg()) {
- // We don't want any other register but scratch clobbered.
- ASSERT(!scratch.is(rs) && !scratch.is(rt.rm_));
- r2 = rt.rm_;
- } else if (cond != cc_always) {
- // We don't want any other register but scratch clobbered.
- ASSERT(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
+ if (mips32r2) {
+ ext_(rt, rs, pos, size);
+ } else {
+ // Move rs to rt and shift it left then right to get the
+ // desired bitfield on the right side and zeroes on the left.
+ sll(rt, rs, 32 - (pos + size));
+ srl(rt, rt, 32 - size);
}
+}
- switch (cond) {
- case cc_always:
- b(offset);
- break;
- case eq:
- beq(rs, r2, offset);
- break;
- case ne:
- bne(rs, r2, offset);
- break;
- // Signed comparison
- case greater:
- slt(scratch, r2, rs);
- bne(scratch, zero_reg, offset);
- break;
- case greater_equal:
- slt(scratch, rs, r2);
- beq(scratch, zero_reg, offset);
- break;
- case less:
- slt(scratch, rs, r2);
- bne(scratch, zero_reg, offset);
- break;
- case less_equal:
- slt(scratch, r2, rs);
- beq(scratch, zero_reg, offset);
- break;
+void MacroAssembler::Ins(Register rt,
+ Register rs,
+ uint16_t pos,
+ uint16_t size) {
+ ASSERT(pos < 32);
+ ASSERT(pos + size < 32);
- // Unsigned comparison.
- case Ugreater:
- sltu(scratch, r2, rs);
- bne(scratch, zero_reg, offset);
- break;
- case Ugreater_equal:
- sltu(scratch, rs, r2);
- beq(scratch, zero_reg, offset);
- break;
- case Uless:
- sltu(scratch, rs, r2);
- bne(scratch, zero_reg, offset);
- break;
- case Uless_equal:
- sltu(scratch, r2, rs);
- beq(scratch, zero_reg, offset);
- break;
+ if (mips32r2) {
+ ins_(rt, rs, pos, size);
+ } else {
+ ASSERT(!rt.is(t8) && !rs.is(t8));
+
+ srl(t8, rt, pos + size);
+ // The left chunk from rt that needs to
+ // be saved is on the right side of t8.
+ sll(at, t8, pos + size);
+ // The 'at' register now contains the left chunk on
+ // the left (proper position) and zeroes.
+ sll(t8, rt, 32 - pos);
+ // t8 now contains the right chunk on the left and zeroes.
+ srl(t8, t8, 32 - pos);
+ // t8 now contains the right chunk on
+ // the right (proper position) and zeroes.
+ or_(rt, at, t8);
+ // rt now contains the left and right chunks from the original rt
+ // in their proper position and zeroes in the middle.
+ sll(t8, rs, 32 - size);
+ // t8 now contains the chunk from rs on the left and zeroes.
+ srl(t8, t8, 32 - size - pos);
+ // t8 now contains the original chunk from rs in
+ // the middle (proper position).
+ or_(rt, rt, t8);
+ // rt now contains the result of the ins instruction in R2 mode.
+ }
+}
- default:
- UNREACHABLE();
+
+void MacroAssembler::Cvt_d_uw(FPURegister fd, FPURegister fs) {
+ // Move the data from fs to t4.
+ mfc1(t4, fs);
+ return Cvt_d_uw(fd, t4);
+}
+
+
+void MacroAssembler::Cvt_d_uw(FPURegister fd, Register rs) {
+ // Convert rs to a FP value in fd (and fd + 1).
+ // We do this by converting rs minus the MSB to avoid sign conversion,
+ // then adding 2^31-1 and 1 to the result.
+
+ ASSERT(!fd.is(f20));
+ ASSERT(!rs.is(t9));
+ ASSERT(!rs.is(t8));
+
+ // Save rs's MSB to t8
+ And(t8, rs, 0x80000000);
+ // Remove rs's MSB.
+ And(t9, rs, 0x7FFFFFFF);
+ // Move t9 to fd
+ mtc1(t9, fd);
+
+ // Convert fd to a real FP value.
+ cvt_d_w(fd, fd);
+
+ Label conversion_done;
+
+ // If rs's MSB was 0, it's done.
+ // Otherwise we need to add that to the FP register.
+ Branch(&conversion_done, eq, t8, Operand(zero_reg));
+
+ // First load 2^31 - 1 into f20.
+ Or(t9, zero_reg, 0x7FFFFFFF);
+ mtc1(t9, f20);
+
+ // Convert it to FP and add it to fd.
+ cvt_d_w(f20, f20);
+ add_d(fd, fd, f20);
+ // Now add 1.
+ Or(t9, zero_reg, 1);
+ mtc1(t9, f20);
+
+ cvt_d_w(f20, f20);
+ add_d(fd, fd, f20);
+ bind(&conversion_done);
+}
+
+
+void MacroAssembler::Trunc_uw_d(FPURegister fd, FPURegister fs) {
+ Trunc_uw_d(fs, t4);
+ mtc1(t4, fd);
+}
+
+
+void MacroAssembler::Trunc_uw_d(FPURegister fd, Register rs) {
+ ASSERT(!fd.is(f22));
+ ASSERT(!rs.is(t6));
+
+ // Load 2^31 into f22.
+ Or(t6, zero_reg, 0x80000000);
+ Cvt_d_uw(f22, t6);
+
+ // Test if f22 > fd.
+ c(OLT, D, fd, f22);
+
+ Label simple_convert;
+ // If fd < 2^31 we can convert it normally.
+ bc1t(&simple_convert);
+
+ // First we subtract 2^31 from fd, then trunc it to rs
+ // and add 2^31 to rs.
+
+ sub_d(f22, fd, f22);
+ trunc_w_d(f22, f22);
+ mfc1(rs, f22);
+ or_(rs, rs, t6);
+
+ Label done;
+ Branch(&done);
+ // Simple conversion.
+ bind(&simple_convert);
+ trunc_w_d(f22, fd);
+ mfc1(rs, f22);
+
+ bind(&done);
+}
+
+
+// Tries to get a signed int32 out of a double precision floating point heap
+// number. Rounds towards 0. Branch to 'not_int32' if the double is out of the
+// 32bits signed integer range.
+// This method implementation differs from the ARM version for performance
+// reasons.
+void MacroAssembler::ConvertToInt32(Register source,
+ Register dest,
+ Register scratch,
+ Register scratch2,
+ FPURegister double_scratch,
+ Label *not_int32) {
+ Label right_exponent, done;
+ // Get exponent word (ENDIAN issues).
+ lw(scratch, FieldMemOperand(source, HeapNumber::kExponentOffset));
+ // Get exponent alone in scratch2.
+ And(scratch2, scratch, Operand(HeapNumber::kExponentMask));
+ // Load dest with zero. We use this either for the final shift or
+ // for the answer.
+ mov(dest, zero_reg);
+ // Check whether the exponent matches a 32 bit signed int that is not a Smi.
+ // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is
+ // the exponent that we are fastest at and also the highest exponent we can
+ // handle here.
+ const uint32_t non_smi_exponent =
+ (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
+ // If we have a match of the int32-but-not-Smi exponent then skip some logic.
+ Branch(&right_exponent, eq, scratch2, Operand(non_smi_exponent));
+ // If the exponent is higher than that then go to not_int32 case. This
+ // catches numbers that don't fit in a signed int32, infinities and NaNs.
+ Branch(not_int32, gt, scratch2, Operand(non_smi_exponent));
+
+ // We know the exponent is smaller than 30 (biased). If it is less than
+ // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
+ // it rounds to zero.
+ const uint32_t zero_exponent =
+ (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
+ Subu(scratch2, scratch2, Operand(zero_exponent));
+ // Dest already has a Smi zero.
+ Branch(&done, lt, scratch2, Operand(zero_reg));
+ if (!Isolate::Current()->cpu_features()->IsSupported(FPU)) {
+ // We have a shifted exponent between 0 and 30 in scratch2.
+ srl(dest, scratch2, HeapNumber::kExponentShift);
+ // We now have the exponent in dest. Subtract from 30 to get
+ // how much to shift down.
+ li(at, Operand(30));
+ subu(dest, at, dest);
+ }
+ bind(&right_exponent);
+ if (Isolate::Current()->cpu_features()->IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ // MIPS FPU instructions implementing double precision to integer
+ // conversion using round to zero. Since the FP value was qualified
+ // above, the resulting integer should be a legal int32.
+ // The original 'Exponent' word is still in scratch.
+ lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
+ mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1));
+ trunc_w_d(double_scratch, double_scratch);
+ mfc1(dest, double_scratch);
+ } else {
+ // On entry, dest has final downshift, scratch has original sign/exp/mant.
+ // Save sign bit in top bit of dest.
+ And(scratch2, scratch, Operand(0x80000000));
+ Or(dest, dest, Operand(scratch2));
+ // Put back the implicit 1, just above mantissa field.
+ Or(scratch, scratch, Operand(1 << HeapNumber::kExponentShift));
+
+ // Shift up the mantissa bits to take up the space the exponent used to
+ // take. We just orred in the implicit bit so that took care of one and
+ // we want to leave the sign bit 0 so we subtract 2 bits from the shift
+ // distance. But we want to clear the sign-bit so shift one more bit
+ // left, then shift right one bit.
+ const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
+ sll(scratch, scratch, shift_distance + 1);
+ srl(scratch, scratch, 1);
+
+ // Get the second half of the double. For some exponents we don't
+ // actually need this because the bits get shifted out again, but
+ // it's probably slower to test than just to do it.
+ lw(scratch2, FieldMemOperand(source, HeapNumber::kMantissaOffset));
+ // Extract the top 10 bits, and insert those bottom 10 bits of scratch.
+ // The width of the field here is the same as the shift amount above.
+ const int field_width = shift_distance;
+ Ext(scratch2, scratch2, 32-shift_distance, field_width);
+ Ins(scratch, scratch2, 0, field_width);
+ // Move down according to the exponent.
+ srlv(scratch, scratch, dest);
+ // Prepare the negative version of our integer.
+ subu(scratch2, zero_reg, scratch);
+ // Trick to check sign bit (msb) held in dest, count leading zero.
+ // 0 indicates negative, save negative version with conditional move.
+ clz(dest, dest);
+ movz(scratch, scratch2, dest);
+ mov(dest, scratch);
}
- // Emit a nop in the branch delay slot.
- nop();
+ bind(&done);
}
-void MacroAssembler::Branch(Condition cond, Label* L, Register rs,
- const Operand& rt, Register scratch) {
+// Emulated condtional branches do not emit a nop in the branch delay slot.
+//
+// BRANCH_ARGS_CHECK checks that conditional jump arguments are correct.
+#define BRANCH_ARGS_CHECK(cond, rs, rt) ASSERT( \
+ (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \
+ (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg))))
+
+
+void MacroAssembler::Branch(int16_t offset, BranchDelaySlot bdslot) {
+ b(offset);
+
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
+}
+
+
+void MacroAssembler::Branch(int16_t offset, Condition cond, Register rs,
+ const Operand& rt,
+ BranchDelaySlot bdslot) {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+ ASSERT(!rs.is(zero_reg));
Register r2 = no_reg;
+ Register scratch = at;
+
if (rt.is_reg()) {
+ // We don't want any other register but scratch clobbered.
+ ASSERT(!scratch.is(rs) && !scratch.is(rt.rm_));
r2 = rt.rm_;
- } else if (cond != cc_always) {
- r2 = scratch;
- li(r2, rt);
+ switch (cond) {
+ case cc_always:
+ b(offset);
+ break;
+ case eq:
+ beq(rs, r2, offset);
+ break;
+ case ne:
+ bne(rs, r2, offset);
+ break;
+ // Signed comparison
+ case greater:
+ if (r2.is(zero_reg)) {
+ bgtz(rs, offset);
+ } else {
+ slt(scratch, r2, rs);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case greater_equal:
+ if (r2.is(zero_reg)) {
+ bgez(rs, offset);
+ } else {
+ slt(scratch, rs, r2);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ case less:
+ if (r2.is(zero_reg)) {
+ bltz(rs, offset);
+ } else {
+ slt(scratch, rs, r2);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case less_equal:
+ if (r2.is(zero_reg)) {
+ blez(rs, offset);
+ } else {
+ slt(scratch, r2, rs);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ // Unsigned comparison.
+ case Ugreater:
+ if (r2.is(zero_reg)) {
+ bgtz(rs, offset);
+ } else {
+ sltu(scratch, r2, rs);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case Ugreater_equal:
+ if (r2.is(zero_reg)) {
+ bgez(rs, offset);
+ } else {
+ sltu(scratch, rs, r2);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ case Uless:
+ if (r2.is(zero_reg)) {
+ b(offset);
+ } else {
+ sltu(scratch, rs, r2);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case Uless_equal:
+ if (r2.is(zero_reg)) {
+ b(offset);
+ } else {
+ sltu(scratch, r2, rs);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ } else {
+ // Be careful to always use shifted_branch_offset only just before the
+ // branch instruction, as the location will be remember for patching the
+ // target.
+ switch (cond) {
+ case cc_always:
+ b(offset);
+ break;
+ case eq:
+ // We don't want any other register but scratch clobbered.
+ ASSERT(!scratch.is(rs));
+ r2 = scratch;
+ li(r2, rt);
+ beq(rs, r2, offset);
+ break;
+ case ne:
+ // We don't want any other register but scratch clobbered.
+ ASSERT(!scratch.is(rs));
+ r2 = scratch;
+ li(r2, rt);
+ bne(rs, r2, offset);
+ break;
+ // Signed comparison
+ case greater:
+ if (rt.imm32_ == 0) {
+ bgtz(rs, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ slt(scratch, r2, rs);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case greater_equal:
+ if (rt.imm32_ == 0) {
+ bgez(rs, offset);
+ } else if (is_int16(rt.imm32_)) {
+ slti(scratch, rs, rt.imm32_);
+ beq(scratch, zero_reg, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, rs, r2);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ case less:
+ if (rt.imm32_ == 0) {
+ bltz(rs, offset);
+ } else if (is_int16(rt.imm32_)) {
+ slti(scratch, rs, rt.imm32_);
+ bne(scratch, zero_reg, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ slt(scratch, rs, r2);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case less_equal:
+ if (rt.imm32_ == 0) {
+ blez(rs, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ slt(scratch, r2, rs);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ // Unsigned comparison.
+ case Ugreater:
+ if (rt.imm32_ == 0) {
+ bgtz(rs, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, r2, rs);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case Ugreater_equal:
+ if (rt.imm32_ == 0) {
+ bgez(rs, offset);
+ } else if (is_int16(rt.imm32_)) {
+ sltiu(scratch, rs, rt.imm32_);
+ beq(scratch, zero_reg, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, rs, r2);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ case Uless:
+ if (rt.imm32_ == 0) {
+ b(offset);
+ } else if (is_int16(rt.imm32_)) {
+ sltiu(scratch, rs, rt.imm32_);
+ bne(scratch, zero_reg, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, rs, r2);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case Uless_equal:
+ if (rt.imm32_ == 0) {
+ b(offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, r2, rs);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
}
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
+}
+
+void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) {
// We use branch_offset as an argument for the branch instructions to be sure
// it is called just before generating the branch instruction, as needed.
- switch (cond) {
- case cc_always:
- b(shifted_branch_offset(L, false));
- break;
- case eq:
- beq(rs, r2, shifted_branch_offset(L, false));
- break;
- case ne:
- bne(rs, r2, shifted_branch_offset(L, false));
- break;
+ b(shifted_branch_offset(L, false));
- // Signed comparison
- case greater:
- slt(scratch, r2, rs);
- bne(scratch, zero_reg, shifted_branch_offset(L, false));
- break;
- case greater_equal:
- slt(scratch, rs, r2);
- beq(scratch, zero_reg, shifted_branch_offset(L, false));
- break;
- case less:
- slt(scratch, rs, r2);
- bne(scratch, zero_reg, shifted_branch_offset(L, false));
- break;
- case less_equal:
- slt(scratch, r2, rs);
- beq(scratch, zero_reg, shifted_branch_offset(L, false));
- break;
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
+}
- // Unsigned comparison.
- case Ugreater:
- sltu(scratch, r2, rs);
- bne(scratch, zero_reg, shifted_branch_offset(L, false));
- break;
- case Ugreater_equal:
- sltu(scratch, rs, r2);
- beq(scratch, zero_reg, shifted_branch_offset(L, false));
- break;
- case Uless:
- sltu(scratch, rs, r2);
- bne(scratch, zero_reg, shifted_branch_offset(L, false));
- break;
- case Uless_equal:
- sltu(scratch, r2, rs);
- beq(scratch, zero_reg, shifted_branch_offset(L, false));
- break;
- default:
- UNREACHABLE();
+void MacroAssembler::Branch(Label* L, Condition cond, Register rs,
+ const Operand& rt,
+ BranchDelaySlot bdslot) {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+
+ int32_t offset;
+ Register r2 = no_reg;
+ Register scratch = at;
+ if (rt.is_reg()) {
+ r2 = rt.rm_;
+ // Be careful to always use shifted_branch_offset only just before the
+ // branch instruction, as the location will be remember for patching the
+ // target.
+ switch (cond) {
+ case cc_always:
+ offset = shifted_branch_offset(L, false);
+ b(offset);
+ break;
+ case eq:
+ offset = shifted_branch_offset(L, false);
+ beq(rs, r2, offset);
+ break;
+ case ne:
+ offset = shifted_branch_offset(L, false);
+ bne(rs, r2, offset);
+ break;
+ // Signed comparison
+ case greater:
+ if (r2.is(zero_reg)) {
+ offset = shifted_branch_offset(L, false);
+ bgtz(rs, offset);
+ } else {
+ slt(scratch, r2, rs);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case greater_equal:
+ if (r2.is(zero_reg)) {
+ offset = shifted_branch_offset(L, false);
+ bgez(rs, offset);
+ } else {
+ slt(scratch, rs, r2);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ case less:
+ if (r2.is(zero_reg)) {
+ offset = shifted_branch_offset(L, false);
+ bltz(rs, offset);
+ } else {
+ slt(scratch, rs, r2);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case less_equal:
+ if (r2.is(zero_reg)) {
+ offset = shifted_branch_offset(L, false);
+ blez(rs, offset);
+ } else {
+ slt(scratch, r2, rs);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ // Unsigned comparison.
+ case Ugreater:
+ if (r2.is(zero_reg)) {
+ offset = shifted_branch_offset(L, false);
+ bgtz(rs, offset);
+ } else {
+ sltu(scratch, r2, rs);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case Ugreater_equal:
+ if (r2.is(zero_reg)) {
+ offset = shifted_branch_offset(L, false);
+ bgez(rs, offset);
+ } else {
+ sltu(scratch, rs, r2);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ case Uless:
+ if (r2.is(zero_reg)) {
+ offset = shifted_branch_offset(L, false);
+ b(offset);
+ } else {
+ sltu(scratch, rs, r2);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case Uless_equal:
+ if (r2.is(zero_reg)) {
+ offset = shifted_branch_offset(L, false);
+ b(offset);
+ } else {
+ sltu(scratch, r2, rs);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ } else {
+ // Be careful to always use shifted_branch_offset only just before the
+ // branch instruction, as the location will be remember for patching the
+ // target.
+ switch (cond) {
+ case cc_always:
+ offset = shifted_branch_offset(L, false);
+ b(offset);
+ break;
+ case eq:
+ r2 = scratch;
+ li(r2, rt);
+ offset = shifted_branch_offset(L, false);
+ beq(rs, r2, offset);
+ break;
+ case ne:
+ r2 = scratch;
+ li(r2, rt);
+ offset = shifted_branch_offset(L, false);
+ bne(rs, r2, offset);
+ break;
+ // Signed comparison
+ case greater:
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ bgtz(rs, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ slt(scratch, r2, rs);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case greater_equal:
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ bgez(rs, offset);
+ } else if (is_int16(rt.imm32_)) {
+ slti(scratch, rs, rt.imm32_);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, rs, r2);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ case less:
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ bltz(rs, offset);
+ } else if (is_int16(rt.imm32_)) {
+ slti(scratch, rs, rt.imm32_);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ slt(scratch, rs, r2);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case less_equal:
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ blez(rs, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ slt(scratch, r2, rs);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ // Unsigned comparison.
+ case Ugreater:
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ bgtz(rs, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, r2, rs);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case Ugreater_equal:
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ bgez(rs, offset);
+ } else if (is_int16(rt.imm32_)) {
+ sltiu(scratch, rs, rt.imm32_);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, rs, r2);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ case Uless:
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ b(offset);
+ } else if (is_int16(rt.imm32_)) {
+ sltiu(scratch, rs, rt.imm32_);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, rs, r2);
+ offset = shifted_branch_offset(L, false);
+ bne(scratch, zero_reg, offset);
+ }
+ break;
+ case Uless_equal:
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ b(offset);
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ sltu(scratch, r2, rs);
+ offset = shifted_branch_offset(L, false);
+ beq(scratch, zero_reg, offset);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
}
- // Emit a nop in the branch delay slot.
- nop();
+ // Check that offset could actually hold on an int16_t.
+ ASSERT(is_int16(offset));
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
}
-// Trashes the at register if no scratch register is provided.
// We need to use a bgezal or bltzal, but they can't be used directly with the
// slt instructions. We could use sub or add instead but we would miss overflow
// cases, so we keep slt and add an intermediate third instruction.
-void MacroAssembler::BranchAndLink(Condition cond, int16_t offset, Register rs,
- const Operand& rt, Register scratch) {
+void MacroAssembler::BranchAndLink(int16_t offset,
+ BranchDelaySlot bdslot) {
+ bal(offset);
+
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
+}
+
+
+void MacroAssembler::BranchAndLink(int16_t offset, Condition cond, Register rs,
+ const Operand& rt,
+ BranchDelaySlot bdslot) {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
Register r2 = no_reg;
+ Register scratch = at;
+
if (rt.is_reg()) {
r2 = rt.rm_;
} else if (cond != cc_always) {
@@ -633,14 +1491,29 @@ void MacroAssembler::BranchAndLink(Condition cond, int16_t offset, Register rs,
default:
UNREACHABLE();
}
- // Emit a nop in the branch delay slot.
- nop();
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
}
-void MacroAssembler::BranchAndLink(Condition cond, Label* L, Register rs,
- const Operand& rt, Register scratch) {
+void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) {
+ bal(shifted_branch_offset(L, false));
+
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
+}
+
+
+void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs,
+ const Operand& rt,
+ BranchDelaySlot bdslot) {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+
+ int32_t offset;
Register r2 = no_reg;
+ Register scratch = at;
if (rt.is_reg()) {
r2 = rt.rm_;
} else if (cond != cc_always) {
@@ -650,157 +1523,280 @@ void MacroAssembler::BranchAndLink(Condition cond, Label* L, Register rs,
switch (cond) {
case cc_always:
- bal(shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bal(offset);
break;
case eq:
bne(rs, r2, 2);
nop();
- bal(shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bal(offset);
break;
case ne:
beq(rs, r2, 2);
nop();
- bal(shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bal(offset);
break;
// Signed comparison
case greater:
slt(scratch, r2, rs);
addiu(scratch, scratch, -1);
- bgezal(scratch, shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bgezal(scratch, offset);
break;
case greater_equal:
slt(scratch, rs, r2);
addiu(scratch, scratch, -1);
- bltzal(scratch, shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bltzal(scratch, offset);
break;
case less:
slt(scratch, rs, r2);
addiu(scratch, scratch, -1);
- bgezal(scratch, shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bgezal(scratch, offset);
break;
case less_equal:
slt(scratch, r2, rs);
addiu(scratch, scratch, -1);
- bltzal(scratch, shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bltzal(scratch, offset);
break;
// Unsigned comparison.
case Ugreater:
sltu(scratch, r2, rs);
addiu(scratch, scratch, -1);
- bgezal(scratch, shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bgezal(scratch, offset);
break;
case Ugreater_equal:
sltu(scratch, rs, r2);
addiu(scratch, scratch, -1);
- bltzal(scratch, shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bltzal(scratch, offset);
break;
case Uless:
sltu(scratch, rs, r2);
addiu(scratch, scratch, -1);
- bgezal(scratch, shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bgezal(scratch, offset);
break;
case Uless_equal:
sltu(scratch, r2, rs);
addiu(scratch, scratch, -1);
- bltzal(scratch, shifted_branch_offset(L, false));
+ offset = shifted_branch_offset(L, false);
+ bltzal(scratch, offset);
break;
default:
UNREACHABLE();
}
- // Emit a nop in the branch delay slot.
- nop();
+
+ // Check that offset could actually hold on an int16_t.
+ ASSERT(is_int16(offset));
+
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
+}
+
+
+void MacroAssembler::Jump(const Operand& target, BranchDelaySlot bdslot) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ if (target.is_reg()) {
+ jr(target.rm());
+ } else {
+ if (!MustUseReg(target.rmode_)) {
+ j(target.imm32_);
+ } else {
+ li(t9, target);
+ jr(t9);
+ }
+ }
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
}
void MacroAssembler::Jump(const Operand& target,
- Condition cond, Register rs, const Operand& rt) {
+ Condition cond, Register rs, const Operand& rt,
+ BranchDelaySlot bdslot) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ BRANCH_ARGS_CHECK(cond, rs, rt);
if (target.is_reg()) {
if (cond == cc_always) {
jr(target.rm());
} else {
- Branch(NegateCondition(cond), 2, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
jr(target.rm());
}
- } else { // !target.is_reg()
- if (!MustUseAt(target.rmode_)) {
+ } else { // Not register target.
+ if (!MustUseReg(target.rmode_)) {
if (cond == cc_always) {
j(target.imm32_);
} else {
- Branch(NegateCondition(cond), 2, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
j(target.imm32_); // Will generate only one instruction.
}
- } else { // MustUseAt(target)
- li(at, target);
+ } else { // MustUseReg(target)
+ li(t9, target);
if (cond == cc_always) {
- jr(at);
+ jr(t9);
} else {
- Branch(NegateCondition(cond), 2, rs, rt);
- jr(at); // Will generate only one instruction.
+ Branch(2, NegateCondition(cond), rs, rt);
+ jr(t9); // Will generate only one instruction.
}
}
}
- // Emit a nop in the branch delay slot.
- nop();
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
}
+// Note: To call gcc-compiled C code on mips, you must call thru t9.
+void MacroAssembler::Call(const Operand& target, BranchDelaySlot bdslot) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ if (target.is_reg()) {
+ jalr(target.rm());
+ } else { // !target.is_reg()
+ if (!MustUseReg(target.rmode_)) {
+ jal(target.imm32_);
+ } else { // MustUseReg(target)
+ li(t9, target);
+ jalr(t9);
+ }
+ }
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
+}
+
+
+// Note: To call gcc-compiled C code on mips, you must call thru t9.
void MacroAssembler::Call(const Operand& target,
- Condition cond, Register rs, const Operand& rt) {
+ Condition cond, Register rs, const Operand& rt,
+ BranchDelaySlot bdslot) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ BRANCH_ARGS_CHECK(cond, rs, rt);
if (target.is_reg()) {
if (cond == cc_always) {
jalr(target.rm());
} else {
- Branch(NegateCondition(cond), 2, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
jalr(target.rm());
}
} else { // !target.is_reg()
- if (!MustUseAt(target.rmode_)) {
+ if (!MustUseReg(target.rmode_)) {
if (cond == cc_always) {
jal(target.imm32_);
} else {
- Branch(NegateCondition(cond), 2, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
jal(target.imm32_); // Will generate only one instruction.
}
- } else { // MustUseAt(target)
- li(at, target);
+ } else { // MustUseReg(target)
+ li(t9, target);
if (cond == cc_always) {
- jalr(at);
+ jalr(t9);
} else {
- Branch(NegateCondition(cond), 2, rs, rt);
- jalr(at); // Will generate only one instruction.
+ Branch(2, NegateCondition(cond), rs, rt);
+ jalr(t9); // Will generate only one instruction.
}
}
}
- // Emit a nop in the branch delay slot.
- nop();
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
+}
+
+
+void MacroAssembler::Drop(int count,
+ Condition cond,
+ Register reg,
+ const Operand& op) {
+ if (count <= 0) {
+ return;
+ }
+
+ Label skip;
+
+ if (cond != al) {
+ Branch(&skip, NegateCondition(cond), reg, op);
+ }
+
+ if (count > 0) {
+ addiu(sp, sp, count * kPointerSize);
+ }
+
+ if (cond != al) {
+ bind(&skip);
+ }
}
-void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
- UNIMPLEMENTED_MIPS();
+
+void MacroAssembler::DropAndRet(int drop,
+ Condition cond,
+ Register r1,
+ const Operand& r2) {
+ // This is a workaround to make sure only one branch instruction is
+ // generated. It relies on Drop and Ret not creating branches if
+ // cond == cc_always.
+ Label skip;
+ if (cond != cc_always) {
+ Branch(&skip, NegateCondition(cond), r1, r2);
+ }
+
+ Drop(drop);
+ Ret();
+
+ if (cond != cc_always) {
+ bind(&skip);
+ }
}
-void MacroAssembler::Drop(int count, Condition cond) {
- UNIMPLEMENTED_MIPS();
+void MacroAssembler::Swap(Register reg1,
+ Register reg2,
+ Register scratch) {
+ if (scratch.is(no_reg)) {
+ Xor(reg1, reg1, Operand(reg2));
+ Xor(reg2, reg2, Operand(reg1));
+ Xor(reg1, reg1, Operand(reg2));
+ } else {
+ mov(scratch, reg1);
+ mov(reg1, reg2);
+ mov(reg2, scratch);
+ }
}
void MacroAssembler::Call(Label* target) {
- UNIMPLEMENTED_MIPS();
+ BranchAndLink(target);
+}
+
+
+void MacroAssembler::Move(Register dst, Register src) {
+ if (!dst.is(src)) {
+ mov(dst, src);
+ }
}
#ifdef ENABLE_DEBUGGER_SUPPORT
- // ---------------------------------------------------------------------------
- // Debugger Support
- void MacroAssembler::DebugBreak() {
- UNIMPLEMENTED_MIPS();
- }
-#endif
+void MacroAssembler::DebugBreak() {
+ ASSERT(allow_stub_calls());
+ mov(a0, zero_reg);
+ li(a1, Operand(ExternalReference(Runtime::kDebugBreak, isolate())));
+ CEntryStub ces(1);
+ Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
+}
+
+#endif // ENABLE_DEBUGGER_SUPPORT
// ---------------------------------------------------------------------------
@@ -822,7 +1818,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
&& StackHandlerConstants::kPCOffset == 3 * kPointerSize
&& StackHandlerConstants::kNextOffset == 0 * kPointerSize);
// Save the current handler as the next handler.
- LoadExternalReference(t2, ExternalReference(Top::k_handler_address));
+ li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
lw(t1, MemOperand(t2));
addiu(sp, sp, -StackHandlerConstants::kSize);
@@ -848,7 +1844,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
li(t0, Operand(StackHandler::ENTRY));
// Save the current handler as the next handler.
- LoadExternalReference(t2, ExternalReference(Top::k_handler_address));
+ li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
lw(t1, MemOperand(t2));
addiu(sp, sp, -StackHandlerConstants::kSize);
@@ -864,45 +1860,377 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
void MacroAssembler::PopTryHandler() {
- UNIMPLEMENTED_MIPS();
+ ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
+ pop(a1);
+ Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+ li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ sw(a1, MemOperand(at));
+}
+
+
+void MacroAssembler::AllocateInNewSpace(int object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ AllocationFlags flags) {
+ if (!FLAG_inline_new) {
+ if (FLAG_debug_code) {
+ // Trash the registers to simulate an allocation failure.
+ li(result, 0x7091);
+ li(scratch1, 0x7191);
+ li(scratch2, 0x7291);
+ }
+ jmp(gc_required);
+ return;
+ }
+
+ ASSERT(!result.is(scratch1));
+ ASSERT(!result.is(scratch2));
+ ASSERT(!scratch1.is(scratch2));
+ ASSERT(!scratch1.is(t9));
+ ASSERT(!scratch2.is(t9));
+ ASSERT(!result.is(t9));
+
+ // Make object size into bytes.
+ if ((flags & SIZE_IN_WORDS) != 0) {
+ object_size *= kPointerSize;
+ }
+ ASSERT_EQ(0, object_size & kObjectAlignmentMask);
+
+ // Check relative positions of allocation top and limit addresses.
+ // ARM adds additional checks to make sure the ldm instruction can be
+ // used. On MIPS we don't have ldm so we don't need additional checks either.
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
+ ExternalReference new_space_allocation_limit =
+ ExternalReference::new_space_allocation_limit_address(isolate());
+ intptr_t top =
+ reinterpret_cast<intptr_t>(new_space_allocation_top.address());
+ intptr_t limit =
+ reinterpret_cast<intptr_t>(new_space_allocation_limit.address());
+ ASSERT((limit - top) == kPointerSize);
+
+ // Set up allocation top address and object size registers.
+ Register topaddr = scratch1;
+ Register obj_size_reg = scratch2;
+ li(topaddr, Operand(new_space_allocation_top));
+ li(obj_size_reg, Operand(object_size));
+
+ // This code stores a temporary value in t9.
+ if ((flags & RESULT_CONTAINS_TOP) == 0) {
+ // Load allocation top into result and allocation limit into t9.
+ lw(result, MemOperand(topaddr));
+ lw(t9, MemOperand(topaddr, kPointerSize));
+ } else {
+ if (FLAG_debug_code) {
+ // Assert that result actually contains top on entry. t9 is used
+ // immediately below so this use of t9 does not cause difference with
+ // respect to register content between debug and release mode.
+ lw(t9, MemOperand(topaddr));
+ Check(eq, "Unexpected allocation top", result, Operand(t9));
+ }
+ // Load allocation limit into t9. Result already contains allocation top.
+ lw(t9, MemOperand(topaddr, limit - top));
+ }
+
+ // Calculate new top and bail out if new space is exhausted. Use result
+ // to calculate the new top.
+ Addu(scratch2, result, Operand(obj_size_reg));
+ Branch(gc_required, Ugreater, scratch2, Operand(t9));
+ sw(scratch2, MemOperand(topaddr));
+
+ // Tag object if requested.
+ if ((flags & TAG_OBJECT) != 0) {
+ Addu(result, result, Operand(kHeapObjectTag));
+ }
}
+void MacroAssembler::AllocateInNewSpace(Register object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ AllocationFlags flags) {
+ if (!FLAG_inline_new) {
+ if (FLAG_debug_code) {
+ // Trash the registers to simulate an allocation failure.
+ li(result, 0x7091);
+ li(scratch1, 0x7191);
+ li(scratch2, 0x7291);
+ }
+ jmp(gc_required);
+ return;
+ }
-// -----------------------------------------------------------------------------
-// Activation frames
+ ASSERT(!result.is(scratch1));
+ ASSERT(!result.is(scratch2));
+ ASSERT(!scratch1.is(scratch2));
+ ASSERT(!scratch1.is(t9) && !scratch2.is(t9) && !result.is(t9));
+
+ // Check relative positions of allocation top and limit addresses.
+ // ARM adds additional checks to make sure the ldm instruction can be
+ // used. On MIPS we don't have ldm so we don't need additional checks either.
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
+ ExternalReference new_space_allocation_limit =
+ ExternalReference::new_space_allocation_limit_address(isolate());
+ intptr_t top =
+ reinterpret_cast<intptr_t>(new_space_allocation_top.address());
+ intptr_t limit =
+ reinterpret_cast<intptr_t>(new_space_allocation_limit.address());
+ ASSERT((limit - top) == kPointerSize);
+
+ // Set up allocation top address and object size registers.
+ Register topaddr = scratch1;
+ li(topaddr, Operand(new_space_allocation_top));
+
+ // This code stores a temporary value in t9.
+ if ((flags & RESULT_CONTAINS_TOP) == 0) {
+ // Load allocation top into result and allocation limit into t9.
+ lw(result, MemOperand(topaddr));
+ lw(t9, MemOperand(topaddr, kPointerSize));
+ } else {
+ if (FLAG_debug_code) {
+ // Assert that result actually contains top on entry. t9 is used
+ // immediately below so this use of t9 does not cause difference with
+ // respect to register content between debug and release mode.
+ lw(t9, MemOperand(topaddr));
+ Check(eq, "Unexpected allocation top", result, Operand(t9));
+ }
+ // Load allocation limit into t9. Result already contains allocation top.
+ lw(t9, MemOperand(topaddr, limit - top));
+ }
+
+ // Calculate new top and bail out if new space is exhausted. Use result
+ // to calculate the new top. Object size may be in words so a shift is
+ // required to get the number of bytes.
+ if ((flags & SIZE_IN_WORDS) != 0) {
+ sll(scratch2, object_size, kPointerSizeLog2);
+ Addu(scratch2, result, scratch2);
+ } else {
+ Addu(scratch2, result, Operand(object_size));
+ }
+ Branch(gc_required, Ugreater, scratch2, Operand(t9));
+
+ // Update allocation top. result temporarily holds the new top.
+ if (FLAG_debug_code) {
+ And(t9, scratch2, Operand(kObjectAlignmentMask));
+ Check(eq, "Unaligned allocation in new space", t9, Operand(zero_reg));
+ }
+ sw(scratch2, MemOperand(topaddr));
+
+ // Tag object if requested.
+ if ((flags & TAG_OBJECT) != 0) {
+ Addu(result, result, Operand(kHeapObjectTag));
+ }
+}
-void MacroAssembler::SetupAlignedCall(Register scratch, int arg_count) {
- Label extra_push, end;
- andi(scratch, sp, 7);
+void MacroAssembler::UndoAllocationInNewSpace(Register object,
+ Register scratch) {
+ ExternalReference new_space_allocation_top =
+ ExternalReference::new_space_allocation_top_address(isolate());
- // We check for args and receiver size on the stack, all of them word sized.
- // We add one for sp, that we also want to store on the stack.
- if (((arg_count + 1) % kPointerSizeLog2) == 0) {
- Branch(ne, &extra_push, at, Operand(zero_reg));
- } else { // ((arg_count + 1) % 2) == 1
- Branch(eq, &extra_push, at, Operand(zero_reg));
+ // Make sure the object has no tag before resetting top.
+ And(object, object, Operand(~kHeapObjectTagMask));
+#ifdef DEBUG
+ // Check that the object un-allocated is below the current top.
+ li(scratch, Operand(new_space_allocation_top));
+ lw(scratch, MemOperand(scratch));
+ Check(less, "Undo allocation of non allocated memory",
+ object, Operand(scratch));
+#endif
+ // Write the address of the object to un-allocate as the current top.
+ li(scratch, Operand(new_space_allocation_top));
+ sw(object, MemOperand(scratch));
+}
+
+
+void MacroAssembler::AllocateTwoByteString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* gc_required) {
+ // Calculate the number of bytes needed for the characters in the string while
+ // observing object alignment.
+ ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+ sll(scratch1, length, 1); // Length in bytes, not chars.
+ addiu(scratch1, scratch1,
+ kObjectAlignmentMask + SeqTwoByteString::kHeaderSize);
+ And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
+
+ // Allocate two-byte string in new space.
+ AllocateInNewSpace(scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map, length and hash field.
+ InitializeNewString(result,
+ length,
+ Heap::kStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
+void MacroAssembler::AllocateAsciiString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* gc_required) {
+ // Calculate the number of bytes needed for the characters in the string
+ // while observing object alignment.
+ ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
+ ASSERT(kCharSize == 1);
+ addiu(scratch1, length, kObjectAlignmentMask + SeqAsciiString::kHeaderSize);
+ And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
+
+ // Allocate ASCII string in new space.
+ AllocateInNewSpace(scratch1,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map, length and hash field.
+ InitializeNewString(result,
+ length,
+ Heap::kAsciiStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
+void MacroAssembler::AllocateTwoByteConsString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(ConsString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+ InitializeNewString(result,
+ length,
+ Heap::kConsStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
+void MacroAssembler::AllocateAsciiConsString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(ConsString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+ InitializeNewString(result,
+ length,
+ Heap::kConsAsciiStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
+// Allocates a heap number or jumps to the label if the young space is full and
+// a scavenge is needed.
+void MacroAssembler::AllocateHeapNumber(Register result,
+ Register scratch1,
+ Register scratch2,
+ Register heap_number_map,
+ Label* need_gc) {
+ // Allocate an object in the heap for the heap number and tag it as a heap
+ // object.
+ AllocateInNewSpace(HeapNumber::kSize,
+ result,
+ scratch1,
+ scratch2,
+ need_gc,
+ TAG_OBJECT);
+
+ // Store heap number map in the allocated object.
+ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+ sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
+}
+
+
+void MacroAssembler::AllocateHeapNumberWithValue(Register result,
+ FPURegister value,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
+ AllocateHeapNumber(result, scratch1, scratch2, t6, gc_required);
+ sdc1(value, FieldMemOperand(result, HeapNumber::kValueOffset));
+}
+
+
+// Copies a fixed number of fields of heap objects from src to dst.
+void MacroAssembler::CopyFields(Register dst,
+ Register src,
+ RegList temps,
+ int field_count) {
+ ASSERT((temps & dst.bit()) == 0);
+ ASSERT((temps & src.bit()) == 0);
+ // Primitive implementation using only one temporary register.
+
+ Register tmp = no_reg;
+ // Find a temp register in temps list.
+ for (int i = 0; i < kNumRegisters; i++) {
+ if ((temps & (1 << i)) != 0) {
+ tmp.code_ = i;
+ break;
+ }
}
+ ASSERT(!tmp.is(no_reg));
- // Save sp on the stack.
- mov(scratch, sp);
- Push(scratch);
- b(&end);
+ for (int i = 0; i < field_count; i++) {
+ lw(tmp, FieldMemOperand(src, i * kPointerSize));
+ sw(tmp, FieldMemOperand(dst, i * kPointerSize));
+ }
+}
- // Align before saving sp on the stack.
- bind(&extra_push);
- mov(scratch, sp);
- addiu(sp, sp, -8);
- sw(scratch, MemOperand(sp));
- // The stack is aligned and sp is stored on the top.
- bind(&end);
+void MacroAssembler::CheckMap(Register obj,
+ Register scratch,
+ Handle<Map> map,
+ Label* fail,
+ bool is_heap_object) {
+ if (!is_heap_object) {
+ JumpIfSmi(obj, fail);
+ }
+ lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+ li(at, Operand(map));
+ Branch(fail, ne, scratch, Operand(at));
}
-void MacroAssembler::ReturnFromAlignedCall() {
- lw(sp, MemOperand(sp));
+void MacroAssembler::CheckMap(Register obj,
+ Register scratch,
+ Heap::RootListIndex index,
+ Label* fail,
+ bool is_heap_object) {
+ if (!is_heap_object) {
+ JumpIfSmi(obj, fail);
+ }
+ lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+ LoadRoot(at, index);
+ Branch(fail, ne, scratch, Operand(at));
}
@@ -914,7 +2242,8 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Handle<Code> code_constant,
Register code_reg,
Label* done,
- InvokeFlag flag) {
+ InvokeFlag flag,
+ PostCallGenerator* post_call_generator) {
bool definitely_matches = false;
Label regular_invoke;
@@ -949,11 +2278,13 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
li(a2, Operand(expected.immediate()));
}
}
- } else if (actual.is_immediate()) {
- Branch(eq, &regular_invoke, expected.reg(), Operand(actual.immediate()));
- li(a0, Operand(actual.immediate()));
} else {
- Branch(eq, &regular_invoke, expected.reg(), Operand(actual.reg()));
+ if (actual.is_immediate()) {
+ Branch(&regular_invoke, eq, expected.reg(), Operand(actual.immediate()));
+ li(a0, Operand(actual.immediate()));
+ } else {
+ Branch(&regular_invoke, eq, expected.reg(), Operand(actual.reg()));
+ }
}
if (!definitely_matches) {
@@ -962,25 +2293,29 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
addiu(a3, a3, Code::kHeaderSize - kHeapObjectTag);
}
- ExternalReference adaptor(Builtins::ArgumentsAdaptorTrampoline);
+ Handle<Code> adaptor =
+ isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (flag == CALL_FUNCTION) {
- CallBuiltin(adaptor);
- b(done);
- nop();
+ Call(adaptor, RelocInfo::CODE_TARGET);
+ if (post_call_generator != NULL) post_call_generator->Generate();
+ jmp(done);
} else {
- JumpToBuiltin(adaptor);
+ Jump(adaptor, RelocInfo::CODE_TARGET);
}
bind(&regular_invoke);
}
}
+
void MacroAssembler::InvokeCode(Register code,
const ParameterCount& expected,
const ParameterCount& actual,
- InvokeFlag flag) {
+ InvokeFlag flag,
+ PostCallGenerator* post_call_generator) {
Label done;
- InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
+ InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag,
+ post_call_generator);
if (flag == CALL_FUNCTION) {
Call(code);
} else {
@@ -1014,7 +2349,8 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
void MacroAssembler::InvokeFunction(Register function,
const ParameterCount& actual,
- InvokeFlag flag) {
+ InvokeFlag flag,
+ PostCallGenerator* post_call_generator) {
// Contract with called JS functions requires that function is passed in a1.
ASSERT(function.is(a1));
Register expected_reg = a2;
@@ -1025,68 +2361,120 @@ void MacroAssembler::InvokeFunction(Register function,
lw(expected_reg,
FieldMemOperand(code_reg,
SharedFunctionInfo::kFormalParameterCountOffset));
- lw(code_reg,
- MemOperand(code_reg, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
- addiu(code_reg, code_reg, Code::kHeaderSize - kHeapObjectTag);
+ sra(expected_reg, expected_reg, kSmiTagSize);
+ lw(code_reg, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
ParameterCount expected(expected_reg);
- InvokeCode(code_reg, expected, actual, flag);
+ InvokeCode(code_reg, expected, actual, flag, post_call_generator);
+}
+
+
+void MacroAssembler::InvokeFunction(JSFunction* function,
+ const ParameterCount& actual,
+ InvokeFlag flag) {
+ ASSERT(function->is_compiled());
+
+ // Get the function and setup the context.
+ li(a1, Operand(Handle<JSFunction>(function)));
+ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
+
+ // Invoke the cached code.
+ Handle<Code> code(function->code());
+ ParameterCount expected(function->shared()->formal_parameter_count());
+ if (V8::UseCrankshaft()) {
+ UNIMPLEMENTED_MIPS();
+ } else {
+ InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag);
+ }
+}
+
+
+void MacroAssembler::IsObjectJSObjectType(Register heap_object,
+ Register map,
+ Register scratch,
+ Label* fail) {
+ lw(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
+ IsInstanceJSObjectType(map, scratch, fail);
+}
+
+
+void MacroAssembler::IsInstanceJSObjectType(Register map,
+ Register scratch,
+ Label* fail) {
+ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+ Branch(fail, lt, scratch, Operand(FIRST_JS_OBJECT_TYPE));
+ Branch(fail, gt, scratch, Operand(LAST_JS_OBJECT_TYPE));
+}
+
+
+void MacroAssembler::IsObjectJSStringType(Register object,
+ Register scratch,
+ Label* fail) {
+ ASSERT(kNotStringTag != 0);
+
+ lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+ lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+ And(scratch, scratch, Operand(kIsNotStringMask));
+ Branch(fail, ne, scratch, Operand(zero_reg));
}
// ---------------------------------------------------------------------------
// Support functions.
- void MacroAssembler::GetObjectType(Register function,
- Register map,
- Register type_reg) {
- lw(map, FieldMemOperand(function, HeapObject::kMapOffset));
- lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
- }
+void MacroAssembler::TryGetFunctionPrototype(Register function,
+ Register result,
+ Register scratch,
+ Label* miss) {
+ // Check that the receiver isn't a smi.
+ JumpIfSmi(function, miss);
- void MacroAssembler::CallBuiltin(ExternalReference builtin_entry) {
- // Load builtin address.
- LoadExternalReference(t9, builtin_entry);
- lw(t9, MemOperand(t9)); // Deref address.
- addiu(t9, t9, Code::kHeaderSize - kHeapObjectTag);
- // Call and allocate arguments slots.
- jalr(t9);
- // Use the branch delay slot to allocated argument slots.
- addiu(sp, sp, -StandardFrameConstants::kRArgsSlotsSize);
- addiu(sp, sp, StandardFrameConstants::kRArgsSlotsSize);
- }
+ // Check that the function really is a function. Load map into result reg.
+ GetObjectType(function, result, scratch);
+ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
+ // Make sure that the function has an instance prototype.
+ Label non_instance;
+ lbu(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
+ And(scratch, scratch, Operand(1 << Map::kHasNonInstancePrototype));
+ Branch(&non_instance, ne, scratch, Operand(zero_reg));
- void MacroAssembler::CallBuiltin(Register target) {
- // Target already holds target address.
- // Call and allocate arguments slots.
- jalr(target);
- // Use the branch delay slot to allocated argument slots.
- addiu(sp, sp, -StandardFrameConstants::kRArgsSlotsSize);
- addiu(sp, sp, StandardFrameConstants::kRArgsSlotsSize);
- }
+ // Get the prototype or initial map from the function.
+ lw(result,
+ FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+ // If the prototype or initial map is the hole, don't return it and
+ // simply miss the cache instead. This will allow us to allocate a
+ // prototype object on-demand in the runtime system.
+ LoadRoot(t8, Heap::kTheHoleValueRootIndex);
+ Branch(miss, eq, result, Operand(t8));
- void MacroAssembler::JumpToBuiltin(ExternalReference builtin_entry) {
- // Load builtin address.
- LoadExternalReference(t9, builtin_entry);
- lw(t9, MemOperand(t9)); // Deref address.
- addiu(t9, t9, Code::kHeaderSize - kHeapObjectTag);
- // Call and allocate arguments slots.
- jr(t9);
- // Use the branch delay slot to allocated argument slots.
- addiu(sp, sp, -StandardFrameConstants::kRArgsSlotsSize);
- }
+ // If the function does not have an initial map, we're done.
+ Label done;
+ GetObjectType(result, scratch, scratch);
+ Branch(&done, ne, scratch, Operand(MAP_TYPE));
+ // Get the prototype from the initial map.
+ lw(result, FieldMemOperand(result, Map::kPrototypeOffset));
+ jmp(&done);
- void MacroAssembler::JumpToBuiltin(Register target) {
- // t9 already holds target address.
- // Call and allocate arguments slots.
- jr(t9);
- // Use the branch delay slot to allocated argument slots.
- addiu(sp, sp, -StandardFrameConstants::kRArgsSlotsSize);
- }
+ // Non-instance prototype: Fetch prototype from constructor field
+ // in initial map.
+ bind(&non_instance);
+ lw(result, FieldMemOperand(result, Map::kConstructorOffset));
+
+ // All done.
+ bind(&done);
+}
+
+
+void MacroAssembler::GetObjectType(Register object,
+ Register map,
+ Register type_reg) {
+ lw(map, FieldMemOperand(object, HeapObject::kMapOffset));
+ lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
+}
// -----------------------------------------------------------------------------
@@ -1099,8 +2487,9 @@ void MacroAssembler::CallStub(CodeStub* stub, Condition cond,
}
-void MacroAssembler::StubReturn(int argc) {
- UNIMPLEMENTED_MIPS();
+void MacroAssembler::TailCallStub(CodeStub* stub) {
+ ASSERT(allow_stub_calls()); // stub calls are not allowed in some stubs
+ Jump(stub->GetCode(), RelocInfo::CODE_TARGET);
}
@@ -1112,7 +2501,71 @@ void MacroAssembler::IllegalOperation(int num_arguments) {
}
-void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
+void MacroAssembler::IndexFromHash(Register hash,
+ Register index) {
+ // If the hash field contains an array index pick it out. The assert checks
+ // that the constants for the maximum number of digits for an array index
+ // cached in the hash field and the number of bits reserved for it does not
+ // conflict.
+ ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
+ (1 << String::kArrayIndexValueBits));
+ // We want the smi-tagged index in key. kArrayIndexValueMask has zeros in
+ // the low kHashShift bits.
+ STATIC_ASSERT(kSmiTag == 0);
+ Ext(hash, hash, String::kHashShift, String::kArrayIndexValueBits);
+ sll(index, hash, kSmiTagSize);
+}
+
+
+void MacroAssembler::ObjectToDoubleFPURegister(Register object,
+ FPURegister result,
+ Register scratch1,
+ Register scratch2,
+ Register heap_number_map,
+ Label* not_number,
+ ObjectToDoubleFlags flags) {
+ Label done;
+ if ((flags & OBJECT_NOT_SMI) == 0) {
+ Label not_smi;
+ JumpIfNotSmi(object, &not_smi);
+ // Remove smi tag and convert to double.
+ sra(scratch1, object, kSmiTagSize);
+ mtc1(scratch1, result);
+ cvt_d_w(result, result);
+ Branch(&done);
+ bind(&not_smi);
+ }
+ // Check for heap number and load double value from it.
+ lw(scratch1, FieldMemOperand(object, HeapObject::kMapOffset));
+ Branch(not_number, ne, scratch1, Operand(heap_number_map));
+
+ if ((flags & AVOID_NANS_AND_INFINITIES) != 0) {
+ // If exponent is all ones the number is either a NaN or +/-Infinity.
+ Register exponent = scratch1;
+ Register mask_reg = scratch2;
+ lw(exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
+ li(mask_reg, HeapNumber::kExponentMask);
+
+ And(exponent, exponent, mask_reg);
+ Branch(not_number, eq, exponent, Operand(mask_reg));
+ }
+ ldc1(result, FieldMemOperand(object, HeapNumber::kValueOffset));
+ bind(&done);
+}
+
+
+
+void MacroAssembler::SmiToDoubleFPURegister(Register smi,
+ FPURegister value,
+ Register scratch1) {
+ sra(scratch1, smi, kSmiTagSize);
+ mtc1(scratch1, value);
+ cvt_d_w(value, value);
+}
+
+
+void MacroAssembler::CallRuntime(const Runtime::Function* f,
+ int num_arguments) {
// All parameters are on the stack. v0 has the return value after call.
// If the expected number of arguments of the runtime function is
@@ -1128,8 +2581,18 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
// should remove this need and make the runtime routine entry code
// smarter.
li(a0, num_arguments);
- LoadExternalReference(a1, ExternalReference(f));
+ li(a1, Operand(ExternalReference(f, isolate())));
+ CEntryStub stub(1);
+ CallStub(&stub);
+}
+
+
+void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
+ const Runtime::Function* function = Runtime::FunctionForId(id);
+ li(a0, Operand(function->nargs));
+ li(a1, Operand(ExternalReference(function, isolate())));
CEntryStub stub(1);
+ stub.SaveDoubles();
CallStub(&stub);
}
@@ -1139,58 +2602,108 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId fid, int num_arguments) {
}
+void MacroAssembler::CallExternalReference(const ExternalReference& ext,
+ int num_arguments) {
+ li(a0, Operand(num_arguments));
+ li(a1, Operand(ext));
+
+ CEntryStub stub(1);
+ CallStub(&stub);
+}
+
+
void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
int num_arguments,
int result_size) {
- UNIMPLEMENTED_MIPS();
+ // TODO(1236192): Most runtime routines don't need the number of
+ // arguments passed in because it is constant. At some point we
+ // should remove this need and make the runtime routine entry code
+ // smarter.
+ li(a0, Operand(num_arguments));
+ JumpToExternalReference(ext);
}
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size) {
- TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
+ TailCallExternalReference(ExternalReference(fid, isolate()),
+ num_arguments,
+ result_size);
}
void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
- UNIMPLEMENTED_MIPS();
+ li(a1, Operand(builtin));
+ CEntryStub stub(1);
+ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
}
-Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
- bool* resolved) {
- UNIMPLEMENTED_MIPS();
- return Handle<Code>(reinterpret_cast<Code*>(NULL)); // UNIMPLEMENTED RETURN
+void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
+ InvokeJSFlags flags,
+ PostCallGenerator* post_call_generator) {
+ GetBuiltinEntry(t9, id);
+ if (flags == CALL_JS) {
+ Call(t9);
+ if (post_call_generator != NULL) post_call_generator->Generate();
+ } else {
+ ASSERT(flags == JUMP_JS);
+ Jump(t9);
+ }
}
-void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
- InvokeJSFlags flags) {
- UNIMPLEMENTED_MIPS();
+void MacroAssembler::GetBuiltinFunction(Register target,
+ Builtins::JavaScript id) {
+ // Load the builtins object into target register.
+ lw(target, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ lw(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
+ // Load the JavaScript builtin function from the builtins object.
+ lw(target, FieldMemOperand(target,
+ JSBuiltinsObject::OffsetOfFunctionWithId(id)));
}
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
- UNIMPLEMENTED_MIPS();
+ ASSERT(!target.is(a1));
+ GetBuiltinFunction(a1, id);
+ // Load the code entry point from the builtins object.
+ lw(target, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
}
void MacroAssembler::SetCounter(StatsCounter* counter, int value,
Register scratch1, Register scratch2) {
- UNIMPLEMENTED_MIPS();
+ if (FLAG_native_code_counters && counter->Enabled()) {
+ li(scratch1, Operand(value));
+ li(scratch2, Operand(ExternalReference(counter)));
+ sw(scratch1, MemOperand(scratch2));
+ }
}
void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
Register scratch1, Register scratch2) {
- UNIMPLEMENTED_MIPS();
+ ASSERT(value > 0);
+ if (FLAG_native_code_counters && counter->Enabled()) {
+ li(scratch2, Operand(ExternalReference(counter)));
+ lw(scratch1, MemOperand(scratch2));
+ Addu(scratch1, scratch1, Operand(value));
+ sw(scratch1, MemOperand(scratch2));
+ }
}
void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
Register scratch1, Register scratch2) {
- UNIMPLEMENTED_MIPS();
+ ASSERT(value > 0);
+ if (FLAG_native_code_counters && counter->Enabled()) {
+ li(scratch2, Operand(ExternalReference(counter)));
+ lw(scratch1, MemOperand(scratch2));
+ Subu(scratch1, scratch1, Operand(value));
+ sw(scratch1, MemOperand(scratch2));
+ }
}
@@ -1199,30 +2712,144 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
void MacroAssembler::Assert(Condition cc, const char* msg,
Register rs, Operand rt) {
- UNIMPLEMENTED_MIPS();
+ if (FLAG_debug_code)
+ Check(cc, msg, rs, rt);
+}
+
+
+void MacroAssembler::AssertRegisterIsRoot(Register reg,
+ Heap::RootListIndex index) {
+ if (FLAG_debug_code) {
+ LoadRoot(at, index);
+ Check(eq, "Register did not match expected root", reg, Operand(at));
+ }
+}
+
+
+void MacroAssembler::AssertFastElements(Register elements) {
+ if (FLAG_debug_code) {
+ ASSERT(!elements.is(at));
+ Label ok;
+ Push(elements);
+ lw(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
+ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+ Branch(&ok, eq, elements, Operand(at));
+ LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex);
+ Branch(&ok, eq, elements, Operand(at));
+ Abort("JSObject with fast elements map has slow elements");
+ bind(&ok);
+ Pop(elements);
+ }
}
void MacroAssembler::Check(Condition cc, const char* msg,
Register rs, Operand rt) {
- UNIMPLEMENTED_MIPS();
+ Label L;
+ Branch(&L, cc, rs, rt);
+ Abort(msg);
+ // will not return here
+ bind(&L);
}
void MacroAssembler::Abort(const char* msg) {
- UNIMPLEMENTED_MIPS();
+ Label abort_start;
+ bind(&abort_start);
+ // We want to pass the msg string like a smi to avoid GC
+ // problems, however msg is not guaranteed to be aligned
+ // properly. Instead, we pass an aligned pointer that is
+ // a proper v8 smi, but also pass the alignment difference
+ // from the real pointer as a smi.
+ intptr_t p1 = reinterpret_cast<intptr_t>(msg);
+ intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
+ ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
+#ifdef DEBUG
+ if (msg != NULL) {
+ RecordComment("Abort message: ");
+ RecordComment(msg);
+ }
+#endif
+ // Disable stub call restrictions to always allow calls to abort.
+ AllowStubCallsScope allow_scope(this, true);
+
+ li(a0, Operand(p0));
+ Push(a0);
+ li(a0, Operand(Smi::FromInt(p1 - p0)));
+ Push(a0);
+ CallRuntime(Runtime::kAbort, 2);
+ // will not return here
+ if (is_trampoline_pool_blocked()) {
+ // If the calling code cares about the exact number of
+ // instructions generated, we insert padding here to keep the size
+ // of the Abort macro constant.
+ // Currently in debug mode with debug_code enabled the number of
+ // generated instructions is 14, so we use this as a maximum value.
+ static const int kExpectedAbortInstructions = 14;
+ int abort_instructions = InstructionsGeneratedSince(&abort_start);
+ ASSERT(abort_instructions <= kExpectedAbortInstructions);
+ while (abort_instructions++ < kExpectedAbortInstructions) {
+ nop();
+ }
+ }
+}
+
+
+void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
+ if (context_chain_length > 0) {
+ // Move up the chain of contexts to the context containing the slot.
+ lw(dst, MemOperand(cp, Context::SlotOffset(Context::CLOSURE_INDEX)));
+ // Load the function context (which is the incoming, outer context).
+ lw(dst, FieldMemOperand(dst, JSFunction::kContextOffset));
+ for (int i = 1; i < context_chain_length; i++) {
+ lw(dst, MemOperand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
+ lw(dst, FieldMemOperand(dst, JSFunction::kContextOffset));
+ }
+ // The context may be an intermediate context, not a function context.
+ lw(dst, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+ } else { // Slot is in the current function context.
+ // The context may be an intermediate context, not a function context.
+ lw(dst, MemOperand(cp, Context::SlotOffset(Context::FCONTEXT_INDEX)));
+ }
+}
+
+
+void MacroAssembler::LoadGlobalFunction(int index, Register function) {
+ // Load the global or builtins object from the current context.
+ lw(function, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ // Load the global context from the global or builtins object.
+ lw(function, FieldMemOperand(function,
+ GlobalObject::kGlobalContextOffset));
+ // Load the function from the global context.
+ lw(function, MemOperand(function, Context::SlotOffset(index)));
+}
+
+
+void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
+ Register map,
+ Register scratch) {
+ // Load the initial map. The global functions all have initial maps.
+ lw(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+ if (FLAG_debug_code) {
+ Label ok, fail;
+ CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false);
+ Branch(&ok);
+ bind(&fail);
+ Abort("Global functions must have initial map");
+ bind(&ok);
+ }
}
void MacroAssembler::EnterFrame(StackFrame::Type type) {
addiu(sp, sp, -5 * kPointerSize);
- li(t0, Operand(Smi::FromInt(type)));
- li(t1, Operand(CodeObject()));
+ li(t8, Operand(Smi::FromInt(type)));
+ li(t9, Operand(CodeObject()));
sw(ra, MemOperand(sp, 4 * kPointerSize));
sw(fp, MemOperand(sp, 3 * kPointerSize));
sw(cp, MemOperand(sp, 2 * kPointerSize));
- sw(t0, MemOperand(sp, 1 * kPointerSize));
- sw(t1, MemOperand(sp, 0 * kPointerSize));
+ sw(t8, MemOperand(sp, 1 * kPointerSize));
+ sw(t9, MemOperand(sp, 0 * kPointerSize));
addiu(fp, sp, 3 * kPointerSize);
}
@@ -1235,62 +2862,98 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
}
-void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode,
- Register hold_argc,
+void MacroAssembler::EnterExitFrame(Register hold_argc,
Register hold_argv,
- Register hold_function) {
- // Compute the argv pointer and keep it in a callee-saved register.
+ Register hold_function,
+ bool save_doubles) {
// a0 is argc.
- sll(t0, a0, kPointerSizeLog2);
- add(hold_argv, sp, t0);
- addi(hold_argv, hold_argv, -kPointerSize);
+ sll(t8, a0, kPointerSizeLog2);
+ addu(hold_argv, sp, t8);
+ addiu(hold_argv, hold_argv, -kPointerSize);
// Compute callee's stack pointer before making changes and save it as
- // t1 register so that it is restored as sp register on exit, thereby
+ // t9 register so that it is restored as sp register on exit, thereby
// popping the args.
- // t1 = sp + kPointerSize * #args
- add(t1, sp, t0);
+ // t9 = sp + kPointerSize * #args
+ addu(t9, sp, t8);
+
+ // Compute the argv pointer and keep it in a callee-saved register.
+ // This only seems to be needed for crankshaft and may cause problems
+ // so it's disabled for now.
+ // Subu(s6, t9, Operand(kPointerSize));
// Align the stack at this point.
AlignStack(0);
// Save registers.
addiu(sp, sp, -12);
- sw(t1, MemOperand(sp, 8));
+ sw(t9, MemOperand(sp, 8));
sw(ra, MemOperand(sp, 4));
sw(fp, MemOperand(sp, 0));
mov(fp, sp); // Setup new frame pointer.
- // Push debug marker.
- if (mode == ExitFrame::MODE_DEBUG) {
- Push(zero_reg);
- } else {
- li(t0, Operand(CodeObject()));
- Push(t0);
- }
+ li(t8, Operand(CodeObject()));
+ Push(t8); // Accessed from ExitFrame::code_slot.
// Save the frame pointer and the context in top.
- LoadExternalReference(t0, ExternalReference(Top::k_c_entry_fp_address));
- sw(fp, MemOperand(t0));
- LoadExternalReference(t0, ExternalReference(Top::k_context_address));
- sw(cp, MemOperand(t0));
+ li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ sw(fp, MemOperand(t8));
+ li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ sw(cp, MemOperand(t8));
// Setup argc and the builtin function in callee-saved registers.
mov(hold_argc, a0);
mov(hold_function, a1);
+
+ // Optionally save all double registers.
+ if (save_doubles) {
+#ifdef DEBUG
+ int frame_alignment = ActivationFrameAlignment();
+#endif
+ // The stack alignment code above made sp unaligned, so add space for one
+ // more double register and use aligned addresses.
+ ASSERT(kDoubleSize == frame_alignment);
+ // Mark the frame as containing doubles by pushing a non-valid return
+ // address, i.e. 0.
+ ASSERT(ExitFrameConstants::kMarkerOffset == -2 * kPointerSize);
+ push(zero_reg); // Marker and alignment word.
+ int space = FPURegister::kNumRegisters * kDoubleSize + kPointerSize;
+ Subu(sp, sp, Operand(space));
+ // Remember: we only need to save every 2nd double FPU value.
+ for (int i = 0; i < FPURegister::kNumRegisters; i+=2) {
+ FPURegister reg = FPURegister::from_code(i);
+ sdc1(reg, MemOperand(sp, i * kDoubleSize + kPointerSize));
+ }
+ // Note that f0 will be accessible at fp - 2*kPointerSize -
+ // FPURegister::kNumRegisters * kDoubleSize, since the code slot and the
+ // alignment word were pushed after the fp.
+ }
}
-void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) {
+void MacroAssembler::LeaveExitFrame(bool save_doubles) {
+ // Optionally restore all double registers.
+ if (save_doubles) {
+ // TODO(regis): Use vldrm instruction.
+ // Remember: we only need to restore every 2nd double FPU value.
+ for (int i = 0; i < FPURegister::kNumRegisters; i+=2) {
+ FPURegister reg = FPURegister::from_code(i);
+ // Register f30-f31 is just below the marker.
+ const int offset = ExitFrameConstants::kMarkerOffset;
+ ldc1(reg, MemOperand(fp,
+ (i - FPURegister::kNumRegisters) * kDoubleSize + offset));
+ }
+ }
+
// Clear top frame.
- LoadExternalReference(t0, ExternalReference(Top::k_c_entry_fp_address));
- sw(zero_reg, MemOperand(t0));
+ li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ sw(zero_reg, MemOperand(t8));
// Restore current context from top and clear it in debug mode.
- LoadExternalReference(t0, ExternalReference(Top::k_context_address));
- lw(cp, MemOperand(t0));
+ li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ lw(cp, MemOperand(t8));
#ifdef DEBUG
- sw(a3, MemOperand(t0));
+ sw(a3, MemOperand(t8));
#endif
// Pop the arguments, restore registers, and return.
@@ -1303,24 +2966,362 @@ void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) {
}
+void MacroAssembler::InitializeNewString(Register string,
+ Register length,
+ Heap::RootListIndex map_index,
+ Register scratch1,
+ Register scratch2) {
+ sll(scratch1, length, kSmiTagSize);
+ LoadRoot(scratch2, map_index);
+ sw(scratch1, FieldMemOperand(string, String::kLengthOffset));
+ li(scratch1, Operand(String::kEmptyHashField));
+ sw(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
+ sw(scratch1, FieldMemOperand(string, String::kHashFieldOffset));
+}
+
+
+int MacroAssembler::ActivationFrameAlignment() {
+#if defined(V8_HOST_ARCH_MIPS)
+ // Running on the real platform. Use the alignment as mandated by the local
+ // environment.
+ // Note: This will break if we ever start generating snapshots on one Mips
+ // platform for another Mips platform with a different alignment.
+ return OS::ActivationFrameAlignment();
+#else // defined(V8_HOST_ARCH_MIPS)
+ // If we are using the simulator then we should always align to the expected
+ // alignment. As the simulator is used to generate snapshots we do not know
+ // if the target platform will need alignment, so this is controlled from a
+ // flag.
+ return FLAG_sim_stack_alignment;
+#endif // defined(V8_HOST_ARCH_MIPS)
+}
+
+
void MacroAssembler::AlignStack(int offset) {
// On MIPS an offset of 0 aligns to 0 modulo 8 bytes,
// and an offset of 1 aligns to 4 modulo 8 bytes.
+#if defined(V8_HOST_ARCH_MIPS)
+ // Running on the real platform. Use the alignment as mandated by the local
+ // environment.
+ // Note: This will break if we ever start generating snapshots on one MIPS
+ // platform for another MIPS platform with a different alignment.
int activation_frame_alignment = OS::ActivationFrameAlignment();
+#else // defined(V8_HOST_ARCH_MIPS)
+ // If we are using the simulator then we should always align to the expected
+ // alignment. As the simulator is used to generate snapshots we do not know
+ // if the target platform will need alignment, so we will always align at
+ // this point here.
+ int activation_frame_alignment = 2 * kPointerSize;
+#endif // defined(V8_HOST_ARCH_MIPS)
if (activation_frame_alignment != kPointerSize) {
// This code needs to be made more general if this assert doesn't hold.
ASSERT(activation_frame_alignment == 2 * kPointerSize);
if (offset == 0) {
- andi(t0, sp, activation_frame_alignment - 1);
- Push(zero_reg, eq, t0, zero_reg);
+ andi(t8, sp, activation_frame_alignment - 1);
+ Push(zero_reg, eq, t8, zero_reg);
} else {
- andi(t0, sp, activation_frame_alignment - 1);
- addiu(t0, t0, -4);
- Push(zero_reg, eq, t0, zero_reg);
+ andi(t8, sp, activation_frame_alignment - 1);
+ addiu(t8, t8, -4);
+ Push(zero_reg, eq, t8, zero_reg);
+ }
+ }
+}
+
+
+
+void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
+ Register reg,
+ Register scratch,
+ Label* not_power_of_two_or_zero) {
+ Subu(scratch, reg, Operand(1));
+ Branch(USE_DELAY_SLOT, not_power_of_two_or_zero, lt,
+ scratch, Operand(zero_reg));
+ and_(at, scratch, reg); // In the delay slot.
+ Branch(not_power_of_two_or_zero, ne, at, Operand(zero_reg));
+}
+
+
+void MacroAssembler::JumpIfNotBothSmi(Register reg1,
+ Register reg2,
+ Label* on_not_both_smi) {
+ STATIC_ASSERT(kSmiTag == 0);
+ ASSERT_EQ(1, kSmiTagMask);
+ or_(at, reg1, reg2);
+ andi(at, at, kSmiTagMask);
+ Branch(on_not_both_smi, ne, at, Operand(zero_reg));
+}
+
+
+void MacroAssembler::JumpIfEitherSmi(Register reg1,
+ Register reg2,
+ Label* on_either_smi) {
+ STATIC_ASSERT(kSmiTag == 0);
+ ASSERT_EQ(1, kSmiTagMask);
+ // Both Smi tags must be 1 (not Smi).
+ and_(at, reg1, reg2);
+ andi(at, at, kSmiTagMask);
+ Branch(on_either_smi, eq, at, Operand(zero_reg));
+}
+
+
+void MacroAssembler::AbortIfSmi(Register object) {
+ STATIC_ASSERT(kSmiTag == 0);
+ andi(at, object, kSmiTagMask);
+ Assert(ne, "Operand is a smi", at, Operand(zero_reg));
+}
+
+
+void MacroAssembler::AbortIfNotSmi(Register object) {
+ STATIC_ASSERT(kSmiTag == 0);
+ andi(at, object, kSmiTagMask);
+ Assert(eq, "Operand is a smi", at, Operand(zero_reg));
+}
+
+
+void MacroAssembler::AbortIfNotRootValue(Register src,
+ Heap::RootListIndex root_value_index,
+ const char* message) {
+ ASSERT(!src.is(at));
+ LoadRoot(at, root_value_index);
+ Assert(eq, message, src, Operand(at));
+}
+
+
+void MacroAssembler::JumpIfNotHeapNumber(Register object,
+ Register heap_number_map,
+ Register scratch,
+ Label* on_not_heap_number) {
+ lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+ Branch(on_not_heap_number, ne, scratch, Operand(heap_number_map));
+}
+
+
+void MacroAssembler::JumpIfNonSmisNotBothSequentialAsciiStrings(
+ Register first,
+ Register second,
+ Register scratch1,
+ Register scratch2,
+ Label* failure) {
+ // Test that both first and second are sequential ASCII strings.
+ // Assume that they are non-smis.
+ lw(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
+ lw(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
+ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
+ lbu(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
+
+ JumpIfBothInstanceTypesAreNotSequentialAscii(scratch1,
+ scratch2,
+ scratch1,
+ scratch2,
+ failure);
+}
+
+
+void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first,
+ Register second,
+ Register scratch1,
+ Register scratch2,
+ Label* failure) {
+ // Check that neither is a smi.
+ STATIC_ASSERT(kSmiTag == 0);
+ And(scratch1, first, Operand(second));
+ And(scratch1, scratch1, Operand(kSmiTagMask));
+ Branch(failure, eq, scratch1, Operand(zero_reg));
+ JumpIfNonSmisNotBothSequentialAsciiStrings(first,
+ second,
+ scratch1,
+ scratch2,
+ failure);
+}
+
+
+void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
+ Register first,
+ Register second,
+ Register scratch1,
+ Register scratch2,
+ Label* failure) {
+ int kFlatAsciiStringMask =
+ kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+ int kFlatAsciiStringTag = ASCII_STRING_TYPE;
+ ASSERT(kFlatAsciiStringTag <= 0xffff); // Ensure this fits 16-bit immed.
+ andi(scratch1, first, kFlatAsciiStringMask);
+ Branch(failure, ne, scratch1, Operand(kFlatAsciiStringTag));
+ andi(scratch2, second, kFlatAsciiStringMask);
+ Branch(failure, ne, scratch2, Operand(kFlatAsciiStringTag));
+}
+
+
+void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(Register type,
+ Register scratch,
+ Label* failure) {
+ int kFlatAsciiStringMask =
+ kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+ int kFlatAsciiStringTag = ASCII_STRING_TYPE;
+ And(scratch, type, Operand(kFlatAsciiStringMask));
+ Branch(failure, ne, scratch, Operand(kFlatAsciiStringTag));
+}
+
+
+static const int kRegisterPassedArguments = 4;
+
+void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
+ int frame_alignment = ActivationFrameAlignment();
+
+ // Reserve space for Isolate address which is always passed as last parameter
+ num_arguments += 1;
+
+ // Up to four simple arguments are passed in registers a0..a3.
+ // Those four arguments must have reserved argument slots on the stack for
+ // mips, even though those argument slots are not normally used.
+ // Remaining arguments are pushed on the stack, above (higher address than)
+ // the argument slots.
+ ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0);
+ int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ?
+ 0 : num_arguments - kRegisterPassedArguments) +
+ (StandardFrameConstants::kCArgsSlotsSize /
+ kPointerSize);
+ if (frame_alignment > kPointerSize) {
+ // Make stack end at alignment and make room for num_arguments - 4 words
+ // and the original value of sp.
+ mov(scratch, sp);
+ Subu(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
+ ASSERT(IsPowerOf2(frame_alignment));
+ And(sp, sp, Operand(-frame_alignment));
+ sw(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
+ } else {
+ Subu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
+ }
+}
+
+
+void MacroAssembler::CallCFunction(ExternalReference function,
+ int num_arguments) {
+ CallCFunctionHelper(no_reg, function, at, num_arguments);
+}
+
+
+void MacroAssembler::CallCFunction(Register function,
+ Register scratch,
+ int num_arguments) {
+ CallCFunctionHelper(function,
+ ExternalReference::the_hole_value_location(isolate()),
+ scratch,
+ num_arguments);
+}
+
+
+void MacroAssembler::CallCFunctionHelper(Register function,
+ ExternalReference function_reference,
+ Register scratch,
+ int num_arguments) {
+ // Push Isolate address as the last argument.
+ if (num_arguments < kRegisterPassedArguments) {
+ Register arg_to_reg[] = {a0, a1, a2, a3};
+ Register r = arg_to_reg[num_arguments];
+ li(r, Operand(ExternalReference::isolate_address()));
+ } else {
+ int stack_passed_arguments = num_arguments - kRegisterPassedArguments +
+ (StandardFrameConstants::kCArgsSlotsSize /
+ kPointerSize);
+ // Push Isolate address on the stack after the arguments.
+ li(scratch, Operand(ExternalReference::isolate_address()));
+ sw(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
+ }
+ num_arguments += 1;
+
+ // Make sure that the stack is aligned before calling a C function unless
+ // running in the simulator. The simulator has its own alignment check which
+ // provides more information.
+ // The argument stots are presumed to have been set up by
+ // PrepareCallCFunction. The C function must be called via t9, for mips ABI.
+
+#if defined(V8_HOST_ARCH_MIPS)
+ if (emit_debug_code()) {
+ int frame_alignment = OS::ActivationFrameAlignment();
+ int frame_alignment_mask = frame_alignment - 1;
+ if (frame_alignment > kPointerSize) {
+ ASSERT(IsPowerOf2(frame_alignment));
+ Label alignment_as_expected;
+ And(at, sp, Operand(frame_alignment_mask));
+ Branch(&alignment_as_expected, eq, at, Operand(zero_reg));
+ // Don't use Check here, as it will call Runtime_Abort possibly
+ // re-entering here.
+ stop("Unexpected alignment in CallCFunction");
+ bind(&alignment_as_expected);
}
}
+#endif // V8_HOST_ARCH_MIPS
+
+ // Just call directly. The function called cannot cause a GC, or
+ // allow preemption, so the return address in the link register
+ // stays correct.
+ if (!function.is(t9)) {
+ mov(t9, function);
+ function = t9;
+ }
+
+ if (function.is(no_reg)) {
+ li(t9, Operand(function_reference));
+ function = t9;
+ }
+
+ Call(function);
+
+ ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0);
+ int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ?
+ 0 : num_arguments - kRegisterPassedArguments) +
+ (StandardFrameConstants::kCArgsSlotsSize /
+ kPointerSize);
+
+ if (OS::ActivationFrameAlignment() > kPointerSize) {
+ lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
+ } else {
+ Addu(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize)));
+ }
}
+
+#undef BRANCH_ARGS_CHECK
+
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+CodePatcher::CodePatcher(byte* address, int instructions)
+ : address_(address),
+ instructions_(instructions),
+ size_(instructions * Assembler::kInstrSize),
+ masm_(address, size_ + Assembler::kGap) {
+ // Create a new macro assembler pointing to the address of the code to patch.
+ // The size is adjusted with kGap on order for the assembler to generate size
+ // bytes of instructions without failing with buffer size constraints.
+ ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
+}
+
+
+CodePatcher::~CodePatcher() {
+ // Indicate that code has changed.
+ CPU::FlushICache(address_, size_);
+
+ // Check that the code was patched as expected.
+ ASSERT(masm_.pc_ == address_ + size_);
+ ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
+}
+
+
+void CodePatcher::Emit(Instr x) {
+ masm()->emit(x);
+}
+
+
+void CodePatcher::Emit(Address addr) {
+ masm()->emit(reinterpret_cast<Instr>(addr));
+}
+
+
+#endif // ENABLE_DEBUGGER_SUPPORT
+
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 0f0365b7..7ff9e17b 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -36,69 +36,171 @@ namespace internal {
// Forward declaration.
class JumpTarget;
+class PostCallGenerator;
-// Register at is used for instruction generation. So it is not safe to use it
-// unless we know exactly what we do.
+// Reserved Register Usage Summary.
+//
+// Registers t8, t9, and at are reserved for use by the MacroAssembler.
+//
+// The programmer should know that the MacroAssembler may clobber these three,
+// but won't touch other registers except in special cases.
+//
+// Per the MIPS ABI, register t9 must be used for indirect function call
+// via 'jalr t9' or 'jr t9' instructions. This is relied upon by gcc when
+// trying to update gp register for position-independent-code. Whenever
+// MIPS generated code calls C code, it must be via t9 register.
// Registers aliases
// cp is assumed to be a callee saved register.
+const Register roots = s6; // Roots array pointer.
const Register cp = s7; // JavaScript context pointer
const Register fp = s8_fp; // Alias fp
+// Register used for condition evaluation.
+const Register condReg1 = s4;
+const Register condReg2 = s5;
enum InvokeJSFlags {
CALL_JS,
JUMP_JS
};
+
+// Flags used for the AllocateInNewSpace functions.
+enum AllocationFlags {
+ // No special flags.
+ NO_ALLOCATION_FLAGS = 0,
+ // Return the pointer to the allocated already tagged as a heap object.
+ TAG_OBJECT = 1 << 0,
+ // The content of the result register already contains the allocation top in
+ // new space.
+ RESULT_CONTAINS_TOP = 1 << 1,
+ // Specify that the requested size of the space to allocate is specified in
+ // words instead of bytes.
+ SIZE_IN_WORDS = 1 << 2
+};
+
+// Flags used for the ObjectToDoubleFPURegister function.
+enum ObjectToDoubleFlags {
+ // No special flags.
+ NO_OBJECT_TO_DOUBLE_FLAGS = 0,
+ // Object is known to be a non smi.
+ OBJECT_NOT_SMI = 1 << 0,
+ // Don't load NaNs or infinities, branch to the non number case instead.
+ AVOID_NANS_AND_INFINITIES = 1 << 1
+};
+
+// Allow programmer to use Branch Delay Slot of Branches, Jumps, Calls.
+enum BranchDelaySlot {
+ USE_DELAY_SLOT,
+ PROTECT
+};
+
// MacroAssembler implements a collection of frequently used macros.
class MacroAssembler: public Assembler {
public:
MacroAssembler(void* buffer, int size);
- // Jump, Call, and Ret pseudo instructions implementing inter-working.
- void Jump(const Operand& target,
- Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void Call(const Operand& target,
- Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void Jump(Register target,
- Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void Jump(byte* target, RelocInfo::Mode rmode,
- Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void Jump(Handle<Code> code, RelocInfo::Mode rmode,
- Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void Call(Register target,
- Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void Call(byte* target, RelocInfo::Mode rmode,
- Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void Call(Handle<Code> code, RelocInfo::Mode rmode,
- Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void Ret(Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void Branch(Condition cond, int16_t offset, Register rs = zero_reg,
- const Operand& rt = Operand(zero_reg), Register scratch = at);
- void Branch(Condition cond, Label* L, Register rs = zero_reg,
- const Operand& rt = Operand(zero_reg), Register scratch = at);
- // conditionnal branch and link
- void BranchAndLink(Condition cond, int16_t offset, Register rs = zero_reg,
- const Operand& rt = Operand(zero_reg),
- Register scratch = at);
- void BranchAndLink(Condition cond, Label* L, Register rs = zero_reg,
- const Operand& rt = Operand(zero_reg),
- Register scratch = at);
+// Arguments macros
+#define COND_TYPED_ARGS Condition cond, Register r1, const Operand& r2
+#define COND_ARGS cond, r1, r2
+
+// ** Prototypes
+
+// * Prototypes for functions with no target (eg Ret()).
+#define DECLARE_NOTARGET_PROTOTYPE(Name) \
+ void Name(BranchDelaySlot bd = PROTECT); \
+ void Name(COND_TYPED_ARGS, BranchDelaySlot bd = PROTECT); \
+ inline void Name(BranchDelaySlot bd, COND_TYPED_ARGS) { \
+ Name(COND_ARGS, bd); \
+ }
+
+// * Prototypes for functions with a target.
+
+// Cases when relocation may be needed.
+#define DECLARE_RELOC_PROTOTYPE(Name, target_type) \
+ void Name(target_type target, \
+ RelocInfo::Mode rmode, \
+ BranchDelaySlot bd = PROTECT); \
+ inline void Name(BranchDelaySlot bd, \
+ target_type target, \
+ RelocInfo::Mode rmode) { \
+ Name(target, rmode, bd); \
+ } \
+ void Name(target_type target, \
+ RelocInfo::Mode rmode, \
+ COND_TYPED_ARGS, \
+ BranchDelaySlot bd = PROTECT); \
+ inline void Name(BranchDelaySlot bd, \
+ target_type target, \
+ RelocInfo::Mode rmode, \
+ COND_TYPED_ARGS) { \
+ Name(target, rmode, COND_ARGS, bd); \
+ }
+
+// Cases when relocation is not needed.
+#define DECLARE_NORELOC_PROTOTYPE(Name, target_type) \
+ void Name(target_type target, BranchDelaySlot bd = PROTECT); \
+ inline void Name(BranchDelaySlot bd, target_type target) { \
+ Name(target, bd); \
+ } \
+ void Name(target_type target, \
+ COND_TYPED_ARGS, \
+ BranchDelaySlot bd = PROTECT); \
+ inline void Name(BranchDelaySlot bd, \
+ target_type target, \
+ COND_TYPED_ARGS) { \
+ Name(target, COND_ARGS, bd); \
+ }
+
+// ** Target prototypes.
+
+#define DECLARE_JUMP_CALL_PROTOTYPES(Name) \
+ DECLARE_NORELOC_PROTOTYPE(Name, Register) \
+ DECLARE_NORELOC_PROTOTYPE(Name, const Operand&) \
+ DECLARE_RELOC_PROTOTYPE(Name, byte*) \
+ DECLARE_RELOC_PROTOTYPE(Name, Handle<Code>)
+
+#define DECLARE_BRANCH_PROTOTYPES(Name) \
+ DECLARE_NORELOC_PROTOTYPE(Name, Label*) \
+ DECLARE_NORELOC_PROTOTYPE(Name, int16_t)
+
+
+DECLARE_JUMP_CALL_PROTOTYPES(Jump)
+DECLARE_JUMP_CALL_PROTOTYPES(Call)
+
+DECLARE_BRANCH_PROTOTYPES(Branch)
+DECLARE_BRANCH_PROTOTYPES(BranchAndLink)
+
+DECLARE_NOTARGET_PROTOTYPE(Ret)
+
+#undef COND_TYPED_ARGS
+#undef COND_ARGS
+#undef DECLARE_NOTARGET_PROTOTYPE
+#undef DECLARE_NORELOC_PROTOTYPE
+#undef DECLARE_RELOC_PROTOTYPE
+#undef DECLARE_JUMP_CALL_PROTOTYPES
+#undef DECLARE_BRANCH_PROTOTYPES
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the sp register.
- void Drop(int count, Condition cond = cc_always);
+ void Drop(int count,
+ Condition cond = cc_always,
+ Register reg = no_reg,
+ const Operand& op = Operand(no_reg));
+
+ void DropAndRet(int drop = 0,
+ Condition cond = cc_always,
+ Register reg = no_reg,
+ const Operand& op = Operand(no_reg));
+
+ // Swap two registers. If the scratch register is omitted then a slightly
+ // less efficient form using xor instead of mov is emitted.
+ void Swap(Register reg1, Register reg2, Register scratch = no_reg);
void Call(Label* target);
+ // May do nothing if the registers are identical.
+ void Move(Register dst, Register src);
+
// Jump unconditionally to given label.
// We NEED a nop in the branch delay slot, as it used by v8, for example in
@@ -106,7 +208,7 @@ class MacroAssembler: public Assembler {
// Currently the branch delay slot is filled by the MacroAssembler.
// Use rather b(Label) for code generation.
void jmp(Label* L) {
- Branch(cc_always, L);
+ Branch(L);
}
// Load an object from the root table.
@@ -116,19 +218,164 @@ class MacroAssembler: public Assembler {
Heap::RootListIndex index,
Condition cond, Register src1, const Operand& src2);
- // Load an external reference.
- void LoadExternalReference(Register reg, ExternalReference ext) {
- li(reg, Operand(ext));
+ // Store an object to the root table.
+ void StoreRoot(Register source,
+ Heap::RootListIndex index);
+ void StoreRoot(Register source,
+ Heap::RootListIndex index,
+ Condition cond, Register src1, const Operand& src2);
+
+
+ // Check if object is in new space.
+ // scratch can be object itself, but it will be clobbered.
+ void InNewSpace(Register object,
+ Register scratch,
+ Condition cc, // eq for new space, ne otherwise.
+ Label* branch);
+
+
+ // For the page containing |object| mark the region covering [address]
+ // dirty. The object address must be in the first 8K of an allocated page.
+ void RecordWriteHelper(Register object,
+ Register address,
+ Register scratch);
+
+ // For the page containing |object| mark the region covering
+ // [object+offset] dirty. The object address must be in the first 8K
+ // of an allocated page. The 'scratch' registers are used in the
+ // implementation and all 3 registers are clobbered by the
+ // operation, as well as the 'at' register. RecordWrite updates the
+ // write barrier even when storing smis.
+ void RecordWrite(Register object,
+ Operand offset,
+ Register scratch0,
+ Register scratch1);
+
+ // For the page containing |object| mark the region covering
+ // [address] dirty. The object address must be in the first 8K of an
+ // allocated page. All 3 registers are clobbered by the operation,
+ // as well as the ip register. RecordWrite updates the write barrier
+ // even when storing smis.
+ void RecordWrite(Register object,
+ Register address,
+ Register scratch);
+
+
+ // ---------------------------------------------------------------------------
+ // Inline caching support
+
+ // Generate code for checking access rights - used for security checks
+ // on access to global objects across environments. The holder register
+ // is left untouched, whereas both scratch registers are clobbered.
+ void CheckAccessGlobalProxy(Register holder_reg,
+ Register scratch,
+ Label* miss);
+
+ inline void MarkCode(NopMarkerTypes type) {
+ nop(type);
+ }
+
+ // Check if the given instruction is a 'type' marker.
+ // ie. check if it is a sll zero_reg, zero_reg, <type> (referenced as
+ // nop(type)). These instructions are generated to mark special location in
+ // the code, like some special IC code.
+ static inline bool IsMarkedCode(Instr instr, int type) {
+ ASSERT((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
+ return IsNop(instr, type);
+ }
+
+
+ static inline int GetCodeMarker(Instr instr) {
+ uint32_t opcode = ((instr & kOpcodeMask));
+ uint32_t rt = ((instr & kRtFieldMask) >> kRtShift);
+ uint32_t rs = ((instr & kRsFieldMask) >> kRsShift);
+ uint32_t sa = ((instr & kSaFieldMask) >> kSaShift);
+
+ // Return <n> if we have a sll zero_reg, zero_reg, n
+ // else return -1.
+ bool sllzz = (opcode == SLL &&
+ rt == static_cast<uint32_t>(ToNumber(zero_reg)) &&
+ rs == static_cast<uint32_t>(ToNumber(zero_reg)));
+ int type =
+ (sllzz && FIRST_IC_MARKER <= sa && sa < LAST_CODE_MARKER) ? sa : -1;
+ ASSERT((type == -1) ||
+ ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
+ return type;
}
- // Sets the remembered set bit for [address+offset].
- void RecordWrite(Register object, Register offset, Register scratch);
// ---------------------------------------------------------------------------
+ // Allocation support
+
+ // Allocate an object in new space. The object_size is specified
+ // either in bytes or in words if the allocation flag SIZE_IN_WORDS
+ // is passed. If the new space is exhausted control continues at the
+ // gc_required label. The allocated object is returned in result. If
+ // the flag tag_allocated_object is true the result is tagged as as
+ // a heap object. All registers are clobbered also when control
+ // continues at the gc_required label.
+ void AllocateInNewSpace(int object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ AllocationFlags flags);
+ void AllocateInNewSpace(Register object_size,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ AllocationFlags flags);
+
+ // Undo allocation in new space. The object passed and objects allocated after
+ // it will no longer be allocated. The caller must make sure that no pointers
+ // are left to the object(s) no longer allocated as they would be invalid when
+ // allocation is undone.
+ void UndoAllocationInNewSpace(Register object, Register scratch);
+
+
+ void AllocateTwoByteString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* gc_required);
+ void AllocateAsciiString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* gc_required);
+ void AllocateTwoByteConsString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+ void AllocateAsciiConsString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+
+ // Allocates a heap number or jumps to the gc_required label if the young
+ // space is full and a scavenge is needed. All registers are clobbered also
+ // when control continues at the gc_required label.
+ void AllocateHeapNumber(Register result,
+ Register scratch1,
+ Register scratch2,
+ Register heap_number_map,
+ Label* gc_required);
+ void AllocateHeapNumberWithValue(Register result,
+ FPURegister value,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+
+ // ---------------------------------------------------------------------------
// Instruction macros
-#define DEFINE_INSTRUCTION(instr) \
+#define DEFINE_INSTRUCTION(instr) \
void instr(Register rd, Register rs, const Operand& rt); \
void instr(Register rd, Register rs, Register rt) { \
instr(rd, rs, Operand(rt)); \
@@ -137,7 +384,7 @@ class MacroAssembler: public Assembler {
instr(rs, rt, Operand(j)); \
}
-#define DEFINE_INSTRUCTION2(instr) \
+#define DEFINE_INSTRUCTION2(instr) \
void instr(Register rs, const Operand& rt); \
void instr(Register rs, Register rt) { \
instr(rs, Operand(rt)); \
@@ -146,8 +393,8 @@ class MacroAssembler: public Assembler {
instr(rs, Operand(j)); \
}
- DEFINE_INSTRUCTION(Add);
DEFINE_INSTRUCTION(Addu);
+ DEFINE_INSTRUCTION(Subu);
DEFINE_INSTRUCTION(Mul);
DEFINE_INSTRUCTION2(Mult);
DEFINE_INSTRUCTION2(Multu);
@@ -162,6 +409,9 @@ class MacroAssembler: public Assembler {
DEFINE_INSTRUCTION(Slt);
DEFINE_INSTRUCTION(Sltu);
+ // MIPS32 R2 instruction macro.
+ DEFINE_INSTRUCTION(Ror);
+
#undef DEFINE_INSTRUCTION
#undef DEFINE_INSTRUCTION2
@@ -169,8 +419,6 @@ class MacroAssembler: public Assembler {
//------------Pseudo-instructions-------------
void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); }
- // Move the logical ones complement of source to dest.
- void movn(Register rd, Register rt);
// load int32 in the rd register
@@ -178,6 +426,9 @@ class MacroAssembler: public Assembler {
inline void li(Register rd, int32_t j, bool gen2instr = false) {
li(rd, Operand(j), gen2instr);
}
+ inline void li(Register dst, Handle<Object> value, bool gen2instr = false) {
+ li(dst, Operand(value), gen2instr);
+ }
// Exception-generating instructions and debugging support
void stop(const char* msg);
@@ -188,19 +439,51 @@ class MacroAssembler: public Assembler {
// saved in higher memory addresses
void MultiPush(RegList regs);
void MultiPushReversed(RegList regs);
+
void Push(Register src) {
Addu(sp, sp, Operand(-kPointerSize));
sw(src, MemOperand(sp, 0));
}
+
+ // Push two registers. Pushes leftmost register first (to highest address).
+ void Push(Register src1, Register src2, Condition cond = al) {
+ ASSERT(cond == al); // Do not support conditional versions yet.
+ Subu(sp, sp, Operand(2 * kPointerSize));
+ sw(src1, MemOperand(sp, 1 * kPointerSize));
+ sw(src2, MemOperand(sp, 0 * kPointerSize));
+ }
+
+ // Push three registers. Pushes leftmost register first (to highest address).
+ void Push(Register src1, Register src2, Register src3, Condition cond = al) {
+ ASSERT(cond == al); // Do not support conditional versions yet.
+ Addu(sp, sp, Operand(3 * -kPointerSize));
+ sw(src1, MemOperand(sp, 2 * kPointerSize));
+ sw(src2, MemOperand(sp, 1 * kPointerSize));
+ sw(src3, MemOperand(sp, 0 * kPointerSize));
+ }
+
+ // Push four registers. Pushes leftmost register first (to highest address).
+ void Push(Register src1, Register src2,
+ Register src3, Register src4, Condition cond = al) {
+ ASSERT(cond == al); // Do not support conditional versions yet.
+ Addu(sp, sp, Operand(4 * -kPointerSize));
+ sw(src1, MemOperand(sp, 3 * kPointerSize));
+ sw(src2, MemOperand(sp, 2 * kPointerSize));
+ sw(src3, MemOperand(sp, 1 * kPointerSize));
+ sw(src4, MemOperand(sp, 0 * kPointerSize));
+ }
+
inline void push(Register src) { Push(src); }
+ inline void pop(Register src) { Pop(src); }
void Push(Register src, Condition cond, Register tst1, Register tst2) {
// Since we don't have conditionnal execution we use a Branch.
- Branch(cond, 3, tst1, Operand(tst2));
+ Branch(3, cond, tst1, Operand(tst2));
Addu(sp, sp, Operand(-kPointerSize));
sw(src, MemOperand(sp, 0));
}
+
// Pops multiple values from the stack and load them in the
// registers specified in regs. Pop order is the opposite as in MultiPush.
void MultiPop(RegList regs);
@@ -209,44 +492,108 @@ class MacroAssembler: public Assembler {
lw(dst, MemOperand(sp, 0));
Addu(sp, sp, Operand(kPointerSize));
}
- void Pop() {
- Add(sp, sp, Operand(kPointerSize));
+ void Pop(uint32_t count = 1) {
+ Addu(sp, sp, Operand(count * kPointerSize));
+ }
+
+ // ---------------------------------------------------------------------------
+ // These functions are only used by crankshaft, so they are currently
+ // unimplemented.
+
+ // Push and pop the registers that can hold pointers, as defined by the
+ // RegList constant kSafepointSavedRegisters.
+ void PushSafepointRegisters() {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ void PopSafepointRegisters() {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ void PushSafepointRegistersAndDoubles() {
+ UNIMPLEMENTED_MIPS();
}
+ void PopSafepointRegistersAndDoubles() {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ static int SafepointRegisterStackIndex(int reg_code) {
+ UNIMPLEMENTED_MIPS();
+ return 0;
+ }
// ---------------------------------------------------------------------------
+
+ // MIPS32 R2 instruction macro.
+ void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
+ void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
+
+ // Convert unsigned word to double.
+ void Cvt_d_uw(FPURegister fd, FPURegister fs);
+ void Cvt_d_uw(FPURegister fd, Register rs);
+
+ // Convert double to unsigned word.
+ void Trunc_uw_d(FPURegister fd, FPURegister fs);
+ void Trunc_uw_d(FPURegister fd, Register rs);
+
+ // Convert the HeapNumber pointed to by source to a 32bits signed integer
+ // dest. If the HeapNumber does not fit into a 32bits signed integer branch
+ // to not_int32 label. If FPU is available double_scratch is used but not
+ // scratch2.
+ void ConvertToInt32(Register source,
+ Register dest,
+ Register scratch,
+ Register scratch2,
+ FPURegister double_scratch,
+ Label *not_int32);
+
+ // -------------------------------------------------------------------------
// Activation frames
void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
- // Enter specific kind of exit frame; either EXIT or
- // EXIT_DEBUG. Expects the number of arguments in register a0 and
+ void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
+ void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
+
+ // Enter exit frame.
+ // Expects the number of arguments in register a0 and
// the builtin function to call in register a1.
// On output hold_argc, hold_function, and hold_argv are setup.
- void EnterExitFrame(ExitFrame::Mode mode,
- Register hold_argc,
+ void EnterExitFrame(Register hold_argc,
Register hold_argv,
- Register hold_function);
+ Register hold_function,
+ bool save_doubles);
// Leave the current exit frame. Expects the return value in v0.
- void LeaveExitFrame(ExitFrame::Mode mode);
+ void LeaveExitFrame(bool save_doubles);
// Align the stack by optionally pushing a Smi zero.
- void AlignStack(int offset);
+ void AlignStack(int offset); // TODO(mips) : remove this function.
- void SetupAlignedCall(Register scratch, int arg_count = 0);
- void ReturnFromAlignedCall();
+ // Get the actual activation frame alignment for target environment.
+ static int ActivationFrameAlignment();
+ void LoadContext(Register dst, int context_chain_length);
- // ---------------------------------------------------------------------------
+ void LoadGlobalFunction(int index, Register function);
+
+ // Load the initial map from the global function. The registers
+ // function and map can be the same, function is then overwritten.
+ void LoadGlobalFunctionInitialMap(Register function,
+ Register map,
+ Register scratch);
+
+ // -------------------------------------------------------------------------
// JavaScript invokes
// Invoke the JavaScript function code by either calling or jumping.
void InvokeCode(Register code,
const ParameterCount& expected,
const ParameterCount& actual,
- InvokeFlag flag);
+ InvokeFlag flag,
+ PostCallGenerator* post_call_generator = NULL);
void InvokeCode(Handle<Code> code,
const ParameterCount& expected,
@@ -258,84 +605,135 @@ class MacroAssembler: public Assembler {
// current context to the context in the function before invoking.
void InvokeFunction(Register function,
const ParameterCount& actual,
+ InvokeFlag flag,
+ PostCallGenerator* post_call_generator = NULL);
+
+ void InvokeFunction(JSFunction* function,
+ const ParameterCount& actual,
InvokeFlag flag);
+ void IsObjectJSObjectType(Register heap_object,
+ Register map,
+ Register scratch,
+ Label* fail);
+
+ void IsInstanceJSObjectType(Register map,
+ Register scratch,
+ Label* fail);
+
+ void IsObjectJSStringType(Register object,
+ Register scratch,
+ Label* fail);
+
#ifdef ENABLE_DEBUGGER_SUPPORT
- // ---------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
// Debugger Support
- void SaveRegistersToMemory(RegList regs);
- void RestoreRegistersFromMemory(RegList regs);
- void CopyRegistersFromMemoryToStack(Register base, RegList regs);
- void CopyRegistersFromStackToMemory(Register base,
- Register scratch,
- RegList regs);
void DebugBreak();
#endif
- // ---------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
// Exception handling
// Push a new try handler and link into try handler chain.
// The return address must be passed in register ra.
+ // Clobber t0, t1, t2.
void PushTryHandler(CodeLocation try_location, HandlerType type);
// Unlink the stack handler on top of the stack from the try handler chain.
// Must preserve the result register.
void PopTryHandler();
+ // Copies a fixed number of fields of heap objects from src to dst.
+ void CopyFields(Register dst, Register src, RegList temps, int field_count);
- // ---------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
// Support functions.
+ // Try to get function prototype of a function and puts the value in
+ // the result register. Checks that the function really is a
+ // function and jumps to the miss label if the fast checks fail. The
+ // function register will be untouched; the other registers may be
+ // clobbered.
+ void TryGetFunctionPrototype(Register function,
+ Register result,
+ Register scratch,
+ Label* miss);
+
void GetObjectType(Register function,
Register map,
Register type_reg);
- inline void BranchOnSmi(Register value, Label* smi_label,
- Register scratch = at) {
- ASSERT_EQ(0, kSmiTag);
- andi(scratch, value, kSmiTagMask);
- Branch(eq, smi_label, scratch, Operand(zero_reg));
- }
-
-
- inline void BranchOnNotSmi(Register value, Label* not_smi_label,
- Register scratch = at) {
- ASSERT_EQ(0, kSmiTag);
- andi(scratch, value, kSmiTagMask);
- Branch(ne, not_smi_label, scratch, Operand(zero_reg));
- }
-
- void CallBuiltin(ExternalReference builtin_entry);
- void CallBuiltin(Register target);
- void JumpToBuiltin(ExternalReference builtin_entry);
- void JumpToBuiltin(Register target);
+ // Check if the map of an object is equal to a specified map (either
+ // given directly or as an index into the root list) and branch to
+ // label if not. Skip the smi check if not required (object is known
+ // to be a heap object)
+ void CheckMap(Register obj,
+ Register scratch,
+ Handle<Map> map,
+ Label* fail,
+ bool is_heap_object);
+
+ void CheckMap(Register obj,
+ Register scratch,
+ Heap::RootListIndex index,
+ Label* fail,
+ bool is_heap_object);
// Generates code for reporting that an illegal operation has
// occurred.
void IllegalOperation(int num_arguments);
-
- // ---------------------------------------------------------------------------
+ // Picks out an array index from the hash field.
+ // Register use:
+ // hash - holds the index's hash. Clobbered.
+ // index - holds the overwritten index on exit.
+ void IndexFromHash(Register hash, Register index);
+
+ // Load the value of a number object into a FPU double register. If the
+ // object is not a number a jump to the label not_number is performed
+ // and the FPU double register is unchanged.
+ void ObjectToDoubleFPURegister(
+ Register object,
+ FPURegister value,
+ Register scratch1,
+ Register scratch2,
+ Register heap_number_map,
+ Label* not_number,
+ ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS);
+
+ // Load the value of a smi object into a FPU double register. The register
+ // scratch1 can be the same register as smi in which case smi will hold the
+ // untagged value afterwards.
+ void SmiToDoubleFPURegister(Register smi,
+ FPURegister value,
+ Register scratch1);
+
+ // -------------------------------------------------------------------------
// Runtime calls
// Call a code stub.
void CallStub(CodeStub* stub, Condition cond = cc_always,
Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
- void CallJSExitStub(CodeStub* stub);
- // Return from a code stub after popping its arguments.
- void StubReturn(int argc);
+ // Tail call a code stub (jump).
+ void TailCallStub(CodeStub* stub);
+
+ void CallJSExitStub(CodeStub* stub);
// Call a runtime routine.
- void CallRuntime(Runtime::Function* f, int num_arguments);
+ void CallRuntime(const Runtime::Function* f, int num_arguments);
+ void CallRuntimeSaveDoubles(Runtime::FunctionId id);
// Convenience function: Same as above, but takes the fid instead.
void CallRuntime(Runtime::FunctionId fid, int num_arguments);
+ // Convenience function: call an external reference.
+ void CallExternalReference(const ExternalReference& ext,
+ int num_arguments);
+
// Tail call of a runtime routine (jump).
// Like JumpToExternalReference, but also takes care of passing the number
// of parameters.
@@ -348,34 +746,54 @@ class MacroAssembler: public Assembler {
int num_arguments,
int result_size);
+ // Before calling a C-function from generated code, align arguments on stack
+ // and add space for the four mips argument slots.
+ // After aligning the frame, non-register arguments must be stored on the
+ // stack, after the argument-slots using helper: CFunctionArgumentOperand().
+ // The argument count assumes all arguments are word sized.
+ // Some compilers/platforms require the stack to be aligned when calling
+ // C++ code.
+ // Needs a scratch register to do some arithmetic. This register will be
+ // trashed.
+ void PrepareCallCFunction(int num_arguments, Register scratch);
+
+ // Arguments 1-4 are placed in registers a0 thru a3 respectively.
+ // Arguments 5..n are stored to stack using following:
+ // sw(t0, CFunctionArgumentOperand(5));
+
+ // Calls a C function and cleans up the space for arguments allocated
+ // by PrepareCallCFunction. The called function is not allowed to trigger a
+ // garbage collection, since that might move the code and invalidate the
+ // return address (unless this is somehow accounted for by the called
+ // function).
+ void CallCFunction(ExternalReference function, int num_arguments);
+ void CallCFunction(Register function, Register scratch, int num_arguments);
+
// Jump to the builtin routine.
void JumpToExternalReference(const ExternalReference& builtin);
// Invoke specified builtin JavaScript function. Adds an entry to
// the unresolved list if the name does not resolve.
- void InvokeBuiltin(Builtins::JavaScript id, InvokeJSFlags flags);
+ void InvokeBuiltin(Builtins::JavaScript id,
+ InvokeJSFlags flags,
+ PostCallGenerator* post_call_generator = NULL);
// Store the code object for the given builtin in the target register and
- // setup the function in r1.
+ // setup the function in a1.
void GetBuiltinEntry(Register target, Builtins::JavaScript id);
+ // Store the function for the given builtin in the target register.
+ void GetBuiltinFunction(Register target, Builtins::JavaScript id);
+
struct Unresolved {
int pc;
uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders.
const char* name;
};
- List<Unresolved>* unresolved() { return &unresolved_; }
Handle<Object> CodeObject() { return code_object_; }
-
- // ---------------------------------------------------------------------------
- // Stack limit support
-
- void StackLimitCheck(Label* on_stack_limit_hit);
-
-
- // ---------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
// StatsCounter support
void SetCounter(StatsCounter* counter, int value,
@@ -386,12 +804,14 @@ class MacroAssembler: public Assembler {
Register scratch1, Register scratch2);
- // ---------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
// Debugging
// Calls Abort(msg) if the condition cc is not satisfied.
// Use --debug_code to enable.
void Assert(Condition cc, const char* msg, Register rs, Operand rt);
+ void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index);
+ void AssertFastElements(Register elements);
// Like Assert(), but always enabled.
void Check(Condition cc, const char* msg, Register rs, Operand rt);
@@ -405,17 +825,132 @@ class MacroAssembler: public Assembler {
void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
bool allow_stub_calls() { return allow_stub_calls_; }
+ // ---------------------------------------------------------------------------
+ // Number utilities
+
+ // Check whether the value of reg is a power of two and not zero. If not
+ // control continues at the label not_power_of_two. If reg is a power of two
+ // the register scratch contains the value of (reg - 1) when control falls
+ // through.
+ void JumpIfNotPowerOfTwoOrZero(Register reg,
+ Register scratch,
+ Label* not_power_of_two_or_zero);
+
+ // -------------------------------------------------------------------------
+ // Smi utilities
+
+ // Try to convert int32 to smi. If the value is to large, preserve
+ // the original value and jump to not_a_smi. Destroys scratch and
+ // sets flags.
+ // This is only used by crankshaft atm so it is unimplemented on MIPS.
+ void TrySmiTag(Register reg, Label* not_a_smi, Register scratch) {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ void SmiTag(Register reg) {
+ Addu(reg, reg, reg);
+ }
+
+ void SmiTag(Register dst, Register src) {
+ Addu(dst, src, src);
+ }
+
+ void SmiUntag(Register reg) {
+ sra(reg, reg, kSmiTagSize);
+ }
+
+ void SmiUntag(Register dst, Register src) {
+ sra(dst, src, kSmiTagSize);
+ }
+
+ // Jump the register contains a smi.
+ inline void JumpIfSmi(Register value, Label* smi_label,
+ Register scratch = at) {
+ ASSERT_EQ(0, kSmiTag);
+ andi(scratch, value, kSmiTagMask);
+ Branch(smi_label, eq, scratch, Operand(zero_reg));
+ }
+
+ // Jump if the register contains a non-smi.
+ inline void JumpIfNotSmi(Register value, Label* not_smi_label,
+ Register scratch = at) {
+ ASSERT_EQ(0, kSmiTag);
+ andi(scratch, value, kSmiTagMask);
+ Branch(not_smi_label, ne, scratch, Operand(zero_reg));
+ }
+
+ // Jump if either of the registers contain a non-smi.
+ void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
+ // Jump if either of the registers contain a smi.
+ void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
+
+ // Abort execution if argument is a smi. Used in debug code.
+ void AbortIfSmi(Register object);
+ void AbortIfNotSmi(Register object);
+
+ // Abort execution if argument is not the root value with the given index.
+ void AbortIfNotRootValue(Register src,
+ Heap::RootListIndex root_value_index,
+ const char* message);
+
+ // ---------------------------------------------------------------------------
+ // HeapNumber utilities
+
+ void JumpIfNotHeapNumber(Register object,
+ Register heap_number_map,
+ Register scratch,
+ Label* on_not_heap_number);
+
+ // -------------------------------------------------------------------------
+ // String utilities
+
+ // Checks if both instance types are sequential ASCII strings and jumps to
+ // label if either is not.
+ void JumpIfBothInstanceTypesAreNotSequentialAscii(
+ Register first_object_instance_type,
+ Register second_object_instance_type,
+ Register scratch1,
+ Register scratch2,
+ Label* failure);
+
+ // Check if instance type is sequential ASCII string and jump to label if
+ // it is not.
+ void JumpIfInstanceTypeIsNotSequentialAscii(Register type,
+ Register scratch,
+ Label* failure);
+
+ // Test that both first and second are sequential ASCII strings.
+ // Assume that they are non-smis.
+ void JumpIfNonSmisNotBothSequentialAsciiStrings(Register first,
+ Register second,
+ Register scratch1,
+ Register scratch2,
+ Label* failure);
+
+ // Test that both first and second are sequential ASCII strings.
+ // Check that they are non-smis.
+ void JumpIfNotBothSequentialAsciiStrings(Register first,
+ Register second,
+ Register scratch1,
+ Register scratch2,
+ Label* failure);
+
private:
- List<Unresolved> unresolved_;
- bool generating_stub_;
- bool allow_stub_calls_;
- // This handle will be patched with the code object on installation.
- Handle<Object> code_object_;
+ void CallCFunctionHelper(Register function,
+ ExternalReference function_reference,
+ Register scratch,
+ int num_arguments);
+ void Jump(intptr_t target, RelocInfo::Mode rmode,
+ BranchDelaySlot bd = PROTECT);
void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
+ Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg),
+ BranchDelaySlot bd = PROTECT);
+ void Call(intptr_t target, RelocInfo::Mode rmode,
+ BranchDelaySlot bd = PROTECT);
void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = cc_always,
- Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
+ Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg),
+ BranchDelaySlot bd = PROTECT);
// Helper functions for generating invokes.
void InvokePrologue(const ParameterCount& expected,
@@ -423,22 +958,84 @@ class MacroAssembler: public Assembler {
Handle<Code> code_constant,
Register code_reg,
Label* done,
- InvokeFlag flag);
+ InvokeFlag flag,
+ PostCallGenerator* post_call_generator = NULL);
// Get the code for the given builtin. Returns if able to resolve
// the function in the 'resolved' flag.
Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
// Activation support.
- // EnterFrame clobbers t0 and t1.
void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type);
+
+ void InitializeNewString(Register string,
+ Register length,
+ Heap::RootListIndex map_index,
+ Register scratch1,
+ Register scratch2);
+
+
+ bool generating_stub_;
+ bool allow_stub_calls_;
+ // This handle will be patched with the code object on installation.
+ Handle<Object> code_object_;
+};
+
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+// The code patcher is used to patch (typically) small parts of code e.g. for
+// debugging and other types of instrumentation. When using the code patcher
+// the exact number of bytes specified must be emitted. It is not legal to emit
+// relocation information. If any of these constraints are violated it causes
+// an assertion to fail.
+class CodePatcher {
+ public:
+ CodePatcher(byte* address, int instructions);
+ virtual ~CodePatcher();
+
+ // Macro assembler to emit code.
+ MacroAssembler* masm() { return &masm_; }
+
+ // Emit an instruction directly.
+ void Emit(Instr x);
+
+ // Emit an address directly.
+ void Emit(Address addr);
+
+ private:
+ byte* address_; // The address of the code being patched.
+ int instructions_; // Number of instructions of the expected patch size.
+ int size_; // Number of bytes of the expected patch size.
+ MacroAssembler masm_; // Macro assembler used to generate the code.
+};
+#endif // ENABLE_DEBUGGER_SUPPORT
+
+
+// Helper class for generating code or data associated with the code
+// right after a call instruction. As an example this can be used to
+// generate safepoint data after calls for crankshaft.
+class PostCallGenerator {
+ public:
+ PostCallGenerator() { }
+ virtual ~PostCallGenerator() { }
+ virtual void Generate() = 0;
};
// -----------------------------------------------------------------------------
// Static helper functions.
+static MemOperand ContextOperand(Register context, int index) {
+ return MemOperand(context, Context::SlotOffset(index));
+}
+
+
+static inline MemOperand GlobalObjectOperand() {
+ return ContextOperand(cp, Context::GLOBAL_INDEX);
+}
+
+
// Generate a MemOperand for loading a field from an object.
static inline MemOperand FieldMemOperand(Register object, int offset) {
return MemOperand(object, offset - kHeapObjectTag);
diff --git a/src/mips/regexp-macro-assembler-mips.cc b/src/mips/regexp-macro-assembler-mips.cc
new file mode 100644
index 00000000..d1dbc435
--- /dev/null
+++ b/src/mips/regexp-macro-assembler-mips.cc
@@ -0,0 +1,478 @@
+// Copyright 2006-2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#if defined(V8_TARGET_ARCH_MIPS)
+
+#include "unicode.h"
+#include "log.h"
+#include "code-stubs.h"
+#include "regexp-stack.h"
+#include "macro-assembler.h"
+#include "regexp-macro-assembler.h"
+#include "mips/regexp-macro-assembler-mips.h"
+
+namespace v8 {
+namespace internal {
+
+#ifndef V8_INTERPRETED_REGEXP
+/*
+ * This assembler uses the following register assignment convention
+ * - t1 : Pointer to current code object (Code*) including heap object tag.
+ * - t2 : Current position in input, as negative offset from end of string.
+ * Please notice that this is the byte offset, not the character offset!
+ * - t3 : Currently loaded character. Must be loaded using
+ * LoadCurrentCharacter before using any of the dispatch methods.
+ * - t4 : points to tip of backtrack stack
+ * - t5 : Unused.
+ * - t6 : End of input (points to byte after last character in input).
+ * - fp : Frame pointer. Used to access arguments, local variables and
+ * RegExp registers.
+ * - sp : points to tip of C stack.
+ *
+ * The remaining registers are free for computations.
+ *
+ * Each call to a public method should retain this convention.
+ * The stack will have the following structure:
+ * - direct_call (if 1, direct call from JavaScript code, if 0 call
+ * through the runtime system)
+ * - stack_area_base (High end of the memory area to use as
+ * backtracking stack)
+ * - int* capture_array (int[num_saved_registers_], for output).
+ * - stack frame header (16 bytes in size)
+ * --- sp when called ---
+ * - link address
+ * - backup of registers s0..s7
+ * - end of input (Address of end of string)
+ * - start of input (Address of first character in string)
+ * - start index (character index of start)
+ * --- frame pointer ----
+ * - void* input_string (location of a handle containing the string)
+ * - Offset of location before start of input (effectively character
+ * position -1). Used to initialize capture registers to a non-position.
+ * - At start (if 1, we are starting at the start of the
+ * string, otherwise 0)
+ * - register 0 (Only positions must be stored in the first
+ * - register 1 num_saved_registers_ registers)
+ * - ...
+ * - register num_registers-1
+ * --- sp ---
+ *
+ * The first num_saved_registers_ registers are initialized to point to
+ * "character -1" in the string (i.e., char_size() bytes before the first
+ * character of the string). The remaining registers start out as garbage.
+ *
+ * The data up to the return address must be placed there by the calling
+ * code, by calling the code entry as cast to a function with the signature:
+ * int (*match)(String* input_string,
+ * int start_index,
+ * Address start,
+ * Address end,
+ * int* capture_output_array,
+ * bool at_start,
+ * byte* stack_area_base,
+ * bool direct_call)
+ * The call is performed by NativeRegExpMacroAssembler::Execute()
+ * (in regexp-macro-assembler.cc).
+ */
+
+#define __ ACCESS_MASM(masm_)
+
+RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(
+ Mode mode,
+ int registers_to_save)
+ : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
+ mode_(mode),
+ num_registers_(registers_to_save),
+ num_saved_registers_(registers_to_save),
+ entry_label_(),
+ start_label_(),
+ success_label_(),
+ backtrack_label_(),
+ exit_label_() {
+ ASSERT_EQ(0, registers_to_save % 2);
+ __ jmp(&entry_label_); // We'll write the entry code later.
+ __ bind(&start_label_); // And then continue from here.
+}
+
+
+RegExpMacroAssemblerMIPS::~RegExpMacroAssemblerMIPS() {
+ delete masm_;
+ // Unuse labels in case we throw away the assembler without calling GetCode.
+ entry_label_.Unuse();
+ start_label_.Unuse();
+ success_label_.Unuse();
+ backtrack_label_.Unuse();
+ exit_label_.Unuse();
+ check_preempt_label_.Unuse();
+ stack_overflow_label_.Unuse();
+}
+
+
+int RegExpMacroAssemblerMIPS::stack_limit_slack() {
+ return RegExpStack::kStackLimitSlack;
+}
+
+
+void RegExpMacroAssemblerMIPS::AdvanceCurrentPosition(int by) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::AdvanceRegister(int reg, int by) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::Backtrack() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::Bind(Label* label) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckCharacter(uint32_t c, Label* on_equal) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckCharacters(Vector<const uc16> str,
+ int cp_offset,
+ Label* on_failure,
+ bool check_end_of_string) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckGreedyLoop(Label* on_equal) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
+ int start_reg,
+ Label* on_no_match) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckNotBackReference(
+ int start_reg,
+ Label* on_no_match) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckNotRegistersEqual(int reg1,
+ int reg2,
+ Label* on_not_equal) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckNotCharacter(uint32_t c,
+ Label* on_not_equal) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckCharacterAfterAnd(uint32_t c,
+ uint32_t mask,
+ Label* on_equal) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterAnd(uint32_t c,
+ uint32_t mask,
+ Label* on_not_equal) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterMinusAnd(
+ uc16 c,
+ uc16 minus,
+ uc16 mask,
+ Label* on_not_equal) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+bool RegExpMacroAssemblerMIPS::CheckSpecialCharacterClass(uc16 type,
+ Label* on_no_match) {
+ UNIMPLEMENTED_MIPS();
+ return false;
+}
+
+
+void RegExpMacroAssemblerMIPS::Fail() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+Handle<Object> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
+ UNIMPLEMENTED_MIPS();
+ return Handle<Object>::null();
+}
+
+
+void RegExpMacroAssemblerMIPS::GoTo(Label* to) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::IfRegisterGE(int reg,
+ int comparand,
+ Label* if_ge) {
+ __ lw(a0, register_location(reg));
+ BranchOrBacktrack(if_ge, ge, a0, Operand(comparand));
+}
+
+
+void RegExpMacroAssemblerMIPS::IfRegisterLT(int reg,
+ int comparand,
+ Label* if_lt) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::IfRegisterEqPos(int reg,
+ Label* if_eq) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+RegExpMacroAssembler::IrregexpImplementation
+ RegExpMacroAssemblerMIPS::Implementation() {
+ return kMIPSImplementation;
+}
+
+
+void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::PopCurrentPosition() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::PopRegister(int register_index) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+
+void RegExpMacroAssemblerMIPS::PushBacktrack(Label* label) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::PushCurrentPosition() {
+ Push(current_input_offset());
+}
+
+
+void RegExpMacroAssemblerMIPS::PushRegister(int register_index,
+ StackCheckFlag check_stack_limit) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::ReadCurrentPositionFromRegister(int reg) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::ReadStackPointerFromRegister(int reg) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::SetCurrentPositionFromEnd(int by) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::SetRegister(int register_index, int to) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::Succeed() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg,
+ int cp_offset) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::ClearRegisters(int reg_from, int reg_to) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::WriteStackPointerToRegister(int reg) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// Private methods:
+
+void RegExpMacroAssemblerMIPS::CallCheckStackGuardState(Register scratch) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+// Helper function for reading a value out of a stack frame.
+template <typename T>
+static T& frame_entry(Address re_frame, int frame_offset) {
+ return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
+}
+
+
+int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
+ Code* re_code,
+ Address re_frame) {
+ UNIMPLEMENTED_MIPS();
+ return 0;
+}
+
+
+MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) {
+ UNIMPLEMENTED_MIPS();
+ return MemOperand(zero_reg, 0);
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset,
+ Label* on_outside_input) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::BranchOrBacktrack(Label* to,
+ Condition condition,
+ Register rs,
+ const Operand& rt) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::SafeCall(Label* to, Condition cond, Register rs,
+ const Operand& rt) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::SafeReturn() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::SafeCallTarget(Label* name) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::Push(Register source) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::Pop(Register target) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckPreemption() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CheckStackLimit() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::CallCFunctionUsingStub(
+ ExternalReference function,
+ int num_arguments) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset,
+ int characters) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+#undef __
+
+#endif // V8_INTERPRETED_REGEXP
+
+}} // namespace v8::internal
+
+#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/mips/regexp-macro-assembler-mips.h b/src/mips/regexp-macro-assembler-mips.h
new file mode 100644
index 00000000..2f4319f9
--- /dev/null
+++ b/src/mips/regexp-macro-assembler-mips.h
@@ -0,0 +1,250 @@
+// Copyright 2006-2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#ifndef V8_MIPS_REGEXP_MACRO_ASSEMBLER_MIPS_H_
+#define V8_MIPS_REGEXP_MACRO_ASSEMBLER_MIPS_H_
+
+namespace v8 {
+namespace internal {
+
+#ifdef V8_INTERPRETED_REGEXP
+class RegExpMacroAssemblerMIPS: public RegExpMacroAssembler {
+ public:
+ RegExpMacroAssemblerMIPS();
+ virtual ~RegExpMacroAssemblerMIPS();
+};
+#else // V8_INTERPRETED_REGEXP
+class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler {
+ public:
+ RegExpMacroAssemblerMIPS(Mode mode, int registers_to_save);
+ virtual ~RegExpMacroAssemblerMIPS();
+ virtual int stack_limit_slack();
+ virtual void AdvanceCurrentPosition(int by);
+ virtual void AdvanceRegister(int reg, int by);
+ virtual void Backtrack();
+ virtual void Bind(Label* label);
+ virtual void CheckAtStart(Label* on_at_start);
+ virtual void CheckCharacter(uint32_t c, Label* on_equal);
+ virtual void CheckCharacterAfterAnd(uint32_t c,
+ uint32_t mask,
+ Label* on_equal);
+ virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
+ virtual void CheckCharacterLT(uc16 limit, Label* on_less);
+ virtual void CheckCharacters(Vector<const uc16> str,
+ int cp_offset,
+ Label* on_failure,
+ bool check_end_of_string);
+ // A "greedy loop" is a loop that is both greedy and with a simple
+ // body. It has a particularly simple implementation.
+ virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
+ virtual void CheckNotAtStart(Label* on_not_at_start);
+ virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
+ virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
+ Label* on_no_match);
+ virtual void CheckNotRegistersEqual(int reg1, int reg2, Label* on_not_equal);
+ virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal);
+ virtual void CheckNotCharacterAfterAnd(uint32_t c,
+ uint32_t mask,
+ Label* on_not_equal);
+ virtual void CheckNotCharacterAfterMinusAnd(uc16 c,
+ uc16 minus,
+ uc16 mask,
+ Label* on_not_equal);
+ // Checks whether the given offset from the current position is before
+ // the end of the string.
+ virtual void CheckPosition(int cp_offset, Label* on_outside_input);
+ virtual bool CheckSpecialCharacterClass(uc16 type,
+ Label* on_no_match);
+ virtual void Fail();
+ virtual Handle<Object> GetCode(Handle<String> source);
+ virtual void GoTo(Label* label);
+ virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
+ virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
+ virtual void IfRegisterEqPos(int reg, Label* if_eq);
+ virtual IrregexpImplementation Implementation();
+ virtual void LoadCurrentCharacter(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds = true,
+ int characters = 1);
+ virtual void PopCurrentPosition();
+ virtual void PopRegister(int register_index);
+ virtual void PushBacktrack(Label* label);
+ virtual void PushCurrentPosition();
+ virtual void PushRegister(int register_index,
+ StackCheckFlag check_stack_limit);
+ virtual void ReadCurrentPositionFromRegister(int reg);
+ virtual void ReadStackPointerFromRegister(int reg);
+ virtual void SetCurrentPositionFromEnd(int by);
+ virtual void SetRegister(int register_index, int to);
+ virtual void Succeed();
+ virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
+ virtual void ClearRegisters(int reg_from, int reg_to);
+ virtual void WriteStackPointerToRegister(int reg);
+
+ // Called from RegExp if the stack-guard is triggered.
+ // If the code object is relocated, the return address is fixed before
+ // returning.
+ static int CheckStackGuardState(Address* return_address,
+ Code* re_code,
+ Address re_frame);
+ private:
+ // Offsets from frame_pointer() of function parameters and stored registers.
+ static const int kFramePointer = 0;
+
+ // Above the frame pointer - Stored registers and stack passed parameters.
+ // Registers s0 to s7, fp, and ra.
+ static const int kStoredRegisters = kFramePointer;
+ // Return address (stored from link register, read into pc on return).
+ static const int kReturnAddress = kStoredRegisters + 9 * kPointerSize;
+ // Stack frame header.
+ static const int kStackFrameHeader = kReturnAddress + kPointerSize;
+ // Stack parameters placed by caller.
+ static const int kRegisterOutput = kStackFrameHeader + 16;
+ static const int kStackHighEnd = kRegisterOutput + kPointerSize;
+ static const int kDirectCall = kStackHighEnd + kPointerSize;
+ static const int kIsolate = kDirectCall + kPointerSize;
+
+ // Below the frame pointer.
+ // Register parameters stored by setup code.
+ static const int kInputEnd = kFramePointer - kPointerSize;
+ static const int kInputStart = kInputEnd - kPointerSize;
+ static const int kStartIndex = kInputStart - kPointerSize;
+ static const int kInputString = kStartIndex - kPointerSize;
+ // When adding local variables remember to push space for them in
+ // the frame in GetCode.
+ static const int kInputStartMinusOne = kInputString - kPointerSize;
+ static const int kAtStart = kInputStartMinusOne - kPointerSize;
+ // First register address. Following registers are below it on the stack.
+ static const int kRegisterZero = kAtStart - kPointerSize;
+
+ // Initial size of code buffer.
+ static const size_t kRegExpCodeSize = 1024;
+
+ // Load a number of characters at the given offset from the
+ // current position, into the current-character register.
+ void LoadCurrentCharacterUnchecked(int cp_offset, int character_count);
+
+ // Check whether preemption has been requested.
+ void CheckPreemption();
+
+ // Check whether we are exceeding the stack limit on the backtrack stack.
+ void CheckStackLimit();
+
+
+ // Generate a call to CheckStackGuardState.
+ void CallCheckStackGuardState(Register scratch);
+
+ // The ebp-relative location of a regexp register.
+ MemOperand register_location(int register_index);
+
+ // Register holding the current input position as negative offset from
+ // the end of the string.
+ inline Register current_input_offset() { return t2; }
+
+ // The register containing the current character after LoadCurrentCharacter.
+ inline Register current_character() { return t3; }
+
+ // Register holding address of the end of the input string.
+ inline Register end_of_input_address() { return t6; }
+
+ // Register holding the frame address. Local variables, parameters and
+ // regexp registers are addressed relative to this.
+ inline Register frame_pointer() { return fp; }
+
+ // The register containing the backtrack stack top. Provides a meaningful
+ // name to the register.
+ inline Register backtrack_stackpointer() { return t4; }
+
+ // Register holding pointer to the current code object.
+ inline Register code_pointer() { return t1; }
+
+ // Byte size of chars in the string to match (decided by the Mode argument)
+ inline int char_size() { return static_cast<int>(mode_); }
+
+ // Equivalent to a conditional branch to the label, unless the label
+ // is NULL, in which case it is a conditional Backtrack.
+ void BranchOrBacktrack(Label* to,
+ Condition condition,
+ Register rs,
+ const Operand& rt);
+
+ // Call and return internally in the generated code in a way that
+ // is GC-safe (i.e., doesn't leave absolute code addresses on the stack)
+ inline void SafeCall(Label* to,
+ Condition cond,
+ Register rs,
+ const Operand& rt);
+ inline void SafeReturn();
+ inline void SafeCallTarget(Label* name);
+
+ // Pushes the value of a register on the backtrack stack. Decrements the
+ // stack pointer by a word size and stores the register's value there.
+ inline void Push(Register source);
+
+ // Pops a value from the backtrack stack. Reads the word at the stack pointer
+ // and increments it by a word size.
+ inline void Pop(Register target);
+
+ // Calls a C function and cleans up the frame alignment done by
+ // by FrameAlign. The called function *is* allowed to trigger a garbage
+ // collection, but may not take more than four arguments (no arguments
+ // passed on the stack), and the first argument will be a pointer to the
+ // return address.
+ inline void CallCFunctionUsingStub(ExternalReference function,
+ int num_arguments);
+
+
+ MacroAssembler* masm_;
+
+ // Which mode to generate code for (ASCII or UC16).
+ Mode mode_;
+
+ // One greater than maximal register index actually used.
+ int num_registers_;
+
+ // Number of registers to output at the end (the saved registers
+ // are always 0..num_saved_registers_-1)
+ int num_saved_registers_;
+
+ // Labels used internally.
+ Label entry_label_;
+ Label start_label_;
+ Label success_label_;
+ Label backtrack_label_;
+ Label exit_label_;
+ Label check_preempt_label_;
+ Label stack_overflow_label_;
+};
+
+#endif // V8_INTERPRETED_REGEXP
+
+
+}} // namespace v8::internal
+
+#endif // V8_MIPS_REGEXP_MACRO_ASSEMBLER_MIPS_H_
+
diff --git a/src/mips/register-allocator-mips-inl.h b/src/mips/register-allocator-mips-inl.h
index a876bee4..bbfb31dd 100644
--- a/src/mips/register-allocator-mips-inl.h
+++ b/src/mips/register-allocator-mips-inl.h
@@ -125,9 +125,6 @@ Register RegisterAllocator::ToRegister(int num) {
void RegisterAllocator::Initialize() {
Reset();
- // The non-reserved a1 and ra registers are live on JS function entry.
- Use(a1); // JS function.
- Use(ra); // Return address.
}
diff --git a/src/mips/register-allocator-mips.h b/src/mips/register-allocator-mips.h
index e056fb80..c4489231 100644
--- a/src/mips/register-allocator-mips.h
+++ b/src/mips/register-allocator-mips.h
@@ -35,8 +35,9 @@ namespace internal {
class RegisterAllocatorConstants : public AllStatic {
public:
- static const int kNumRegisters = assembler::mips::kNumRegisters;
- static const int kInvalidRegister = assembler::mips::kInvalidRegister;
+ // No registers are currently managed by the register allocator on MIPS.
+ static const int kNumRegisters = 0;
+ static const int kInvalidRegister = -1;
};
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 59a53732..50ad7a18 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -26,6 +26,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
+#include <math.h>
+#include <limits.h>
#include <cstdarg>
#include "v8.h"
@@ -37,23 +39,25 @@
#include "mips/constants-mips.h"
#include "mips/simulator-mips.h"
-namespace v8i = v8::internal;
-
-#if !defined(__mips) || defined(USE_SIMULATOR)
// Only build the simulator if not compiling for real MIPS hardware.
-namespace assembler {
-namespace mips {
+#if defined(USE_SIMULATOR)
-using ::v8::internal::Object;
-using ::v8::internal::PrintF;
-using ::v8::internal::OS;
-using ::v8::internal::ReadLine;
-using ::v8::internal::DeleteArray;
+namespace v8 {
+namespace internal {
// Utils functions
bool HaveSameSign(int32_t a, int32_t b) {
- return ((a ^ b) > 0);
+ return ((a ^ b) >= 0);
+}
+
+
+uint32_t get_fcsr_condition_bit(uint32_t cc) {
+ if (cc == 0) {
+ return 23;
+ } else {
+ return 24 + cc;
+ }
}
@@ -63,15 +67,18 @@ bool HaveSameSign(int32_t a, int32_t b) {
// Library does not provide vsscanf.
#define SScanF sscanf // NOLINT
-// The Debugger class is used by the simulator while debugging simulated MIPS
+// The MipsDebugger class is used by the simulator while debugging simulated
// code.
-class Debugger {
+class MipsDebugger {
public:
- explicit Debugger(Simulator* sim);
- ~Debugger();
+ explicit MipsDebugger(Simulator* sim);
+ ~MipsDebugger();
void Stop(Instruction* instr);
void Debug();
+ // Print all registers with a nice formatting.
+ void PrintAllRegs();
+ void PrintAllRegsIncludingFPU();
private:
// We set the breakpoint code to 0xfffff to easily recognize it.
@@ -81,6 +88,10 @@ class Debugger {
Simulator* sim_;
int32_t GetRegisterValue(int regnum);
+ int32_t GetFPURegisterValueInt(int regnum);
+ int64_t GetFPURegisterValueLong(int regnum);
+ float GetFPURegisterValueFloat(int regnum);
+ double GetFPURegisterValueDouble(int regnum);
bool GetValue(const char* desc, int32_t* value);
// Set or delete a breakpoint. Returns true if successful.
@@ -91,18 +102,17 @@ class Debugger {
// execution to skip past breakpoints when run from the debugger.
void UndoBreakpoints();
void RedoBreakpoints();
-
- // Print all registers with a nice formatting.
- void PrintAllRegs();
};
-Debugger::Debugger(Simulator* sim) {
+MipsDebugger::MipsDebugger(Simulator* sim) {
sim_ = sim;
}
-Debugger::~Debugger() {
+
+MipsDebugger::~MipsDebugger() {
}
+
#ifdef GENERATED_CODE_COVERAGE
static FILE* coverage_log = NULL;
@@ -115,7 +125,7 @@ static void InitializeCoverage() {
}
-void Debugger::Stop(Instruction* instr) {
+void MipsDebugger::Stop(Instruction* instr) {
UNIMPLEMENTED_MIPS();
char* str = reinterpret_cast<char*>(instr->InstructionBits());
if (strlen(str) > 0) {
@@ -125,9 +135,10 @@ void Debugger::Stop(Instruction* instr) {
}
instr->SetInstructionBits(0x0); // Overwrite with nop.
}
- sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize);
+ sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
}
+
#else // ndef GENERATED_CODE_COVERAGE
#define UNSUPPORTED() printf("Unsupported instruction.\n");
@@ -135,16 +146,16 @@ void Debugger::Stop(Instruction* instr) {
static void InitializeCoverage() {}
-void Debugger::Stop(Instruction* instr) {
+void MipsDebugger::Stop(Instruction* instr) {
const char* str = reinterpret_cast<char*>(instr->InstructionBits());
PrintF("Simulator hit %s\n", str);
- sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize);
+ sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
Debug();
}
#endif // GENERATED_CODE_COVERAGE
-int32_t Debugger::GetRegisterValue(int regnum) {
+int32_t MipsDebugger::GetRegisterValue(int regnum) {
if (regnum == kNumSimuRegisters) {
return sim_->get_pc();
} else {
@@ -153,11 +164,54 @@ int32_t Debugger::GetRegisterValue(int regnum) {
}
-bool Debugger::GetValue(const char* desc, int32_t* value) {
+int32_t MipsDebugger::GetFPURegisterValueInt(int regnum) {
+ if (regnum == kNumFPURegisters) {
+ return sim_->get_pc();
+ } else {
+ return sim_->get_fpu_register(regnum);
+ }
+}
+
+
+int64_t MipsDebugger::GetFPURegisterValueLong(int regnum) {
+ if (regnum == kNumFPURegisters) {
+ return sim_->get_pc();
+ } else {
+ return sim_->get_fpu_register_long(regnum);
+ }
+}
+
+
+float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
+ if (regnum == kNumFPURegisters) {
+ return sim_->get_pc();
+ } else {
+ return sim_->get_fpu_register_float(regnum);
+ }
+}
+
+
+double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
+ if (regnum == kNumFPURegisters) {
+ return sim_->get_pc();
+ } else {
+ return sim_->get_fpu_register_double(regnum);
+ }
+}
+
+
+bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
int regnum = Registers::Number(desc);
+ int fpuregnum = FPURegisters::Number(desc);
+
if (regnum != kInvalidRegister) {
*value = GetRegisterValue(regnum);
return true;
+ } else if (fpuregnum != kInvalidFPURegister) {
+ *value = GetFPURegisterValueInt(fpuregnum);
+ return true;
+ } else if (strncmp(desc, "0x", 2) == 0) {
+ return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
} else {
return SScanF(desc, "%i", value) == 1;
}
@@ -165,7 +219,7 @@ bool Debugger::GetValue(const char* desc, int32_t* value) {
}
-bool Debugger::SetBreakpoint(Instruction* breakpc) {
+bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
// Check if a breakpoint can be set. If not return without any side-effects.
if (sim_->break_pc_ != NULL) {
return false;
@@ -180,7 +234,7 @@ bool Debugger::SetBreakpoint(Instruction* breakpc) {
}
-bool Debugger::DeleteBreakpoint(Instruction* breakpc) {
+bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
if (sim_->break_pc_ != NULL) {
sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
}
@@ -191,20 +245,21 @@ bool Debugger::DeleteBreakpoint(Instruction* breakpc) {
}
-void Debugger::UndoBreakpoints() {
+void MipsDebugger::UndoBreakpoints() {
if (sim_->break_pc_ != NULL) {
sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
}
}
-void Debugger::RedoBreakpoints() {
+void MipsDebugger::RedoBreakpoints() {
if (sim_->break_pc_ != NULL) {
sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
}
}
-void Debugger::PrintAllRegs() {
+
+void MipsDebugger::PrintAllRegs() {
#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
PrintF("\n");
@@ -237,10 +292,45 @@ void Debugger::PrintAllRegs() {
// pc
PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n",
REG_INFO(31), REG_INFO(34));
+
+#undef REG_INFO
+#undef FPU_REG_INFO
+}
+
+
+void MipsDebugger::PrintAllRegsIncludingFPU() {
+#define FPU_REG_INFO(n) FPURegisters::Name(n), FPURegisters::Name(n+1), \
+ GetFPURegisterValueInt(n+1), \
+ GetFPURegisterValueInt(n), \
+ GetFPURegisterValueDouble(n)
+
+ PrintAllRegs();
+
+ PrintF("\n\n");
+ // f0, f1, f2, ... f31
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(0) );
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(2) );
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(4) );
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(6) );
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(8) );
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(10));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(12));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(14));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(16));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(18));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(20));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(22));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(24));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(26));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(28));
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO(30));
+
#undef REG_INFO
+#undef FPU_REG_INFO
}
-void Debugger::Debug() {
+
+void MipsDebugger::Debug() {
intptr_t last_pc = -1;
bool done = false;
@@ -253,6 +343,7 @@ void Debugger::Debug() {
char cmd[COMMAND_SIZE + 1];
char arg1[ARG_SIZE + 1];
char arg2[ARG_SIZE + 1];
+ char* argv[3] = { cmd, arg1, arg2 };
// make sure to have a proper terminating character if reaching the limit
cmd[COMMAND_SIZE] = 0;
@@ -280,19 +371,21 @@ void Debugger::Debug() {
} else {
// Use sscanf to parse the individual parts of the command line. At the
// moment no command expects more than two parameters.
- int args = SScanF(line,
+ int argc = SScanF(line,
"%" XSTR(COMMAND_SIZE) "s "
"%" XSTR(ARG_SIZE) "s "
"%" XSTR(ARG_SIZE) "s",
cmd, arg1, arg2);
if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
- if (!(reinterpret_cast<Instruction*>(sim_->get_pc())->IsTrap())) {
+ Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
+ if (!(instr->IsTrap()) ||
+ instr->InstructionBits() == rtCallRedirInstr) {
sim_->InstructionDecode(
- reinterpret_cast<Instruction*>(sim_->get_pc()));
+ reinterpret_cast<Instruction*>(sim_->get_pc()));
} else {
// Allow si to jump over generated breakpoints.
PrintF("/!\\ Jumping over generated breakpoint.\n");
- sim_->set_pc(sim_->get_pc() + Instruction::kInstructionSize);
+ sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
}
} else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
// Execute the one instruction we broke at with breakpoints disabled.
@@ -300,23 +393,65 @@ void Debugger::Debug() {
// Leave the debugger shell.
done = true;
} else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
- if (args == 2) {
+ if (argc == 2) {
int32_t value;
+ float fvalue;
if (strcmp(arg1, "all") == 0) {
PrintAllRegs();
+ } else if (strcmp(arg1, "allf") == 0) {
+ PrintAllRegsIncludingFPU();
} else {
- if (GetValue(arg1, &value)) {
+ int regnum = Registers::Number(arg1);
+ int fpuregnum = FPURegisters::Number(arg1);
+
+ if (regnum != kInvalidRegister) {
+ value = GetRegisterValue(regnum);
PrintF("%s: 0x%08x %d \n", arg1, value, value);
+ } else if (fpuregnum != kInvalidFPURegister) {
+ if (fpuregnum % 2 == 1) {
+ value = GetFPURegisterValueInt(fpuregnum);
+ fvalue = GetFPURegisterValueFloat(fpuregnum);
+ PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
+ } else {
+ double dfvalue;
+ int32_t lvalue1 = GetFPURegisterValueInt(fpuregnum);
+ int32_t lvalue2 = GetFPURegisterValueInt(fpuregnum + 1);
+ dfvalue = GetFPURegisterValueDouble(fpuregnum);
+ PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
+ FPURegisters::Name(fpuregnum+1),
+ FPURegisters::Name(fpuregnum),
+ lvalue1,
+ lvalue2,
+ dfvalue);
+ }
} else {
PrintF("%s unrecognized\n", arg1);
}
}
} else {
- PrintF("print <register>\n");
+ if (argc == 3) {
+ if (strcmp(arg2, "single") == 0) {
+ int32_t value;
+ float fvalue;
+ int fpuregnum = FPURegisters::Number(arg1);
+
+ if (fpuregnum != kInvalidFPURegister) {
+ value = GetFPURegisterValueInt(fpuregnum);
+ fvalue = GetFPURegisterValueFloat(fpuregnum);
+ PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
+ } else {
+ PrintF("%s unrecognized\n", arg1);
+ }
+ } else {
+ PrintF("print <fpu register> single\n");
+ }
+ } else {
+ PrintF("print <register> or print <fpu register> single\n");
+ }
}
} else if ((strcmp(cmd, "po") == 0)
|| (strcmp(cmd, "printobject") == 0)) {
- if (args == 2) {
+ if (argc == 2) {
int32_t value;
if (GetValue(arg1, &value)) {
Object* obj = reinterpret_cast<Object*>(value);
@@ -333,6 +468,39 @@ void Debugger::Debug() {
} else {
PrintF("printobject <value>\n");
}
+ } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
+ int32_t* cur = NULL;
+ int32_t* end = NULL;
+ int next_arg = 1;
+
+ if (strcmp(cmd, "stack") == 0) {
+ cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
+ } else { // "mem"
+ int32_t value;
+ if (!GetValue(arg1, &value)) {
+ PrintF("%s unrecognized\n", arg1);
+ continue;
+ }
+ cur = reinterpret_cast<int32_t*>(value);
+ next_arg++;
+ }
+
+ int32_t words;
+ if (argc == next_arg) {
+ words = 10;
+ } else if (argc == next_arg + 1) {
+ if (!GetValue(argv[next_arg], &words)) {
+ words = 10;
+ }
+ }
+ end = cur + words;
+
+ while (cur < end) {
+ PrintF(" 0x%08x: 0x%08x %10d\n",
+ reinterpret_cast<intptr_t>(cur), *cur, *cur);
+ cur++;
+ }
+
} else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0)) {
disasm::NameConverter converter;
disasm::Disassembler dasm(converter);
@@ -342,36 +510,37 @@ void Debugger::Debug() {
byte_* cur = NULL;
byte_* end = NULL;
- if (args == 1) {
+ if (argc == 1) {
cur = reinterpret_cast<byte_*>(sim_->get_pc());
- end = cur + (10 * Instruction::kInstructionSize);
- } else if (args == 2) {
+ end = cur + (10 * Instruction::kInstrSize);
+ } else if (argc == 2) {
int32_t value;
if (GetValue(arg1, &value)) {
cur = reinterpret_cast<byte_*>(value);
// no length parameter passed, assume 10 instructions
- end = cur + (10 * Instruction::kInstructionSize);
+ end = cur + (10 * Instruction::kInstrSize);
}
} else {
int32_t value1;
int32_t value2;
if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
cur = reinterpret_cast<byte_*>(value1);
- end = cur + (value2 * Instruction::kInstructionSize);
+ end = cur + (value2 * Instruction::kInstrSize);
}
}
while (cur < end) {
dasm.InstructionDecode(buffer, cur);
- PrintF(" 0x%08x %s\n", cur, buffer.start());
- cur += Instruction::kInstructionSize;
+ PrintF(" 0x%08x %s\n",
+ reinterpret_cast<intptr_t>(cur), buffer.start());
+ cur += Instruction::kInstrSize;
}
} else if (strcmp(cmd, "gdb") == 0) {
PrintF("relinquishing control to gdb\n");
v8::internal::OS::DebugBreak();
PrintF("regaining control from gdb\n");
} else if (strcmp(cmd, "break") == 0) {
- if (args == 2) {
+ if (argc == 2) {
int32_t value;
if (GetValue(arg1, &value)) {
if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
@@ -404,29 +573,30 @@ void Debugger::Debug() {
byte_* cur = NULL;
byte_* end = NULL;
- if (args == 1) {
+ if (argc == 1) {
cur = reinterpret_cast<byte_*>(sim_->get_pc());
- end = cur + (10 * Instruction::kInstructionSize);
- } else if (args == 2) {
+ end = cur + (10 * Instruction::kInstrSize);
+ } else if (argc == 2) {
int32_t value;
if (GetValue(arg1, &value)) {
cur = reinterpret_cast<byte_*>(value);
// no length parameter passed, assume 10 instructions
- end = cur + (10 * Instruction::kInstructionSize);
+ end = cur + (10 * Instruction::kInstrSize);
}
} else {
int32_t value1;
int32_t value2;
if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
cur = reinterpret_cast<byte_*>(value1);
- end = cur + (value2 * Instruction::kInstructionSize);
+ end = cur + (value2 * Instruction::kInstrSize);
}
}
while (cur < end) {
dasm.InstructionDecode(buffer, cur);
- PrintF(" 0x%08x %s\n", cur, buffer.start());
- cur += Instruction::kInstructionSize;
+ PrintF(" 0x%08x %s\n",
+ reinterpret_cast<intptr_t>(cur), buffer.start());
+ cur += Instruction::kInstrSize;
}
} else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
PrintF("cont\n");
@@ -438,6 +608,10 @@ void Debugger::Debug() {
PrintF(" use register name 'all' to print all registers\n");
PrintF("printobject <register>\n");
PrintF(" print an object from a register (alias 'po')\n");
+ PrintF("stack [<words>]\n");
+ PrintF(" dump stack content, default dump 10 words)\n");
+ PrintF("mem <address> [<words>]\n");
+ PrintF(" dump memory content, default dump 10 words)\n");
PrintF("flags\n");
PrintF(" print flags\n");
PrintF("disasm [<instructions>]\n");
@@ -471,29 +645,120 @@ void Debugger::Debug() {
}
-// Create one simulator per thread and keep it in thread local storage.
-static v8::internal::Thread::LocalStorageKey simulator_key;
+static bool ICacheMatch(void* one, void* two) {
+ ASSERT((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
+ ASSERT((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
+ return one == two;
+}
+
+static uint32_t ICacheHash(void* key) {
+ return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
+}
-bool Simulator::initialized_ = false;
+
+static bool AllOnOnePage(uintptr_t start, int size) {
+ intptr_t start_page = (start & ~CachePage::kPageMask);
+ intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
+ return start_page == end_page;
+}
+
+
+void Simulator::FlushICache(v8::internal::HashMap* i_cache,
+ void* start_addr,
+ size_t size) {
+ intptr_t start = reinterpret_cast<intptr_t>(start_addr);
+ int intra_line = (start & CachePage::kLineMask);
+ start -= intra_line;
+ size += intra_line;
+ size = ((size - 1) | CachePage::kLineMask) + 1;
+ int offset = (start & CachePage::kPageMask);
+ while (!AllOnOnePage(start, size - 1)) {
+ int bytes_to_flush = CachePage::kPageSize - offset;
+ FlushOnePage(i_cache, start, bytes_to_flush);
+ start += bytes_to_flush;
+ size -= bytes_to_flush;
+ ASSERT_EQ(0, start & CachePage::kPageMask);
+ offset = 0;
+ }
+ if (size != 0) {
+ FlushOnePage(i_cache, start, size);
+ }
+}
+
+
+CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
+ v8::internal::HashMap::Entry* entry = i_cache->Lookup(page,
+ ICacheHash(page),
+ true);
+ if (entry->value == NULL) {
+ CachePage* new_page = new CachePage();
+ entry->value = new_page;
+ }
+ return reinterpret_cast<CachePage*>(entry->value);
+}
+
+
+// Flush from start up to and not including start + size.
+void Simulator::FlushOnePage(v8::internal::HashMap* i_cache,
+ intptr_t start,
+ int size) {
+ ASSERT(size <= CachePage::kPageSize);
+ ASSERT(AllOnOnePage(start, size - 1));
+ ASSERT((start & CachePage::kLineMask) == 0);
+ ASSERT((size & CachePage::kLineMask) == 0);
+ void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
+ int offset = (start & CachePage::kPageMask);
+ CachePage* cache_page = GetCachePage(i_cache, page);
+ char* valid_bytemap = cache_page->ValidityByte(offset);
+ memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
+}
+
+
+void Simulator::CheckICache(v8::internal::HashMap* i_cache,
+ Instruction* instr) {
+ intptr_t address = reinterpret_cast<intptr_t>(instr);
+ void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
+ void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
+ int offset = (address & CachePage::kPageMask);
+ CachePage* cache_page = GetCachePage(i_cache, page);
+ char* cache_valid_byte = cache_page->ValidityByte(offset);
+ bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
+ char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
+ if (cache_hit) {
+ // Check that the data in memory matches the contents of the I-cache.
+ CHECK(memcmp(reinterpret_cast<void*>(instr),
+ cache_page->CachedData(offset),
+ Instruction::kInstrSize) == 0);
+ } else {
+ // Cache miss. Load memory into the cache.
+ memcpy(cached_line, line, CachePage::kLineLength);
+ *cache_valid_byte = CachePage::LINE_VALID;
+ }
+}
void Simulator::Initialize() {
- if (initialized_) return;
- simulator_key = v8::internal::Thread::CreateThreadLocalKey();
- initialized_ = true;
+ if (Isolate::Current()->simulator_initialized()) return;
+ Isolate::Current()->set_simulator_initialized(true);
::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference);
}
-Simulator::Simulator() {
+Simulator::Simulator() : isolate_(Isolate::Current()) {
+ i_cache_ = isolate_->simulator_i_cache();
+ if (i_cache_ == NULL) {
+ i_cache_ = new v8::internal::HashMap(&ICacheMatch);
+ isolate_->set_simulator_i_cache(i_cache_);
+ }
Initialize();
// Setup simulator support first. Some of this information is needed to
// setup the architecture state.
- size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack
- stack_ = reinterpret_cast<char*>(malloc(stack_size));
+ stack_size_ = 1 * 1024*1024; // allocate 1MB for stack
+ stack_ = reinterpret_cast<char*>(malloc(stack_size_));
pc_modified_ = false;
icount_ = 0;
+ break_count_ = 0;
break_pc_ = NULL;
break_instr_ = 0;
@@ -502,16 +767,23 @@ Simulator::Simulator() {
for (int i = 0; i < kNumSimuRegisters; i++) {
registers_[i] = 0;
}
+ for (int i = 0; i < kNumFPURegisters; i++) {
+ FPUregisters_[i] = 0;
+ }
+ FCSR_ = 0;
// The sp is initialized to point to the bottom (high address) of the
// allocated stack area. To be safe in potential stack underflows we leave
// some buffer below.
- registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
+ registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
// The ra and pc are initialized to a known bad value that will cause an
// access violation if the simulator ever tries to execute it.
registers_[pc] = bad_ra;
registers_[ra] = bad_ra;
InitializeCoverage();
+ for (int i = 0; i < kNumExceptions; i++) {
+ exceptions[i] = 0;
+ }
}
@@ -524,12 +796,18 @@ Simulator::Simulator() {
// offset from the swi instruction so the simulator knows what to call.
class Redirection {
public:
- Redirection(void* external_function, bool fp_return)
+ Redirection(void* external_function, ExternalReference::Type type)
: external_function_(external_function),
swi_instruction_(rtCallRedirInstr),
- fp_return_(fp_return),
- next_(list_) {
- list_ = this;
+ type_(type),
+ next_(NULL) {
+ Isolate* isolate = Isolate::Current();
+ next_ = isolate->simulator_redirection();
+ Simulator::current(isolate)->
+ FlushICache(isolate->simulator_i_cache(),
+ reinterpret_cast<void*>(&swi_instruction_),
+ Instruction::kInstrSize);
+ isolate->set_simulator_redirection(this);
}
void* address_of_swi_instruction() {
@@ -537,14 +815,16 @@ class Redirection {
}
void* external_function() { return external_function_; }
- bool fp_return() { return fp_return_; }
+ ExternalReference::Type type() { return type_; }
- static Redirection* Get(void* external_function, bool fp_return) {
- Redirection* current;
- for (current = list_; current != NULL; current = current->next_) {
+ static Redirection* Get(void* external_function,
+ ExternalReference::Type type) {
+ Isolate* isolate = Isolate::Current();
+ Redirection* current = isolate->simulator_redirection();
+ for (; current != NULL; current = current->next_) {
if (current->external_function_ == external_function) return current;
}
- return new Redirection(external_function, fp_return);
+ return new Redirection(external_function, type);
}
static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
@@ -557,31 +837,33 @@ class Redirection {
private:
void* external_function_;
uint32_t swi_instruction_;
- bool fp_return_;
+ ExternalReference::Type type_;
Redirection* next_;
- static Redirection* list_;
};
-Redirection* Redirection::list_ = NULL;
-
-
void* Simulator::RedirectExternalReference(void* external_function,
- bool fp_return) {
- Redirection* redirection = Redirection::Get(external_function, fp_return);
+ ExternalReference::Type type) {
+ Redirection* redirection = Redirection::Get(external_function, type);
return redirection->address_of_swi_instruction();
}
// Get the active Simulator for the current thread.
-Simulator* Simulator::current() {
- Initialize();
- Simulator* sim = reinterpret_cast<Simulator*>(
- v8::internal::Thread::GetThreadLocal(simulator_key));
+Simulator* Simulator::current(Isolate* isolate) {
+ v8::internal::Isolate::PerIsolateThreadData* isolate_data =
+ Isolate::CurrentPerIsolateThreadData();
+ if (isolate_data == NULL) {
+ Isolate::EnterDefaultIsolate();
+ isolate_data = Isolate::CurrentPerIsolateThreadData();
+ }
+ ASSERT(isolate_data != NULL);
+
+ Simulator* sim = isolate_data->simulator();
if (sim == NULL) {
- // TODO(146): delete the simulator object when a thread goes away.
+ // TODO(146): delete the simulator object when a thread/isolate goes away.
sim = new Simulator();
- v8::internal::Thread::SetThreadLocal(simulator_key, sim);
+ isolate_data->set_simulator(sim);
}
return sim;
}
@@ -599,14 +881,22 @@ void Simulator::set_register(int reg, int32_t value) {
registers_[reg] = (reg == 0) ? 0 : value;
}
+
void Simulator::set_fpu_register(int fpureg, int32_t value) {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
FPUregisters_[fpureg] = value;
}
+
+void Simulator::set_fpu_register_float(int fpureg, float value) {
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
+ *BitCast<float*>(&FPUregisters_[fpureg]) = value;
+}
+
+
void Simulator::set_fpu_register_double(int fpureg, double value) {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
- *v8i::BitCast<double*>(&FPUregisters_[fpureg]) = value;
+ *BitCast<double*>(&FPUregisters_[fpureg]) = value;
}
@@ -620,22 +910,75 @@ int32_t Simulator::get_register(int reg) const {
return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
}
+
int32_t Simulator::get_fpu_register(int fpureg) const {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
return FPUregisters_[fpureg];
}
+
+int64_t Simulator::get_fpu_register_long(int fpureg) const {
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
+ return *BitCast<int64_t*>(
+ const_cast<int32_t*>(&FPUregisters_[fpureg]));
+}
+
+
+float Simulator::get_fpu_register_float(int fpureg) const {
+ ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
+ return *BitCast<float*>(
+ const_cast<int32_t*>(&FPUregisters_[fpureg]));
+}
+
+
double Simulator::get_fpu_register_double(int fpureg) const {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
- return *v8i::BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg]));
+ return *BitCast<double*>(const_cast<int32_t*>(&FPUregisters_[fpureg]));
+}
+
+
+// Helper functions for setting and testing the FCSR register's bits.
+void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
+ if (value) {
+ FCSR_ |= (1 << cc);
+ } else {
+ FCSR_ &= ~(1 << cc);
+ }
+}
+
+
+bool Simulator::test_fcsr_bit(uint32_t cc) {
+ return FCSR_ & (1 << cc);
}
+
+// Sets the rounding error codes in FCSR based on the result of the rounding.
+// Returns true if the operation was invalid.
+bool Simulator::set_fcsr_round_error(double original, double rounded) {
+ if (!isfinite(original) ||
+ rounded > LONG_MAX ||
+ rounded < LONG_MIN) {
+ set_fcsr_bit(6, true); // Invalid operation.
+ return true;
+ } else if (original != static_cast<double>(rounded)) {
+ set_fcsr_bit(2, true); // Inexact.
+ }
+ return false;
+}
+
+
// Raw access to the PC register.
void Simulator::set_pc(int32_t value) {
pc_modified_ = true;
registers_[pc] = value;
}
+
+bool Simulator::has_bad_pc() const {
+ return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
+}
+
+
// Raw access to the PC register without the special adjustment when reading.
int32_t Simulator::get_pc() const {
return registers_[pc];
@@ -651,24 +994,38 @@ int32_t Simulator::get_pc() const {
// get the correct MIPS-like behaviour on unaligned accesses.
int Simulator::ReadW(int32_t addr, Instruction* instr) {
- if ((addr & v8i::kPointerAlignmentMask) == 0) {
+ if (addr >=0 && addr < 0x400) {
+ // this has to be a NULL-dereference
+ MipsDebugger dbg(this);
+ dbg.Debug();
+ }
+ if ((addr & kPointerAlignmentMask) == 0) {
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
return *ptr;
}
- PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
- OS::Abort();
+ PrintF("Unaligned read at 0x%08x, pc=%p\n", addr,
+ reinterpret_cast<void*>(instr));
+ MipsDebugger dbg(this);
+ dbg.Debug();
return 0;
}
void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
- if ((addr & v8i::kPointerAlignmentMask) == 0) {
+ if (addr >= 0 && addr < 0x400) {
+ // this has to be a NULL-dereference
+ MipsDebugger dbg(this);
+ dbg.Debug();
+ }
+ if ((addr & kPointerAlignmentMask) == 0) {
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
*ptr = value;
return;
}
- PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
- OS::Abort();
+ PrintF("Unaligned write at 0x%08x, pc=%p\n", addr,
+ reinterpret_cast<void*>(instr));
+ MipsDebugger dbg(this);
+ dbg.Debug();
}
@@ -677,7 +1034,8 @@ double Simulator::ReadD(int32_t addr, Instruction* instr) {
double* ptr = reinterpret_cast<double*>(addr);
return *ptr;
}
- PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
+ PrintF("Unaligned (double) read at 0x%08x, pc=%p\n", addr,
+ reinterpret_cast<void*>(instr));
OS::Abort();
return 0;
}
@@ -689,7 +1047,8 @@ void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
*ptr = value;
return;
}
- PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
+ PrintF("Unaligned (double) write at 0x%08x, pc=%p\n", addr,
+ reinterpret_cast<void*>(instr));
OS::Abort();
}
@@ -699,7 +1058,8 @@ uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
}
- PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
+ PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr,
+ reinterpret_cast<void*>(instr));
OS::Abort();
return 0;
}
@@ -710,7 +1070,8 @@ int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
return *ptr;
}
- PrintF("Unaligned signed halfword read at 0x%08x, pc=%p\n", addr, instr);
+ PrintF("Unaligned signed halfword read at 0x%08x, pc=%p\n", addr,
+ reinterpret_cast<void*>(instr));
OS::Abort();
return 0;
}
@@ -722,7 +1083,8 @@ void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
*ptr = value;
return;
}
- PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
+ PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr,
+ reinterpret_cast<void*>(instr));
OS::Abort();
}
@@ -733,7 +1095,8 @@ void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
*ptr = value;
return;
}
- PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
+ PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr,
+ reinterpret_cast<void*>(instr));
OS::Abort();
}
@@ -746,7 +1109,7 @@ uint32_t Simulator::ReadBU(int32_t addr) {
int32_t Simulator::ReadB(int32_t addr) {
int8_t* ptr = reinterpret_cast<int8_t*>(addr);
- return ((*ptr << 24) >> 24) & 0xff;
+ return *ptr;
}
@@ -773,7 +1136,7 @@ uintptr_t Simulator::StackLimit() const {
// Unsupported instructions use Format to print an error and stop execution.
void Simulator::Format(Instruction* instr, const char* format) {
PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n",
- instr, format);
+ reinterpret_cast<intptr_t>(instr), format);
UNIMPLEMENTED_MIPS();
}
@@ -782,75 +1145,140 @@ void Simulator::Format(Instruction* instr, const char* format) {
// Note: To be able to return two values from some calls the code in runtime.cc
// uses the ObjectPair which is essentially two 32-bit values stuffed into a
// 64-bit value. With the code below we assume that all runtime calls return
-// 64 bits of result. If they don't, the r1 result register contains a bogus
+// 64 bits of result. If they don't, the v1 result register contains a bogus
// value, which is fine because it is caller-saved.
typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
int32_t arg1,
int32_t arg2,
- int32_t arg3);
-typedef double (*SimulatorRuntimeFPCall)(double fparg0,
- double fparg1);
-
+ int32_t arg3,
+ int32_t arg4,
+ int32_t arg5);
+typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
+ int32_t arg1,
+ int32_t arg2,
+ int32_t arg3);
// Software interrupt instructions are used by the simulator to call into the
-// C-based V8 runtime.
+// C-based V8 runtime. They are also used for debugging with simulator.
void Simulator::SoftwareInterrupt(Instruction* instr) {
+ // There are several instructions that could get us here,
+ // the break_ instruction, or several variants of traps. All
+ // Are "SPECIAL" class opcode, and are distinuished by function.
+ int32_t func = instr->FunctionFieldRaw();
+ int32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1;
+
// We first check if we met a call_rt_redirected.
if (instr->InstructionBits() == rtCallRedirInstr) {
+ // Check if stack is aligned. Error if not aligned is reported below to
+ // include information on the function called.
+ bool stack_aligned =
+ (get_register(sp)
+ & (::v8::internal::FLAG_sim_stack_alignment - 1)) == 0;
Redirection* redirection = Redirection::FromSwiInstruction(instr);
int32_t arg0 = get_register(a0);
int32_t arg1 = get_register(a1);
int32_t arg2 = get_register(a2);
int32_t arg3 = get_register(a3);
- // fp args are (not always) in f12 and f14.
- // See MIPS conventions for more details.
- double fparg0 = get_fpu_register_double(f12);
- double fparg1 = get_fpu_register_double(f14);
+ int32_t arg4 = 0;
+ int32_t arg5 = 0;
+
+ // Need to check if sp is valid before assigning arg4, arg5.
+ // This is a fix for cctest test-api/CatchStackOverflow which causes
+ // the stack to overflow. For some reason arm doesn't need this
+ // stack check here.
+ int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
+ int32_t* stack = reinterpret_cast<int32_t*>(stack_);
+ if (stack_pointer >= stack && stack_pointer < stack + stack_size_) {
+ arg4 = stack_pointer[0];
+ arg5 = stack_pointer[1];
+ }
// This is dodgy but it works because the C entry stubs are never moved.
// See comment in codegen-arm.cc and bug 1242173.
int32_t saved_ra = get_register(ra);
- if (redirection->fp_return()) {
- intptr_t external =
- reinterpret_cast<intptr_t>(redirection->external_function());
+
+ intptr_t external =
+ reinterpret_cast<int32_t>(redirection->external_function());
+
+ // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
+ // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
+ // simulator. Soft-float has additional abstraction of ExternalReference,
+ // to support serialization. Finally, when simulated on x86 host, the
+ // x86 softfloat routines are used, and this Redirection infrastructure
+ // lets simulated-mips make calls into x86 C code.
+ // When doing that, the 'double' return type must be handled differently
+ // than the usual int64_t return. The data is returned in different
+ // registers and cannot be cast from one type to the other. However, the
+ // calling arguments are passed the same way in both cases.
+ if (redirection->type() == ExternalReference::FP_RETURN_CALL) {
SimulatorRuntimeFPCall target =
reinterpret_cast<SimulatorRuntimeFPCall>(external);
- if (::v8::internal::FLAG_trace_sim) {
- PrintF("Call to host function at %p with args %f, %f\n",
- FUNCTION_ADDR(target), fparg0, fparg1);
+ if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+ PrintF("Call to host function at %p with args %08x:%08x %08x:%08x",
+ FUNCTION_ADDR(target), arg0, arg1, arg2, arg3);
+ if (!stack_aligned) {
+ PrintF(" with unaligned stack %08x\n", get_register(sp));
+ }
+ PrintF("\n");
}
- double result = target(fparg0, fparg1);
- set_fpu_register_double(f0, result);
+ double result = target(arg0, arg1, arg2, arg3);
+ // fp result -> registers v0 and v1.
+ int32_t gpreg_pair[2];
+ memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t));
+ set_register(v0, gpreg_pair[0]);
+ set_register(v1, gpreg_pair[1]);
+ } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
+ PrintF("Mips does not yet support ExternalReference::DIRECT_API_CALL\n");
+ ASSERT(redirection->type() != ExternalReference::DIRECT_API_CALL);
+ } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
+ PrintF("Mips does not support ExternalReference::DIRECT_GETTER_CALL\n");
+ ASSERT(redirection->type() != ExternalReference::DIRECT_GETTER_CALL);
} else {
- intptr_t external =
- reinterpret_cast<int32_t>(redirection->external_function());
+ // Builtin call.
+ ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
- if (::v8::internal::FLAG_trace_sim) {
+ if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
PrintF(
- "Call to host function at %p with args %08x, %08x, %08x, %08x\n",
+ "Call to host function at %p: %08x, %08x, %08x, %08x, %08x, %08x",
FUNCTION_ADDR(target),
arg0,
arg1,
arg2,
- arg3);
- }
- int64_t result = target(arg0, arg1, arg2, arg3);
- int32_t lo_res = static_cast<int32_t>(result);
- int32_t hi_res = static_cast<int32_t>(result >> 32);
- if (::v8::internal::FLAG_trace_sim) {
- PrintF("Returned %08x\n", lo_res);
+ arg3,
+ arg4,
+ arg5);
+ if (!stack_aligned) {
+ PrintF(" with unaligned stack %08x\n", get_register(sp));
+ }
+ PrintF("\n");
}
- set_register(v0, lo_res);
- set_register(v1, hi_res);
+
+ int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
+ set_register(v0, static_cast<int32_t>(result));
+ set_register(v1, static_cast<int32_t>(result >> 32));
+ }
+ if (::v8::internal::FLAG_trace_sim) {
+ PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
}
set_register(ra, saved_ra);
set_pc(get_register(ra));
+
+ } else if (func == BREAK && code >= 0 && code < 16) {
+ // First 16 break_ codes interpreted as debug markers.
+ MipsDebugger dbg(this);
+ ++break_count_;
+ PrintF("\n---- break %d marker: %3d (instr count: %8d) ----------"
+ "----------------------------------",
+ code, break_count_, icount_);
+ dbg.PrintAllRegs(); // Print registers and continue running.
} else {
- Debugger dbg(this);
+ // All remaining break_ codes, and all traps are handled here.
+ MipsDebugger dbg(this);
dbg.Debug();
}
}
+
void Simulator::SignalExceptions() {
for (int i = 1; i < kNumExceptions; i++) {
if (exceptions[i] != 0) {
@@ -859,51 +1287,52 @@ void Simulator::SignalExceptions() {
}
}
-// Handle execution based on instruction types.
-void Simulator::DecodeTypeRegister(Instruction* instr) {
- // Instruction fields
- Opcode op = instr->OpcodeFieldRaw();
- int32_t rs_reg = instr->RsField();
- int32_t rs = get_register(rs_reg);
- uint32_t rs_u = static_cast<uint32_t>(rs);
- int32_t rt_reg = instr->RtField();
- int32_t rt = get_register(rt_reg);
- uint32_t rt_u = static_cast<uint32_t>(rt);
- int32_t rd_reg = instr->RdField();
- uint32_t sa = instr->SaField();
-
- int32_t fs_reg= instr->FsField();
- // ALU output
- // It should not be used as is. Instructions using it should always initialize
- // it first.
- int32_t alu_out = 0x12345678;
- // Output or temporary for floating point.
- double fp_out = 0.0;
+// Handle execution based on instruction types.
- // For break and trap instructions.
- bool do_interrupt = false;
+void Simulator::ConfigureTypeRegister(Instruction* instr,
+ int32_t& alu_out,
+ int64_t& i64hilo,
+ uint64_t& u64hilo,
+ int32_t& next_pc,
+ bool& do_interrupt) {
+ // Every local variable declared here needs to be const.
+ // This is to make sure that changed values are sent back to
+ // DecodeTypeRegister correctly.
+
+ // Instruction fields.
+ const Opcode op = instr->OpcodeFieldRaw();
+ const int32_t rs_reg = instr->RsValue();
+ const int32_t rs = get_register(rs_reg);
+ const uint32_t rs_u = static_cast<uint32_t>(rs);
+ const int32_t rt_reg = instr->RtValue();
+ const int32_t rt = get_register(rt_reg);
+ const uint32_t rt_u = static_cast<uint32_t>(rt);
+ const int32_t rd_reg = instr->RdValue();
+ const uint32_t sa = instr->SaValue();
+
+ const int32_t fs_reg = instr->FsValue();
- // For jr and jalr
- // Get current pc.
- int32_t current_pc = get_pc();
- // Next pc
- int32_t next_pc = 0;
// ---------- Configuration
switch (op) {
case COP1: // Coprocessor instructions
switch (instr->RsFieldRaw()) {
- case BC1: // branch on coprocessor condition
+ case BC1: // Handled in DecodeTypeImmed, should never come here.
UNREACHABLE();
break;
+ case CFC1:
+ // At the moment only FCSR is supported.
+ ASSERT(fs_reg == kFCSRRegister);
+ alu_out = FCSR_;
+ break;
case MFC1:
alu_out = get_fpu_register(fs_reg);
break;
case MFHC1:
- fp_out = get_fpu_register_double(fs_reg);
- alu_out = *v8i::BitCast<int32_t*>(&fp_out);
+ UNIMPLEMENTED_MIPS();
break;
+ case CTC1:
case MTC1:
case MTHC1:
// Do the store in the execution step.
@@ -923,13 +1352,22 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
switch (instr->FunctionFieldRaw()) {
case JR:
case JALR:
- next_pc = get_register(instr->RsField());
+ next_pc = get_register(instr->RsValue());
break;
case SLL:
alu_out = rt << sa;
break;
case SRL:
- alu_out = rt_u >> sa;
+ if (rs_reg == 0) {
+ // Regular logical right shift of a word by a fixed number of
+ // bits instruction. RS field is always equal to 0.
+ alu_out = rt_u >> sa;
+ } else {
+ // Logical right-rotate of a word by a fixed number of bits. This
+ // is special case of SRL instruction, added in MIPS32 Release 2.
+ // RS field is equal to 00001
+ alu_out = (rt_u >> sa) | (rt_u << (32 - sa));
+ }
break;
case SRA:
alu_out = rt >> sa;
@@ -938,7 +1376,16 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
alu_out = rt << rs;
break;
case SRLV:
- alu_out = rt_u >> rs;
+ if (sa == 0) {
+ // Regular logical right-shift of a word by a variable number of
+ // bits instruction. SA field is always equal to 0.
+ alu_out = rt_u >> rs;
+ } else {
+ // Logical right-rotate of a word by a variable number of bits.
+ // This is special case od SRLV instruction, added in MIPS32
+ // Release 2. SA field is equal to 00001
+ alu_out = (rt_u >> rs_u) | (rt_u << (32 - rs_u));
+ }
break;
case SRAV:
alu_out = rt >> rs;
@@ -950,10 +1397,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
alu_out = get_register(LO);
break;
case MULT:
- UNIMPLEMENTED_MIPS();
+ i64hilo = static_cast<int64_t>(rs) * static_cast<int64_t>(rt);
break;
case MULTU:
- UNIMPLEMENTED_MIPS();
+ u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u);
break;
case DIV:
case DIVU:
@@ -1005,6 +1452,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
break;
// Break and trap instructions
case BREAK:
+
do_interrupt = true;
break;
case TGE:
@@ -1025,6 +1473,11 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
case TNE:
do_interrupt = rs != rt;
break;
+ case MOVN:
+ case MOVZ:
+ case MOVCI:
+ // No action taken on decode.
+ break;
default:
UNREACHABLE();
};
@@ -1034,13 +1487,83 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
case MUL:
alu_out = rs_u * rt_u; // Only the lower 32 bits are kept.
break;
+ case CLZ:
+ alu_out = __builtin_clz(rs_u);
+ break;
default:
UNREACHABLE();
- }
+ };
+ break;
+ case SPECIAL3:
+ switch (instr->FunctionFieldRaw()) {
+ case INS: { // Mips32r2 instruction.
+ // Interpret Rd field as 5-bit msb of insert.
+ uint16_t msb = rd_reg;
+ // Interpret sa field as 5-bit lsb of insert.
+ uint16_t lsb = sa;
+ uint16_t size = msb - lsb + 1;
+ uint32_t mask = (1 << size) - 1;
+ alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
+ break;
+ }
+ case EXT: { // Mips32r2 instruction.
+ // Interpret Rd field as 5-bit msb of extract.
+ uint16_t msb = rd_reg;
+ // Interpret sa field as 5-bit lsb of extract.
+ uint16_t lsb = sa;
+ uint16_t size = msb + 1;
+ uint32_t mask = (1 << size) - 1;
+ alu_out = (rs_u & (mask << lsb)) >> lsb;
+ break;
+ }
+ default:
+ UNREACHABLE();
+ };
break;
default:
UNREACHABLE();
};
+}
+
+
+void Simulator::DecodeTypeRegister(Instruction* instr) {
+ // Instruction fields.
+ const Opcode op = instr->OpcodeFieldRaw();
+ const int32_t rs_reg = instr->RsValue();
+ const int32_t rs = get_register(rs_reg);
+ const uint32_t rs_u = static_cast<uint32_t>(rs);
+ const int32_t rt_reg = instr->RtValue();
+ const int32_t rt = get_register(rt_reg);
+ const uint32_t rt_u = static_cast<uint32_t>(rt);
+ const int32_t rd_reg = instr->RdValue();
+
+ const int32_t fs_reg = instr->FsValue();
+ const int32_t ft_reg = instr->FtValue();
+ const int32_t fd_reg = instr->FdValue();
+ int64_t i64hilo = 0;
+ uint64_t u64hilo = 0;
+
+ // ALU output
+ // It should not be used as is. Instructions using it should always
+ // initialize it first.
+ int32_t alu_out = 0x12345678;
+
+ // For break and trap instructions.
+ bool do_interrupt = false;
+
+ // For jr and jalr
+ // Get current pc.
+ int32_t current_pc = get_pc();
+ // Next pc
+ int32_t next_pc = 0;
+
+ // Setup the variables if needed before executing the instruction.
+ ConfigureTypeRegister(instr,
+ alu_out,
+ i64hilo,
+ u64hilo,
+ next_pc,
+ do_interrupt);
// ---------- Raise exceptions triggered.
SignalExceptions();
@@ -1052,25 +1575,42 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
case BC1: // branch on coprocessor condition
UNREACHABLE();
break;
+ case CFC1:
+ set_register(rt_reg, alu_out);
case MFC1:
- case MFHC1:
set_register(rt_reg, alu_out);
break;
+ case MFHC1:
+ UNIMPLEMENTED_MIPS();
+ break;
+ case CTC1:
+ // At the moment only FCSR is supported.
+ ASSERT(fs_reg == kFCSRRegister);
+ FCSR_ = registers_[rt_reg];
+ break;
case MTC1:
- // We don't need to set the higher bits to 0, because MIPS ISA says
- // they are in an unpredictable state after executing MTC1.
FPUregisters_[fs_reg] = registers_[rt_reg];
- FPUregisters_[fs_reg+1] = Unpredictable;
break;
case MTHC1:
- // Here we need to keep the lower bits unchanged.
- FPUregisters_[fs_reg+1] = registers_[rt_reg];
+ UNIMPLEMENTED_MIPS();
break;
case S:
+ float f;
switch (instr->FunctionFieldRaw()) {
case CVT_D_S:
+ f = get_fpu_register_float(fs_reg);
+ set_fpu_register_double(fd_reg, static_cast<double>(f));
+ break;
case CVT_W_S:
case CVT_L_S:
+ case TRUNC_W_S:
+ case TRUNC_L_S:
+ case ROUND_W_S:
+ case ROUND_L_S:
+ case FLOOR_W_S:
+ case FLOOR_L_S:
+ case CEIL_W_S:
+ case CEIL_L_S:
case CVT_PS_S:
UNIMPLEMENTED_MIPS();
break;
@@ -1079,10 +1619,133 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
}
break;
case D:
+ double ft, fs;
+ uint32_t cc, fcsr_cc;
+ int64_t i64;
+ fs = get_fpu_register_double(fs_reg);
+ ft = get_fpu_register_double(ft_reg);
+ cc = instr->FCccValue();
+ fcsr_cc = get_fcsr_condition_bit(cc);
switch (instr->FunctionFieldRaw()) {
- case CVT_S_D:
- case CVT_W_D:
- case CVT_L_D:
+ case ADD_D:
+ set_fpu_register_double(fd_reg, fs + ft);
+ break;
+ case SUB_D:
+ set_fpu_register_double(fd_reg, fs - ft);
+ break;
+ case MUL_D:
+ set_fpu_register_double(fd_reg, fs * ft);
+ break;
+ case DIV_D:
+ set_fpu_register_double(fd_reg, fs / ft);
+ break;
+ case ABS_D:
+ set_fpu_register_double(fd_reg, fs < 0 ? -fs : fs);
+ break;
+ case MOV_D:
+ set_fpu_register_double(fd_reg, fs);
+ break;
+ case NEG_D:
+ set_fpu_register_double(fd_reg, -fs);
+ break;
+ case SQRT_D:
+ set_fpu_register_double(fd_reg, sqrt(fs));
+ break;
+ case C_UN_D:
+ set_fcsr_bit(fcsr_cc, isnan(fs) || isnan(ft));
+ break;
+ case C_EQ_D:
+ set_fcsr_bit(fcsr_cc, (fs == ft));
+ break;
+ case C_UEQ_D:
+ set_fcsr_bit(fcsr_cc, (fs == ft) || (isnan(fs) || isnan(ft)));
+ break;
+ case C_OLT_D:
+ set_fcsr_bit(fcsr_cc, (fs < ft));
+ break;
+ case C_ULT_D:
+ set_fcsr_bit(fcsr_cc, (fs < ft) || (isnan(fs) || isnan(ft)));
+ break;
+ case C_OLE_D:
+ set_fcsr_bit(fcsr_cc, (fs <= ft));
+ break;
+ case C_ULE_D:
+ set_fcsr_bit(fcsr_cc, (fs <= ft) || (isnan(fs) || isnan(ft)));
+ break;
+ case CVT_W_D: // Convert double to word.
+ // Rounding modes are not yet supported.
+ ASSERT((FCSR_ & 3) == 0);
+ // In rounding mode 0 it should behave like ROUND.
+ case ROUND_W_D: // Round double to word.
+ {
+ double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
+ int32_t result = static_cast<int32_t>(rounded);
+ set_fpu_register(fd_reg, result);
+ if (set_fcsr_round_error(fs, rounded)) {
+ set_fpu_register(fd_reg, kFPUInvalidResult);
+ }
+ }
+ break;
+ case TRUNC_W_D: // Truncate double to word (round towards 0).
+ {
+ int32_t result = static_cast<int32_t>(fs);
+ set_fpu_register(fd_reg, result);
+ if (set_fcsr_round_error(fs, static_cast<double>(result))) {
+ set_fpu_register(fd_reg, kFPUInvalidResult);
+ }
+ }
+ break;
+ case FLOOR_W_D: // Round double to word towards negative infinity.
+ {
+ double rounded = floor(fs);
+ int32_t result = static_cast<int32_t>(rounded);
+ set_fpu_register(fd_reg, result);
+ if (set_fcsr_round_error(fs, rounded)) {
+ set_fpu_register(fd_reg, kFPUInvalidResult);
+ }
+ }
+ break;
+ case CEIL_W_D: // Round double to word towards positive infinity.
+ {
+ double rounded = ceil(fs);
+ int32_t result = static_cast<int32_t>(rounded);
+ set_fpu_register(fd_reg, result);
+ if (set_fcsr_round_error(fs, rounded)) {
+ set_fpu_register(fd_reg, kFPUInvalidResult);
+ }
+ }
+ break;
+ case CVT_S_D: // Convert double to float (single).
+ set_fpu_register_float(fd_reg, static_cast<float>(fs));
+ break;
+ case CVT_L_D: // Mips32r2: Truncate double to 64-bit long-word.
+ i64 = static_cast<int64_t>(fs);
+ set_fpu_register(fd_reg, i64 & 0xffffffff);
+ set_fpu_register(fd_reg + 1, i64 >> 32);
+ break;
+ case TRUNC_L_D: // Mips32r2 instruction.
+ i64 = static_cast<int64_t>(fs);
+ set_fpu_register(fd_reg, i64 & 0xffffffff);
+ set_fpu_register(fd_reg + 1, i64 >> 32);
+ break;
+ case ROUND_L_D: { // Mips32r2 instruction.
+ double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
+ i64 = static_cast<int64_t>(rounded);
+ set_fpu_register(fd_reg, i64 & 0xffffffff);
+ set_fpu_register(fd_reg + 1, i64 >> 32);
+ break;
+ }
+ case FLOOR_L_D: // Mips32r2 instruction.
+ i64 = static_cast<int64_t>(floor(fs));
+ set_fpu_register(fd_reg, i64 & 0xffffffff);
+ set_fpu_register(fd_reg + 1, i64 >> 32);
+ break;
+ case CEIL_L_D: // Mips32r2 instruction.
+ i64 = static_cast<int64_t>(ceil(fs));
+ set_fpu_register(fd_reg, i64 & 0xffffffff);
+ set_fpu_register(fd_reg + 1, i64 >> 32);
+ break;
+ case C_F_D:
UNIMPLEMENTED_MIPS();
break;
default:
@@ -1091,11 +1754,13 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
break;
case W:
switch (instr->FunctionFieldRaw()) {
- case CVT_S_W:
- UNIMPLEMENTED_MIPS();
+ case CVT_S_W: // Convert word to float (single).
+ alu_out = get_fpu_register(fs_reg);
+ set_fpu_register_float(fd_reg, static_cast<float>(alu_out));
break;
case CVT_D_W: // Convert word to double.
- set_fpu_register(rd_reg, static_cast<double>(rs));
+ alu_out = get_fpu_register(fs_reg);
+ set_fpu_register_double(fd_reg, static_cast<double>(alu_out));
break;
default:
UNREACHABLE();
@@ -1103,8 +1768,14 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
break;
case L:
switch (instr->FunctionFieldRaw()) {
+ case CVT_D_L: // Mips32r2 instruction.
+ // Watch the signs here, we want 2 32-bit vals
+ // to make a sign-64.
+ i64 = (uint32_t) get_fpu_register(fs_reg);
+ i64 |= ((int64_t) get_fpu_register(fs_reg + 1) << 32);
+ set_fpu_register_double(fd_reg, static_cast<double>(i64));
+ break;
case CVT_S_L:
- case CVT_D_L:
UNIMPLEMENTED_MIPS();
break;
default:
@@ -1121,7 +1792,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
switch (instr->FunctionFieldRaw()) {
case JR: {
Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
- current_pc+Instruction::kInstructionSize);
+ current_pc+Instruction::kInstrSize);
BranchDelayInstructionDecode(branch_delay_instr);
set_pc(next_pc);
pc_modified_ = true;
@@ -1129,16 +1800,21 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
}
case JALR: {
Instruction* branch_delay_instr = reinterpret_cast<Instruction*>(
- current_pc+Instruction::kInstructionSize);
+ current_pc+Instruction::kInstrSize);
BranchDelayInstructionDecode(branch_delay_instr);
- set_register(31, current_pc + 2* Instruction::kInstructionSize);
+ set_register(31, current_pc + 2* Instruction::kInstrSize);
set_pc(next_pc);
pc_modified_ = true;
break;
}
// Instructions using HI and LO registers.
case MULT:
+ set_register(LO, static_cast<int32_t>(i64hilo & 0xffffffff));
+ set_register(HI, static_cast<int32_t>(i64hilo >> 32));
+ break;
case MULTU:
+ set_register(LO, static_cast<int32_t>(u64hilo & 0xffffffff));
+ set_register(HI, static_cast<int32_t>(u64hilo >> 32));
break;
case DIV:
// Divide by zero was checked in the configuration step.
@@ -1149,7 +1825,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
set_register(LO, rs_u / rt_u);
set_register(HI, rs_u % rt_u);
break;
- // Break and trap instructions
+ // Break and trap instructions.
case BREAK:
case TGE:
case TGEU:
@@ -1161,6 +1837,23 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
SoftwareInterrupt(instr);
}
break;
+ // Conditional moves.
+ case MOVN:
+ if (rt) set_register(rd_reg, rs);
+ break;
+ case MOVCI: {
+ uint32_t cc = instr->FCccValue();
+ uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
+ if (instr->Bit(16)) { // Read Tf bit
+ if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
+ } else {
+ if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg, rs);
+ }
+ break;
+ }
+ case MOVZ:
+ if (!rt) set_register(rd_reg, rs);
+ break;
default: // For other special opcodes we do the default operation.
set_register(rd_reg, alu_out);
};
@@ -1173,9 +1866,23 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
set_register(LO, Unpredictable);
set_register(HI, Unpredictable);
break;
+ default: // For other special2 opcodes we do the default operation.
+ set_register(rd_reg, alu_out);
+ }
+ break;
+ case SPECIAL3:
+ switch (instr->FunctionFieldRaw()) {
+ case INS:
+ // Ins instr leaves result in Rt, rather than Rd.
+ set_register(rt_reg, alu_out);
+ break;
+ case EXT:
+ // Ext instr leaves result in Rt, rather than Rd.
+ set_register(rt_reg, alu_out);
+ break;
default:
UNREACHABLE();
- }
+ };
break;
// Unimplemented opcodes raised an error in the configuration step before,
// so we can use the default here to set the destination register in common
@@ -1185,22 +1892,22 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
};
}
+
// Type 2: instructions using a 16 bytes immediate. (eg: addi, beq)
void Simulator::DecodeTypeImmediate(Instruction* instr) {
- // Instruction fields
+ // Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
- int32_t rs = get_register(instr->RsField());
+ int32_t rs = get_register(instr->RsValue());
uint32_t rs_u = static_cast<uint32_t>(rs);
- int32_t rt_reg = instr->RtField(); // destination register
+ int32_t rt_reg = instr->RtValue(); // destination register
int32_t rt = get_register(rt_reg);
- int16_t imm16 = instr->Imm16Field();
+ int16_t imm16 = instr->Imm16Value();
- int32_t ft_reg = instr->FtField(); // destination register
- int32_t ft = get_register(ft_reg);
+ int32_t ft_reg = instr->FtValue(); // destination register
- // zero extended immediate
+ // Zero extended immediate.
uint32_t oe_imm16 = 0xffff & imm16;
- // sign extended immediate
+ // Sign extended immediate.
int32_t se_imm16 = imm16;
// Get current pc.
@@ -1208,25 +1915,38 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Next pc.
int32_t next_pc = bad_ra;
- // Used for conditional branch instructions
+ // Used for conditional branch instructions.
bool do_branch = false;
bool execute_branch_delay_instruction = false;
- // Used for arithmetic instructions
+ // Used for arithmetic instructions.
int32_t alu_out = 0;
- // Floating point
+ // Floating point.
double fp_out = 0.0;
+ uint32_t cc, cc_value, fcsr_cc;
- // Used for memory instructions
+ // Used for memory instructions.
int32_t addr = 0x0;
+ // Value to be written in memory
+ uint32_t mem_value = 0x0;
// ---------- Configuration (and execution for REGIMM)
switch (op) {
- // ------------- COP1. Coprocessor instructions
+ // ------------- COP1. Coprocessor instructions.
case COP1:
switch (instr->RsFieldRaw()) {
- case BC1: // branch on coprocessor condition
- UNIMPLEMENTED_MIPS();
+ case BC1: // Branch on coprocessor condition.
+ cc = instr->FBccValue();
+ fcsr_cc = get_fcsr_condition_bit(cc);
+ cc_value = test_fcsr_bit(fcsr_cc);
+ do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value;
+ execute_branch_delay_instruction = true;
+ // Set next_pc
+ if (do_branch) {
+ next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
+ } else {
+ next_pc = current_pc + kBranchReturnOffset;
+ }
break;
default:
UNREACHABLE();
@@ -1259,7 +1979,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
execute_branch_delay_instruction = true;
// Set next_pc
if (do_branch) {
- next_pc = current_pc + (imm16 << 2) + Instruction::kInstructionSize;
+ next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
if (instr->IsLinkingInstruction()) {
set_register(31, current_pc + kBranchReturnOffset);
}
@@ -1323,6 +2043,21 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
addr = rs + se_imm16;
alu_out = ReadB(addr);
break;
+ case LH:
+ addr = rs + se_imm16;
+ alu_out = ReadH(addr, instr);
+ break;
+ case LWL: {
+ // al_offset is an offset of the effective address within an aligned word
+ uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
+ uint8_t byte_shift = kPointerAlignmentMask - al_offset;
+ uint32_t mask = (1 << byte_shift * 8) - 1;
+ addr = rs + se_imm16 - al_offset;
+ alu_out = ReadW(addr, instr);
+ alu_out <<= byte_shift * 8;
+ alu_out |= rt & mask;
+ break;
+ }
case LW:
addr = rs + se_imm16;
alu_out = ReadW(addr, instr);
@@ -1331,12 +2066,47 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
addr = rs + se_imm16;
alu_out = ReadBU(addr);
break;
+ case LHU:
+ addr = rs + se_imm16;
+ alu_out = ReadHU(addr, instr);
+ break;
+ case LWR: {
+ // al_offset is an offset of the effective address within an aligned word
+ uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
+ uint8_t byte_shift = kPointerAlignmentMask - al_offset;
+ uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
+ addr = rs + se_imm16 - al_offset;
+ alu_out = ReadW(addr, instr);
+ alu_out = static_cast<uint32_t> (alu_out) >> al_offset * 8;
+ alu_out |= rt & mask;
+ break;
+ }
case SB:
addr = rs + se_imm16;
break;
+ case SH:
+ addr = rs + se_imm16;
+ break;
+ case SWL: {
+ uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
+ uint8_t byte_shift = kPointerAlignmentMask - al_offset;
+ uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
+ addr = rs + se_imm16 - al_offset;
+ mem_value = ReadW(addr, instr) & mask;
+ mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
+ break;
+ }
case SW:
addr = rs + se_imm16;
break;
+ case SWR: {
+ uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
+ uint32_t mask = (1 << al_offset * 8) - 1;
+ addr = rs + se_imm16 - al_offset;
+ mem_value = ReadW(addr, instr);
+ mem_value = (rt << al_offset * 8) | (mem_value & mask);
+ break;
+ }
case LWC1:
addr = rs + se_imm16;
alu_out = ReadW(addr, instr);
@@ -1367,12 +2137,12 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
execute_branch_delay_instruction = true;
// Set next_pc
if (do_branch) {
- next_pc = current_pc + (imm16 << 2) + Instruction::kInstructionSize;
+ next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize;
if (instr->IsLinkingInstruction()) {
- set_register(31, current_pc + 2* Instruction::kInstructionSize);
+ set_register(31, current_pc + 2* Instruction::kInstrSize);
}
} else {
- next_pc = current_pc + 2 * Instruction::kInstructionSize;
+ next_pc = current_pc + 2 * Instruction::kInstrSize;
}
break;
// ------------- Arithmetic instructions
@@ -1388,16 +2158,29 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
break;
// ------------- Memory instructions
case LB:
+ case LH:
+ case LWL:
case LW:
case LBU:
+ case LHU:
+ case LWR:
set_register(rt_reg, alu_out);
break;
case SB:
WriteB(addr, static_cast<int8_t>(rt));
break;
+ case SH:
+ WriteH(addr, static_cast<uint16_t>(rt), instr);
+ break;
+ case SWL:
+ WriteW(addr, mem_value, instr);
+ break;
case SW:
WriteW(addr, rt, instr);
break;
+ case SWR:
+ WriteW(addr, mem_value, instr);
+ break;
case LWC1:
set_fpu_register(ft_reg, alu_out);
break;
@@ -1410,7 +2193,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
break;
case SDC1:
addr = rs + se_imm16;
- WriteD(addr, ft, instr);
+ WriteD(addr, get_fpu_register_double(ft_reg), instr);
break;
default:
break;
@@ -1422,7 +2205,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
// We don't check for end_sim_pc. First it should not be met as the current
// pc is valid. Secondly a jump should always execute its branch delay slot.
Instruction* branch_delay_instr =
- reinterpret_cast<Instruction*>(current_pc+Instruction::kInstructionSize);
+ reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize);
BranchDelayInstructionDecode(branch_delay_instr);
}
@@ -1432,6 +2215,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
}
}
+
// Type 3: instructions using a 26 bytes immediate. (eg: j, jal)
void Simulator::DecodeTypeJump(Instruction* instr) {
// Get current pc.
@@ -1439,35 +2223,39 @@ void Simulator::DecodeTypeJump(Instruction* instr) {
// Get unchanged bits of pc.
int32_t pc_high_bits = current_pc & 0xf0000000;
// Next pc
- int32_t next_pc = pc_high_bits | (instr->Imm26Field() << 2);
+ int32_t next_pc = pc_high_bits | (instr->Imm26Value() << 2);
// Execute branch delay slot
// We don't check for end_sim_pc. First it should not be met as the current pc
// is valid. Secondly a jump should always execute its branch delay slot.
Instruction* branch_delay_instr =
- reinterpret_cast<Instruction*>(current_pc+Instruction::kInstructionSize);
+ reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize);
BranchDelayInstructionDecode(branch_delay_instr);
// Update pc and ra if necessary.
// Do this after the branch delay execution.
if (instr->IsLinkingInstruction()) {
- set_register(31, current_pc + 2* Instruction::kInstructionSize);
+ set_register(31, current_pc + 2* Instruction::kInstrSize);
}
set_pc(next_pc);
pc_modified_ = true;
}
+
// Executes the current instruction.
void Simulator::InstructionDecode(Instruction* instr) {
+ if (v8::internal::FLAG_check_icache) {
+ CheckICache(isolate_->simulator_i_cache(), instr);
+ }
pc_modified_ = false;
if (::v8::internal::FLAG_trace_sim) {
disasm::NameConverter converter;
disasm::Disassembler dasm(converter);
// use a reasonably large buffer
v8::internal::EmbeddedVector<char, 256> buffer;
- dasm.InstructionDecode(buffer,
- reinterpret_cast<byte_*>(instr));
- PrintF(" 0x%08x %s\n", instr, buffer.start());
+ dasm.InstructionDecode(buffer, reinterpret_cast<byte_*>(instr));
+ PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr),
+ buffer.start());
}
switch (instr->InstructionType()) {
@@ -1485,7 +2273,7 @@ void Simulator::InstructionDecode(Instruction* instr) {
}
if (!pc_modified_) {
set_register(pc, reinterpret_cast<int32_t>(instr) +
- Instruction::kInstructionSize);
+ Instruction::kInstrSize);
}
}
@@ -1511,7 +2299,7 @@ void Simulator::Execute() {
Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
icount_++;
if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
- Debugger dbg(this);
+ MipsDebugger dbg(this);
dbg.Debug();
} else {
InstructionDecode(instr);
@@ -1538,7 +2326,7 @@ int32_t Simulator::Call(byte_* entry, int argument_count, ...) {
int original_stack = get_register(sp);
// Compute position of stack on entry to generated code.
int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
- - kArgsSlotsSize);
+ - kCArgsSlotsSize);
if (OS::ActivationFrameAlignment() != 0) {
entry_stack &= -OS::ActivationFrameAlignment();
}
@@ -1643,8 +2431,8 @@ uintptr_t Simulator::PopAddress() {
#undef UNSUPPORTED
-} } // namespace assembler::mips
+} } // namespace v8::internal
-#endif // !__mips || USE_SIMULATOR
+#endif // USE_SIMULATOR
#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/mips/simulator-mips.h b/src/mips/simulator-mips.h
index 6e42683a..0cd9bbe7 100644
--- a/src/mips/simulator-mips.h
+++ b/src/mips/simulator-mips.h
@@ -37,12 +37,31 @@
#define V8_MIPS_SIMULATOR_MIPS_H_
#include "allocation.h"
+#include "constants-mips.h"
-#if defined(__mips) && !defined(USE_SIMULATOR)
+#if !defined(USE_SIMULATOR)
+// Running without a simulator on a native mips platform.
+
+namespace v8 {
+namespace internal {
// When running without a simulator we call the entry directly.
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
- entry(p0, p1, p2, p3, p4);
+ entry(p0, p1, p2, p3, p4)
+
+typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
+ void*, int*, Address, int, Isolate*);
+
+// Call the generated regexp code directly. The code at the entry address
+// should act as a function matching the type arm_regexp_matcher.
+// The fifth argument is a dummy that reserves the space used for
+// the return address added by the ExitFrame in native calls.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
+ (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
+ p0, p1, p2, p3, NULL, p4, p5, p6, p7))
+
+#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
+ reinterpret_cast<TryCatch*>(try_catch_address)
// The stack limit beyond which we will throw stack overflow errors in
// generated code. Because generated code on mips uses the C stack, we
@@ -60,6 +79,8 @@ class SimulatorStack : public v8::internal::AllStatic {
static inline void UnregisterCTryCatch() { }
};
+} } // namespace v8::internal
+
// Calculated the stack limit beyond which we will throw stack overflow errors.
// This macro must be called from a C++ method. It relies on being able to take
// the address of "this" to get a value on the current execution stack and then
@@ -70,39 +91,50 @@ class SimulatorStack : public v8::internal::AllStatic {
(reinterpret_cast<uintptr_t>(this) >= limit ? \
reinterpret_cast<uintptr_t>(this) - limit : 0)
-// Call the generated regexp code directly. The entry function pointer should
-// expect seven int/pointer sized arguments and return an int.
-#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
- entry(p0, p1, p2, p3, p4, p5, p6)
-
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
- reinterpret_cast<TryCatch*>(try_catch_address)
+#else // !defined(USE_SIMULATOR)
+// Running with a simulator.
+#include "hashmap.h"
-#else // #if !defined(__mips) || defined(USE_SIMULATOR)
+namespace v8 {
+namespace internal {
-// When running with the simulator transition into simulated execution at this
-// point.
-#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
- reinterpret_cast<Object*>(\
- assembler::mips::Simulator::current()->Call(FUNCTION_ADDR(entry), 5, \
- p0, p1, p2, p3, p4))
+// -----------------------------------------------------------------------------
+// Utility functions
-#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
- assembler::mips::Simulator::current()->Call(\
- FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6)
+class CachePage {
+ public:
+ static const int LINE_VALID = 0;
+ static const int LINE_INVALID = 1;
+
+ static const int kPageShift = 12;
+ static const int kPageSize = 1 << kPageShift;
+ static const int kPageMask = kPageSize - 1;
+ static const int kLineShift = 2; // The cache line is only 4 bytes right now.
+ static const int kLineLength = 1 << kLineShift;
+ static const int kLineMask = kLineLength - 1;
+
+ CachePage() {
+ memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
+ }
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
- try_catch_address == NULL ? \
- NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
+ char* ValidityByte(int offset) {
+ return &validity_map_[offset >> kLineShift];
+ }
+ char* CachedData(int offset) {
+ return &data_[offset];
+ }
-namespace assembler {
-namespace mips {
+ private:
+ char data_[kPageSize]; // The cached data.
+ static const int kValidityMapSize = kPageSize >> kLineShift;
+ char validity_map_[kValidityMapSize]; // One byte per line.
+};
class Simulator {
public:
- friend class Debugger;
+ friend class MipsDebugger;
// Registers are declared in order. See SMRL chapter 2.
enum Register {
@@ -143,7 +175,7 @@ class Simulator {
// The currently executing Simulator instance. Potentially there can be one
// for each native thread.
- static Simulator* current();
+ static Simulator* current(v8::internal::Isolate* isolate);
// Accessors for register state. Reading the pc value adheres to the MIPS
// architecture specification and is off by a 8 from the currently executing
@@ -152,9 +184,15 @@ class Simulator {
int32_t get_register(int reg) const;
// Same for FPURegisters
void set_fpu_register(int fpureg, int32_t value);
+ void set_fpu_register_float(int fpureg, float value);
void set_fpu_register_double(int fpureg, double value);
int32_t get_fpu_register(int fpureg) const;
+ int64_t get_fpu_register_long(int fpureg) const;
+ float get_fpu_register_float(int fpureg) const;
double get_fpu_register_double(int fpureg) const;
+ void set_fcsr_bit(uint32_t cc, bool value);
+ bool test_fcsr_bit(uint32_t cc);
+ bool set_fcsr_round_error(double original, double rounded);
// Special case of set_register and get_register to access the raw PC value.
void set_pc(int32_t value);
@@ -172,7 +210,7 @@ class Simulator {
// V8 generally calls into generated JS code with 5 parameters and into
// generated RegExp code with 7 parameters. This is a convenience function,
// which sets up the simulator state and grabs the result on return.
- int32_t Call(byte_* entry, int argument_count, ...);
+ int32_t Call(byte* entry, int argument_count, ...);
// Push an address onto the JS stack.
uintptr_t PushAddress(uintptr_t address);
@@ -180,6 +218,14 @@ class Simulator {
// Pop an address from the JS stack.
uintptr_t PopAddress();
+ // ICache checking.
+ static void FlushICache(v8::internal::HashMap* i_cache, void* start,
+ size_t size);
+
+ // Returns true if pc register contains one of the 'special_values' defined
+ // below (bad_ra, end_sim_pc).
+ bool has_bad_pc() const;
+
private:
enum special_values {
// Known bad pc value to ensure that the simulator does not execute
@@ -223,9 +269,17 @@ class Simulator {
inline int32_t SetDoubleHIW(double* addr);
inline int32_t SetDoubleLOW(double* addr);
-
// Executing is handled based on the instruction type.
void DecodeTypeRegister(Instruction* instr);
+
+ // Helper function for DecodeTypeRegister.
+ void ConfigureTypeRegister(Instruction* instr,
+ int32_t& alu_out,
+ int64_t& i64hilo,
+ uint64_t& u64hilo,
+ int32_t& next_pc,
+ bool& do_interrupt);
+
void DecodeTypeImmediate(Instruction* instr);
void DecodeTypeJump(Instruction* instr);
@@ -239,11 +293,18 @@ class Simulator {
if (instr->IsForbiddenInBranchDelay()) {
V8_Fatal(__FILE__, __LINE__,
"Eror:Unexpected %i opcode in a branch delay slot.",
- instr->OpcodeField());
+ instr->OpcodeValue());
}
InstructionDecode(instr);
}
+ // ICache.
+ static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
+ static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
+ int size);
+ static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
+
+
enum Exception {
none,
kIntegerOverflow,
@@ -258,7 +319,7 @@ class Simulator {
// Runtime call support.
static void* RedirectExternalReference(void* external_function,
- bool fp_return);
+ ExternalReference::Type type);
// Used for real time calls that takes two double values as arguments and
// returns a double.
@@ -269,19 +330,40 @@ class Simulator {
int32_t registers_[kNumSimuRegisters];
// Coprocessor Registers.
int32_t FPUregisters_[kNumFPURegisters];
+ // FPU control register.
+ uint32_t FCSR_;
// Simulator support.
char* stack_;
+ size_t stack_size_;
bool pc_modified_;
int icount_;
- static bool initialized_;
+ int break_count_;
+
+ // Icache simulation
+ v8::internal::HashMap* i_cache_;
// Registered breakpoints.
Instruction* break_pc_;
Instr break_instr_;
+
+ v8::internal::Isolate* isolate_;
};
-} } // namespace assembler::mips
+
+// When running with the simulator transition into simulated execution at this
+// point.
+#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
+reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
+ FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
+
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
+ Simulator::current(Isolate::Current())->Call( \
+ entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7)
+
+#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
+ try_catch_address == NULL ? \
+ NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
// The simulator has its own stack. Thus it has a different stack limit from
@@ -292,20 +374,21 @@ class Simulator {
class SimulatorStack : public v8::internal::AllStatic {
public:
static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
- return assembler::mips::Simulator::current()->StackLimit();
+ return Simulator::current(Isolate::Current())->StackLimit();
}
static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
- assembler::mips::Simulator* sim = assembler::mips::Simulator::current();
+ Simulator* sim = Simulator::current(Isolate::Current());
return sim->PushAddress(try_catch_address);
}
static inline void UnregisterCTryCatch() {
- assembler::mips::Simulator::current()->PopAddress();
+ Simulator::current(Isolate::Current())->PopAddress();
}
};
-#endif // !defined(__mips) || defined(USE_SIMULATOR)
+} } // namespace v8::internal
+#endif // !defined(USE_SIMULATOR)
#endif // V8_MIPS_SIMULATOR_MIPS_H_
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 683b8626..1a495581 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -57,6 +57,12 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
}
+void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
+ MacroAssembler* masm, int index, Register prototype, Label* miss) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
// Load a fast property out of a holder object (src). In-object properties
// are loaded directly otherwise the property is loaded from the properties
// fixed array.
@@ -75,6 +81,20 @@ void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
}
+// Generate code to load the length from a string object and return the length.
+// If the receiver object is not a string or a wrapped string object the
+// execution continues at the miss label. The register containing the
+// receiver is potentially clobbered.
+void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Label* miss,
+ bool support_wrappers) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
Register scratch1,
@@ -84,7 +104,7 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
}
-// Generate StoreField code, value is passed in r0 register.
+// Generate StoreField code, value is passed in a0 register.
// After executing generated code, the receiver_reg and name_reg
// may be clobbered.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
@@ -104,15 +124,94 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
}
+class CallInterceptorCompiler BASE_EMBEDDED {
+ public:
+ CallInterceptorCompiler(StubCompiler* stub_compiler,
+ const ParameterCount& arguments,
+ Register name)
+ : stub_compiler_(stub_compiler),
+ arguments_(arguments),
+ name_(name) {}
+
+ void Compile(MacroAssembler* masm,
+ JSObject* object,
+ JSObject* holder,
+ String* name,
+ LookupResult* lookup,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* miss) {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ private:
+ void CompileCacheable(MacroAssembler* masm,
+ JSObject* object,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ JSObject* interceptor_holder,
+ LookupResult* lookup,
+ String* name,
+ const CallOptimization& optimization,
+ Label* miss_label) {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ void CompileRegular(MacroAssembler* masm,
+ JSObject* object,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ String* name,
+ JSObject* interceptor_holder,
+ Label* miss_label) {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ void LoadWithInterceptor(MacroAssembler* masm,
+ Register receiver,
+ Register holder,
+ JSObject* holder_obj,
+ Register scratch,
+ Label* interceptor_succeeded) {
+ UNIMPLEMENTED_MIPS();
+ }
+
+ StubCompiler* stub_compiler_;
+ const ParameterCount& arguments_;
+ Register name_;
+};
+
+
#undef __
#define __ ACCESS_MASM(masm())
+Register StubCompiler::CheckPrototypes(JSObject* object,
+ Register object_reg,
+ JSObject* holder,
+ Register holder_reg,
+ Register scratch1,
+ Register scratch2,
+ String* name,
+ int save_at_depth,
+ Label* miss) {
+ UNIMPLEMENTED_MIPS();
+ return no_reg;
+}
+
+
void StubCompiler::GenerateLoadField(JSObject* object,
JSObject* holder,
Register receiver,
Register scratch1,
Register scratch2,
+ Register scratch3,
int index,
String* name,
Label* miss) {
@@ -125,6 +224,7 @@ void StubCompiler::GenerateLoadConstant(JSObject* object,
Register receiver,
Register scratch1,
Register scratch2,
+ Register scratch3,
Object* value,
String* name,
Label* miss) {
@@ -132,282 +232,365 @@ void StubCompiler::GenerateLoadConstant(JSObject* object,
}
-bool StubCompiler::GenerateLoadCallback(JSObject* object,
- JSObject* holder,
- Register receiver,
- Register name_reg,
- Register scratch1,
- Register scratch2,
- AccessorInfo* callback,
- String* name,
- Label* miss,
- Failure** failure) {
+MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ AccessorInfo* callback,
+ String* name,
+ Label* miss) {
UNIMPLEMENTED_MIPS();
- __ break_(0x470);
- return false; // UNIMPLEMENTED RETURN
+ return NULL;
}
void StubCompiler::GenerateLoadInterceptor(JSObject* object,
- JSObject* holder,
+ JSObject* interceptor_holder,
LookupResult* lookup,
Register receiver,
Register name_reg,
Register scratch1,
Register scratch2,
+ Register scratch3,
String* name,
Label* miss) {
UNIMPLEMENTED_MIPS();
- __ break_(0x505);
}
-Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
- // Registers:
- // a1: function
- // ra: return address
+void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
+ UNIMPLEMENTED_MIPS();
+}
- // Enter an internal frame.
- __ EnterInternalFrame();
- // Preserve the function.
- __ Push(a1);
- // Setup aligned call.
- __ SetupAlignedCall(t0, 1);
- // Push the function on the stack as the argument to the runtime function.
- __ Push(a1);
- // Call the runtime function
- __ CallRuntime(Runtime::kLazyCompile, 1);
- __ ReturnFromAlignedCall();
- // Calculate the entry point.
- __ addiu(t9, v0, Code::kHeaderSize - kHeapObjectTag);
- // Restore saved function.
- __ Pop(a1);
- // Tear down temporary frame.
- __ LeaveInternalFrame();
- // Do a tail-call of the compiled function.
- __ Jump(t9);
- return GetCodeWithFlags(flags, "LazyCompileStub");
+void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
+ JSObject* holder,
+ String* name,
+ Label* miss) {
+ UNIMPLEMENTED_MIPS();
}
-Object* CallStubCompiler::CompileCallField(JSObject* object,
- JSObject* holder,
- int index,
- String* name) {
+void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ Label* miss) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
}
-Object* CallStubCompiler::CompileArrayPushCall(Object* object,
- JSObject* holder,
- JSFunction* function,
- String* name,
- CheckType check) {
+MaybeObject* CallStubCompiler::GenerateMissBranch() {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* CallStubCompiler::CompileArrayPopCall(Object* object,
- JSObject* holder,
- JSFunction* function,
- String* name,
- CheckType check) {
+MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
+ JSObject* holder,
+ int index,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* CallStubCompiler::CompileCallConstant(Object* object,
- JSObject* holder,
- JSFunction* function,
- String* name,
- CheckType check) {
+MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
- JSObject* holder,
- String* name) {
+MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
UNIMPLEMENTED_MIPS();
- __ break_(0x782);
- return GetCode(INTERCEPTOR, name);
+ return NULL;
}
-Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
- GlobalObject* holder,
- JSGlobalPropertyCell* cell,
- JSFunction* function,
- String* name) {
+MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
+ Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* StoreStubCompiler::CompileStoreField(JSObject* object,
- int index,
- Map* transition,
- String* name) {
+MaybeObject* CallStubCompiler::CompileStringCharAtCall(
+ Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
- AccessorInfo* callback,
- String* name) {
+MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
+ Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
UNIMPLEMENTED_MIPS();
- __ break_(0x906);
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
- String* name) {
+MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
- JSGlobalPropertyCell* cell,
- String* name) {
+MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* LoadStubCompiler::CompileLoadField(JSObject* object,
- JSObject* holder,
- int index,
- String* name) {
+MaybeObject* CallStubCompiler::CompileFastApiCall(
+ const CallOptimization& optimization,
+ Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* LoadStubCompiler::CompileLoadCallback(String* name,
- JSObject* object,
- JSObject* holder,
- AccessorInfo* callback) {
+MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
+ JSObject* holder,
+ JSFunction* function,
+ String* name,
+ CheckType check) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
- JSObject* holder,
- Object* value,
- String* name) {
+MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
+ JSObject* holder,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
- JSObject* holder,
+MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
+ GlobalObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
- GlobalObject* holder,
- JSGlobalPropertyCell* cell,
- String* name,
- bool is_dont_delete) {
+MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
+ int index,
+ Map* transition,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
- JSObject* receiver,
+MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
+ AccessorInfo* callback,
+ String* name) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
+ String* name) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
+ JSGlobalPropertyCell* cell,
+ String* name) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
+ JSObject* object,
+ JSObject* last) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
JSObject* holder,
- int index) {
+ int index,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
- JSObject* receiver,
+MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
+ JSObject* object,
JSObject* holder,
AccessorInfo* callback) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
- JSObject* receiver,
+MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
JSObject* holder,
- Object* value) {
+ Object* value,
+ String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
+MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
JSObject* holder,
String* name) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
+MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
+ GlobalObject* holder,
+ JSGlobalPropertyCell* cell,
+ String* name,
+ bool is_dont_delete) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
+MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
+ JSObject* receiver,
+ JSObject* holder,
+ int index) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-// TODO(1224671): implement the fast case.
-Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
+MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
+ String* name,
+ JSObject* receiver,
+ JSObject* holder,
+ AccessorInfo* callback) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
- int index,
- Map* transition,
- String* name) {
+MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
+ JSObject* receiver,
+ JSObject* holder,
+ Object* value) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
+ JSObject* holder,
+ String* name) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
+ int index,
+ Map* transition,
+ String* name) {
+ UNIMPLEMENTED_MIPS();
+ return NULL;
+}
+
+
+MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
+ JSObject* receiver) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* ConstructStubCompiler::CompileConstructStub(
- SharedFunctionInfo* shared) {
+MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* ExternalArrayStubCompiler::CompileKeyedLoadStub(
- ExternalArrayType array_type, Code::Flags flags) {
+MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
+ JSObject* receiver_object,
+ ExternalArrayType array_type,
+ Code::Flags flags) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
-Object* ExternalArrayStubCompiler::CompileKeyedStoreStub(
- ExternalArrayType array_type, Code::Flags flags) {
+MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
+ JSObject* receiver_object,
+ ExternalArrayType array_type,
+ Code::Flags flags) {
UNIMPLEMENTED_MIPS();
- return reinterpret_cast<Object*>(NULL); // UNIMPLEMENTED RETURN
+ return NULL;
}
diff --git a/src/mips/fast-codegen-mips.cc b/src/mips/virtual-frame-mips-inl.h
index 186f9fad..f0d2fab0 100644
--- a/src/mips/fast-codegen-mips.cc
+++ b/src/mips/virtual-frame-mips-inl.h
@@ -25,53 +25,34 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "v8.h"
+#ifndef V8_VIRTUAL_FRAME_MIPS_INL_H_
+#define V8_VIRTUAL_FRAME_MIPS_INL_H_
-#if defined(V8_TARGET_ARCH_MIPS)
-
-#include "codegen-inl.h"
-#include "fast-codegen.h"
+#include "assembler-mips.h"
+#include "virtual-frame-mips.h"
namespace v8 {
namespace internal {
-#define __ ACCESS_MASM(masm_)
-
-Register FastCodeGenerator::accumulator0() { return no_reg; }
-Register FastCodeGenerator::accumulator1() { return no_reg; }
-Register FastCodeGenerator::scratch0() { return no_reg; }
-Register FastCodeGenerator::scratch1() { return no_reg; }
-Register FastCodeGenerator::receiver_reg() { return no_reg; }
-Register FastCodeGenerator::context_reg() { return no_reg; }
-
-
-void FastCodeGenerator::Generate(CompilationInfo* info) {
- UNIMPLEMENTED_MIPS();
-}
-
-
-void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
- UNIMPLEMENTED_MIPS();
-}
-
-void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> name) {
+MemOperand VirtualFrame::ParameterAt(int index) {
UNIMPLEMENTED_MIPS();
+ return MemOperand(zero_reg, 0);
}
-void FastCodeGenerator::EmitThisPropertyLoad(Handle<String> name) {
+// The receiver frame slot.
+MemOperand VirtualFrame::Receiver() {
UNIMPLEMENTED_MIPS();
+ return MemOperand(zero_reg, 0);
}
-void FastCodeGenerator::EmitBitOr() {
+void VirtualFrame::Forget(int count) {
UNIMPLEMENTED_MIPS();
}
-#undef __
-
} } // namespace v8::internal
-#endif // V8_TARGET_ARCH_MIPS
+#endif // V8_VIRTUAL_FRAME_MIPS_INL_H_
diff --git a/src/mips/virtual-frame-mips.cc b/src/mips/virtual-frame-mips.cc
index b61ce75b..22fe9f06 100644
--- a/src/mips/virtual-frame-mips.cc
+++ b/src/mips/virtual-frame-mips.cc
@@ -25,8 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
#include "v8.h"
#if defined(V8_TARGET_ARCH_MIPS)
@@ -39,44 +37,50 @@
namespace v8 {
namespace internal {
-// -------------------------------------------------------------------------
-// VirtualFrame implementation.
-
#define __ ACCESS_MASM(masm())
-void VirtualFrame::SyncElementBelowStackPointer(int index) {
- UNREACHABLE();
+void VirtualFrame::PopToA1A0() {
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::SyncElementByPushing(int index) {
- UNREACHABLE();
+void VirtualFrame::PopToA1() {
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::SyncRange(int begin, int end) {
- // All elements are in memory on MIPS (ie, synced).
-#ifdef DEBUG
- for (int i = begin; i <= end; i++) {
- ASSERT(elements_[i].is_synced());
- }
-#endif
+void VirtualFrame::PopToA0() {
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::MergeTo(VirtualFrame* expected) {
+void VirtualFrame::MergeTo(const VirtualFrame* expected,
+ Condition cond,
+ Register r1,
+ const Operand& r2) {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::Enter() {
- // TODO(MIPS): Implement DEBUG
+void VirtualFrame::MergeTo(VirtualFrame* expected,
+ Condition cond,
+ Register r1,
+ const Operand& r2) {
+ UNIMPLEMENTED_MIPS();
+}
+
- // We are about to push four values to the frame.
- Adjust(4);
- __ MultiPush(ra.bit() | fp.bit() | cp.bit() | a1.bit());
- // Adjust FP to point to saved FP.
- __ addiu(fp, sp, 2 * kPointerSize);
+void VirtualFrame::MergeTOSTo(
+ VirtualFrame::TopOfStack expected_top_of_stack_state,
+ Condition cond,
+ Register r1,
+ const Operand& r2) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void VirtualFrame::Enter() {
+ UNIMPLEMENTED_MIPS();
}
@@ -86,232 +90,216 @@ void VirtualFrame::Exit() {
void VirtualFrame::AllocateStackSlots() {
- int count = local_count();
- if (count > 0) {
- Comment cmnt(masm(), "[ Allocate space for locals");
- Adjust(count);
- // Initialize stack slots with 'undefined' value.
- __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
- __ addiu(sp, sp, -count * kPointerSize);
- for (int i = 0; i < count; i++) {
- __ sw(t0, MemOperand(sp, (count-i-1)*kPointerSize));
- }
- }
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::SaveContextRegister() {
+
+void VirtualFrame::PushReceiverSlotAddress() {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::RestoreContextRegister() {
+void VirtualFrame::PushTryHandler(HandlerType type) {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::PushReceiverSlotAddress() {
+void VirtualFrame::CallJSFunction(int arg_count) {
UNIMPLEMENTED_MIPS();
}
-int VirtualFrame::InvalidateFrameSlotAt(int index) {
- return kIllegalIndex;
+void VirtualFrame::CallRuntime(const Runtime::Function* f, int arg_count) {
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::TakeFrameSlotAt(int index) {
+void VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::StoreToFrameSlotAt(int index) {
+#ifdef ENABLE_DEBUGGER_SUPPORT
+void VirtualFrame::DebugBreak() {
UNIMPLEMENTED_MIPS();
}
+#endif
-void VirtualFrame::PushTryHandler(HandlerType type) {
+void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
+ InvokeJSFlags flags,
+ int arg_count) {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::RawCallStub(CodeStub* stub) {
+void VirtualFrame::CallLoadIC(Handle<String> name, RelocInfo::Mode mode) {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::CallStub(CodeStub* stub, Result* arg) {
+void VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) {
+void VirtualFrame::CallKeyedLoadIC() {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
- PrepareForCall(arg_count, arg_count);
- ASSERT(cgen()->HasValidEntryRegisters());
- __ CallRuntime(f, arg_count);
+void VirtualFrame::CallKeyedStoreIC() {
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
- PrepareForCall(arg_count, arg_count);
- ASSERT(cgen()->HasValidEntryRegisters());
- __ CallRuntime(id, arg_count);
+void VirtualFrame::CallCodeObject(Handle<Code> code,
+ RelocInfo::Mode rmode,
+ int dropped_args) {
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::CallAlignedRuntime(Runtime::Function* f, int arg_count) {
+// NO_TOS_REGISTERS, A0_TOS, A1_TOS, A1_A0_TOS, A0_A1_TOS.
+const bool VirtualFrame::kA0InUse[TOS_STATES] =
+ { false, true, false, true, true };
+const bool VirtualFrame::kA1InUse[TOS_STATES] =
+ { false, false, true, true, true };
+const int VirtualFrame::kVirtualElements[TOS_STATES] =
+ { 0, 1, 1, 2, 2 };
+const Register VirtualFrame::kTopRegister[TOS_STATES] =
+ { a0, a0, a1, a1, a0 };
+const Register VirtualFrame::kBottomRegister[TOS_STATES] =
+ { a0, a0, a1, a0, a1 };
+const Register VirtualFrame::kAllocatedRegisters[
+ VirtualFrame::kNumberOfAllocatedRegisters] = { a2, a3, t0, t1, t2 };
+// Popping is done by the transition implied by kStateAfterPop. Of course if
+// there were no stack slots allocated to registers then the physical SP must
+// be adjusted.
+const VirtualFrame::TopOfStack VirtualFrame::kStateAfterPop[TOS_STATES] =
+ { NO_TOS_REGISTERS, NO_TOS_REGISTERS, NO_TOS_REGISTERS, A0_TOS, A1_TOS };
+// Pushing is done by the transition implied by kStateAfterPush. Of course if
+// the maximum number of registers was already allocated to the top of stack
+// slots then one register must be physically pushed onto the stack.
+const VirtualFrame::TopOfStack VirtualFrame::kStateAfterPush[TOS_STATES] =
+ { A0_TOS, A1_A0_TOS, A0_A1_TOS, A0_A1_TOS, A1_A0_TOS };
+
+
+void VirtualFrame::Drop(int count) {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::CallAlignedRuntime(Runtime::FunctionId id, int arg_count) {
+void VirtualFrame::Pop() {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
- InvokeJSFlags flags,
- Result* arg_count_register,
- int arg_count) {
+void VirtualFrame::EmitPop(Register reg) {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::CallCodeObject(Handle<Code> code,
- RelocInfo::Mode rmode,
- int dropped_args) {
- switch (code->kind()) {
- case Code::CALL_IC:
- break;
- case Code::FUNCTION:
- UNIMPLEMENTED_MIPS();
- break;
- case Code::KEYED_LOAD_IC:
- UNIMPLEMENTED_MIPS();
- break;
- case Code::LOAD_IC:
- UNIMPLEMENTED_MIPS();
- break;
- case Code::KEYED_STORE_IC:
- UNIMPLEMENTED_MIPS();
- break;
- case Code::STORE_IC:
- UNIMPLEMENTED_MIPS();
- break;
- case Code::BUILTIN:
- UNIMPLEMENTED_MIPS();
- break;
- default:
- UNREACHABLE();
- break;
- }
- Forget(dropped_args);
- ASSERT(cgen()->HasValidEntryRegisters());
- __ Call(code, rmode);
+void VirtualFrame::SpillAllButCopyTOSToA0() {
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::CallCodeObject(Handle<Code> code,
- RelocInfo::Mode rmode,
- Result* arg,
- int dropped_args) {
+void VirtualFrame::SpillAllButCopyTOSToA1() {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::CallCodeObject(Handle<Code> code,
- RelocInfo::Mode rmode,
- Result* arg0,
- Result* arg1,
- int dropped_args,
- bool set_auto_args_slots) {
+void VirtualFrame::SpillAllButCopyTOSToA1A0() {
UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::Drop(int count) {
- ASSERT(count >= 0);
- ASSERT(height() >= count);
- int num_virtual_elements = (element_count() - 1) - stack_pointer_;
+Register VirtualFrame::Peek() {
+ UNIMPLEMENTED_MIPS();
+ return no_reg;
+}
- // Emit code to lower the stack pointer if necessary.
- if (num_virtual_elements < count) {
- int num_dropped = count - num_virtual_elements;
- stack_pointer_ -= num_dropped;
- __ addiu(sp, sp, num_dropped * kPointerSize);
- }
- // Discard elements from the virtual frame and free any registers.
- for (int i = 0; i < count; i++) {
- FrameElement dropped = elements_.RemoveLast();
- if (dropped.is_register()) {
- Unuse(dropped.reg());
- }
- }
+Register VirtualFrame::Peek2() {
+ UNIMPLEMENTED_MIPS();
+ return no_reg;
}
-void VirtualFrame::DropFromVFrameOnly(int count) {
+void VirtualFrame::Dup() {
UNIMPLEMENTED_MIPS();
}
-Result VirtualFrame::Pop() {
+void VirtualFrame::Dup2() {
UNIMPLEMENTED_MIPS();
- Result res = Result();
- return res; // UNIMPLEMENTED RETURN
}
-void VirtualFrame::EmitPop(Register reg) {
- ASSERT(stack_pointer_ == element_count() - 1);
- stack_pointer_--;
- elements_.RemoveLast();
- __ Pop(reg);
+Register VirtualFrame::PopToRegister(Register but_not_to_this_one) {
+ UNIMPLEMENTED_MIPS();
+ return no_reg;
+}
+
+
+void VirtualFrame::EnsureOneFreeTOSRegister() {
+ UNIMPLEMENTED_MIPS();
}
void VirtualFrame::EmitMultiPop(RegList regs) {
- ASSERT(stack_pointer_ == element_count() - 1);
- for (int16_t i = 0; i < kNumRegisters; i++) {
- if ((regs & (1 << i)) != 0) {
- stack_pointer_--;
- elements_.RemoveLast();
- }
- }
- __ MultiPop(regs);
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void VirtualFrame::EmitPush(Register reg, TypeInfo info) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void VirtualFrame::SetElementAt(Register reg, int this_far_down) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+Register VirtualFrame::GetTOSRegister() {
+ UNIMPLEMENTED_MIPS();
+ return no_reg;
+}
+
+
+void VirtualFrame::EmitPush(Operand operand, TypeInfo info) {
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::EmitPush(Register reg) {
- ASSERT(stack_pointer_ == element_count() - 1);
- elements_.Add(FrameElement::MemoryElement(NumberInfo::Unknown()));
- stack_pointer_++;
- __ Push(reg);
+void VirtualFrame::EmitPush(MemOperand operand, TypeInfo info) {
+ UNIMPLEMENTED_MIPS();
+}
+
+
+void VirtualFrame::EmitPushRoot(Heap::RootListIndex index) {
+ UNIMPLEMENTED_MIPS();
}
void VirtualFrame::EmitMultiPush(RegList regs) {
- ASSERT(stack_pointer_ == element_count() - 1);
- for (int16_t i = kNumRegisters; i > 0; i--) {
- if ((regs & (1 << i)) != 0) {
- elements_.Add(FrameElement::MemoryElement(NumberInfo::Unknown()));
- stack_pointer_++;
- }
- }
- __ MultiPush(regs);
+ UNIMPLEMENTED_MIPS();
}
-void VirtualFrame::EmitArgumentSlots(RegList reglist) {
+void VirtualFrame::EmitMultiPushReversed(RegList regs) {
UNIMPLEMENTED_MIPS();
}
+
+void VirtualFrame::SpillAll() {
+ UNIMPLEMENTED_MIPS();
+}
+
+
#undef __
} } // namespace v8::internal
diff --git a/src/mips/virtual-frame-mips.h b/src/mips/virtual-frame-mips.h
index b32e2aee..be8b74e8 100644
--- a/src/mips/virtual-frame-mips.h
+++ b/src/mips/virtual-frame-mips.h
@@ -30,11 +30,13 @@
#define V8_MIPS_VIRTUAL_FRAME_MIPS_H_
#include "register-allocator.h"
-#include "scopes.h"
namespace v8 {
namespace internal {
+// This dummy class is only used to create invalid virtual frames.
+extern class InvalidVirtualFrameInitializer {}* kInvalidVirtualFrameInitializer;
+
// -------------------------------------------------------------------------
// Virtual frames
@@ -47,14 +49,54 @@ namespace internal {
class VirtualFrame : public ZoneObject {
public:
+ class RegisterAllocationScope;
// A utility class to introduce a scope where the virtual frame is
// expected to remain spilled. The constructor spills the code
- // generator's current frame, but no attempt is made to require it
- // to stay spilled. It is intended as documentation while the code
- // generator is being transformed.
+ // generator's current frame, and keeps it spilled.
class SpilledScope BASE_EMBEDDED {
public:
+ explicit SpilledScope(VirtualFrame* frame)
+ : old_is_spilled_(
+ Isolate::Current()->is_virtual_frame_in_spilled_scope()) {
+ if (frame != NULL) {
+ if (!old_is_spilled_) {
+ frame->SpillAll();
+ } else {
+ frame->AssertIsSpilled();
+ }
+ }
+ Isolate::Current()->set_is_virtual_frame_in_spilled_scope(true);
+ }
+ ~SpilledScope() {
+ Isolate::Current()->set_is_virtual_frame_in_spilled_scope(
+ old_is_spilled_);
+ }
+ static bool is_spilled() {
+ return Isolate::Current()->is_virtual_frame_in_spilled_scope();
+ }
+
+ private:
+ int old_is_spilled_;
+
SpilledScope() {}
+
+ friend class RegisterAllocationScope;
+ };
+
+ class RegisterAllocationScope BASE_EMBEDDED {
+ public:
+ // A utility class to introduce a scope where the virtual frame
+ // is not spilled, ie. where register allocation occurs. Eventually
+ // when RegisterAllocationScope is ubiquitous it can be removed
+ // along with the (by then unused) SpilledScope class.
+ inline explicit RegisterAllocationScope(CodeGenerator* cgen);
+ inline ~RegisterAllocationScope();
+
+ private:
+ CodeGenerator* cgen_;
+ bool old_is_spilled_;
+
+ RegisterAllocationScope() {}
};
// An illegal index into the virtual frame.
@@ -63,45 +105,49 @@ class VirtualFrame : public ZoneObject {
// Construct an initial virtual frame on entry to a JS function.
inline VirtualFrame();
+ // Construct an invalid virtual frame, used by JumpTargets.
+ inline VirtualFrame(InvalidVirtualFrameInitializer* dummy);
+
// Construct a virtual frame as a clone of an existing one.
explicit inline VirtualFrame(VirtualFrame* original);
- CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
- MacroAssembler* masm() { return cgen()->masm(); }
-
- // Create a duplicate of an existing valid frame element.
- FrameElement CopyElementAt(int index,
- NumberInfo info = NumberInfo::Unknown());
+ inline CodeGenerator* cgen() const;
+ inline MacroAssembler* masm();
// The number of elements on the virtual frame.
- int element_count() { return elements_.length(); }
+ int element_count() const { return element_count_; }
// The height of the virtual expression stack.
- int height() {
- return element_count() - expression_base_index();
- }
-
- int register_location(int num) {
- ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
- return register_locations_[num];
- }
-
- int register_location(Register reg) {
- return register_locations_[RegisterAllocator::ToNumber(reg)];
- }
-
- void set_register_location(Register reg, int index) {
- register_locations_[RegisterAllocator::ToNumber(reg)] = index;
- }
+ inline int height() const;
bool is_used(int num) {
- ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
- return register_locations_[num] != kIllegalIndex;
- }
-
- bool is_used(Register reg) {
- return register_locations_[RegisterAllocator::ToNumber(reg)]
- != kIllegalIndex;
+ switch (num) {
+ case 0: { // a0.
+ return kA0InUse[top_of_stack_state_];
+ }
+ case 1: { // a1.
+ return kA1InUse[top_of_stack_state_];
+ }
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6: { // a2 to a3, t0 to t2.
+ ASSERT(num - kFirstAllocatedRegister < kNumberOfAllocatedRegisters);
+ ASSERT(num >= kFirstAllocatedRegister);
+ if ((register_allocation_map_ &
+ (1 << (num - kFirstAllocatedRegister))) == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ default: {
+ ASSERT(num < kFirstAllocatedRegister ||
+ num >= kFirstAllocatedRegister + kNumberOfAllocatedRegisters);
+ return false;
+ }
+ }
}
// Add extra in-memory elements to the top of the frame to match an actual
@@ -110,53 +156,60 @@ class VirtualFrame : public ZoneObject {
void Adjust(int count);
// Forget elements from the top of the frame to match an actual frame (eg,
- // the frame after a runtime call). No code is emitted.
- void Forget(int count) {
- ASSERT(count >= 0);
- ASSERT(stack_pointer_ == element_count() - 1);
- stack_pointer_ -= count;
- // On mips, all elements are in memory, so there is no extra bookkeeping
- // (registers, copies, etc.) beyond dropping the elements.
- elements_.Rewind(stack_pointer_ + 1);
- }
+ // the frame after a runtime call). No code is emitted except to bring the
+ // frame to a spilled state.
+ void Forget(int count);
- // Forget count elements from the top of the frame and adjust the stack
- // pointer downward. This is used, for example, before merging frames at
- // break, continue, and return targets.
- void ForgetElements(int count);
// Spill all values from the frame to memory.
void SpillAll();
+ void AssertIsSpilled() const {
+ ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS);
+ ASSERT(register_allocation_map_ == 0);
+ }
+
+ void AssertIsNotSpilled() {
+ ASSERT(!SpilledScope::is_spilled());
+ }
+
// Spill all occurrences of a specific register from the frame.
void Spill(Register reg) {
- if (is_used(reg)) SpillElementAt(register_location(reg));
+ UNIMPLEMENTED();
}
// Spill all occurrences of an arbitrary register if possible. Return the
// register spilled or no_reg if it was not possible to free any register
- // (ie, they all have frame-external references).
+ // (ie, they all have frame-external references). Unimplemented.
Register SpillAnyRegister();
- // Prepare this virtual frame for merging to an expected frame by
- // performing some state changes that do not require generating
- // code. It is guaranteed that no code will be generated.
- void PrepareMergeTo(VirtualFrame* expected);
-
// Make this virtual frame have a state identical to an expected virtual
// frame. As a side effect, code may be emitted to make this frame match
// the expected one.
- void MergeTo(VirtualFrame* expected);
+ void MergeTo(const VirtualFrame* expected,
+ Condition cond = al,
+ Register r1 = no_reg,
+ const Operand& r2 = Operand(no_reg));
+
+ void MergeTo(VirtualFrame* expected,
+ Condition cond = al,
+ Register r1 = no_reg,
+ const Operand& r2 = Operand(no_reg));
+
+ // Checks whether this frame can be branched to by the other frame.
+ bool IsCompatibleWith(const VirtualFrame* other) const {
+ return (tos_known_smi_map_ & (~other->tos_known_smi_map_)) == 0;
+ }
+
+ inline void ForgetTypeInfo() {
+ tos_known_smi_map_ = 0;
+ }
// Detach a frame from its code generator, perhaps temporarily. This
// tells the register allocator that it is free to use frame-internal
// registers. Used when the code generator's frame is switched from this
// one to NULL by an unconditional jump.
void DetachFromCodeGenerator() {
- RegisterAllocator* cgen_allocator = cgen()->allocator();
- for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
- if (is_used(i)) cgen_allocator->Unuse(i);
- }
}
// (Re)attach a frame to its code generator. This informs the register
@@ -164,10 +217,6 @@ class VirtualFrame : public ZoneObject {
// Used when a code generator's frame is switched from NULL to this one by
// binding a label.
void AttachToCodeGenerator() {
- RegisterAllocator* cgen_allocator = cgen()->allocator();
- for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
- if (is_used(i)) cgen_allocator->Unuse(i);
- }
}
// Emit code for the physical JS entry and exit frame sequences. After
@@ -177,176 +226,142 @@ class VirtualFrame : public ZoneObject {
void Enter();
void Exit();
- // Prepare for returning from the frame by spilling locals and
- // dropping all non-locals elements in the virtual frame. This
- // avoids generating unnecessary merge code when jumping to the
- // shared return site. Emits code for spills.
- void PrepareForReturn();
+ // Prepare for returning from the frame by elements in the virtual frame.
+ // This avoids generating unnecessary merge code when jumping to the shared
+ // return site. No spill code emitted. Value to return should be in v0.
+ inline void PrepareForReturn();
+
+ // Number of local variables after when we use a loop for allocating.
+ static const int kLocalVarBound = 5;
// Allocate and initialize the frame-allocated locals.
void AllocateStackSlots();
// The current top of the expression stack as an assembly operand.
- MemOperand Top() { return MemOperand(sp, 0); }
+ MemOperand Top() {
+ AssertIsSpilled();
+ return MemOperand(sp, 0);
+ }
// An element of the expression stack as an assembly operand.
MemOperand ElementAt(int index) {
- return MemOperand(sp, index * kPointerSize);
- }
-
- // Random-access store to a frame-top relative frame element. The result
- // becomes owned by the frame and is invalidated.
- void SetElementAt(int index, Result* value);
-
- // Set a frame element to a constant. The index is frame-top relative.
- void SetElementAt(int index, Handle<Object> value) {
- Result temp(value);
- SetElementAt(index, &temp);
+ int adjusted_index = index - kVirtualElements[top_of_stack_state_];
+ ASSERT(adjusted_index >= 0);
+ return MemOperand(sp, adjusted_index * kPointerSize);
}
- void PushElementAt(int index) {
- PushFrameSlotAt(element_count() - index - 1);
+ bool KnownSmiAt(int index) {
+ if (index >= kTOSKnownSmiMapSize) return false;
+ return (tos_known_smi_map_ & (1 << index)) != 0;
}
-
// A frame-allocated local as an assembly operand.
- MemOperand LocalAt(int index) {
- ASSERT(0 <= index);
- ASSERT(index < local_count());
- return MemOperand(s8_fp, kLocal0Offset - index * kPointerSize);
- }
-
- // Push a copy of the value of a local frame slot on top of the frame.
- void PushLocalAt(int index) {
- PushFrameSlotAt(local0_index() + index);
- }
-
- // Push the value of a local frame slot on top of the frame and invalidate
- // the local slot. The slot should be written to before trying to read
- // from it again.
- void TakeLocalAt(int index) {
- TakeFrameSlotAt(local0_index() + index);
- }
-
- // Store the top value on the virtual frame into a local frame slot. The
- // value is left in place on top of the frame.
- void StoreToLocalAt(int index) {
- StoreToFrameSlotAt(local0_index() + index);
- }
+ inline MemOperand LocalAt(int index);
// Push the address of the receiver slot on the frame.
void PushReceiverSlotAddress();
// The function frame slot.
- MemOperand Function() { return MemOperand(s8_fp, kFunctionOffset); }
-
- // Push the function on top of the frame.
- void PushFunction() { PushFrameSlotAt(function_index()); }
+ MemOperand Function() { return MemOperand(fp, kFunctionOffset); }
// The context frame slot.
- MemOperand Context() { return MemOperand(s8_fp, kContextOffset); }
-
- // Save the value of the cp register to the context frame slot.
- void SaveContextRegister();
-
- // Restore the cp register from the value of the context frame
- // slot.
- void RestoreContextRegister();
+ MemOperand Context() { return MemOperand(fp, kContextOffset); }
// A parameter as an assembly operand.
- MemOperand ParameterAt(int index) {
- // Index -1 corresponds to the receiver.
- ASSERT(-1 <= index); // -1 is the receiver.
- ASSERT(index <= parameter_count());
- uint16_t a = 0; // Number of argument slots.
- return MemOperand(s8_fp, (1 + parameter_count() + a - index) *kPointerSize);
- }
-
- // Push a copy of the value of a parameter frame slot on top of the frame.
- void PushParameterAt(int index) {
- PushFrameSlotAt(param0_index() + index);
- }
-
- // Push the value of a paramter frame slot on top of the frame and
- // invalidate the parameter slot. The slot should be written to before
- // trying to read from it again.
- void TakeParameterAt(int index) {
- TakeFrameSlotAt(param0_index() + index);
- }
-
- // Store the top value on the virtual frame into a parameter frame slot.
- // The value is left in place on top of the frame.
- void StoreToParameterAt(int index) {
- StoreToFrameSlotAt(param0_index() + index);
- }
+ inline MemOperand ParameterAt(int index);
// The receiver frame slot.
- MemOperand Receiver() { return ParameterAt(-1); }
+ inline MemOperand Receiver();
// Push a try-catch or try-finally handler on top of the virtual frame.
void PushTryHandler(HandlerType type);
// Call stub given the number of arguments it expects on (and
// removes from) the stack.
- void CallStub(CodeStub* stub, int arg_count) {
- PrepareForCall(arg_count, arg_count);
- RawCallStub(stub);
- }
+ inline void CallStub(CodeStub* stub, int arg_count);
- void CallStub(CodeStub* stub, Result* arg);
-
- void CallStub(CodeStub* stub, Result* arg0, Result* arg1);
+ // Call JS function from top of the stack with arguments
+ // taken from the stack.
+ void CallJSFunction(int arg_count);
// Call runtime given the number of arguments expected on (and
// removed from) the stack.
- void CallRuntime(Runtime::Function* f, int arg_count);
+ void CallRuntime(const Runtime::Function* f, int arg_count);
void CallRuntime(Runtime::FunctionId id, int arg_count);
- // Call runtime with sp aligned to 8 bytes.
- void CallAlignedRuntime(Runtime::Function* f, int arg_count);
- void CallAlignedRuntime(Runtime::FunctionId id, int arg_count);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ void DebugBreak();
+#endif
// Invoke builtin given the number of arguments it expects on (and
// removes from) the stack.
void InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flag,
- Result* arg_count_register,
int arg_count);
+ // Call load IC. Receiver is on the stack and is consumed. Result is returned
+ // in v0.
+ void CallLoadIC(Handle<String> name, RelocInfo::Mode mode);
+
+ // Call store IC. If the load is contextual, value is found on top of the
+ // frame. If not, value and receiver are on the frame. Both are consumed.
+ // Result is returned in v0.
+ void CallStoreIC(Handle<String> name, bool is_contextual);
+
+ // Call keyed load IC. Key and receiver are on the stack. Both are consumed.
+ // Result is returned in v0.
+ void CallKeyedLoadIC();
+
+ // Call keyed store IC. Value, key and receiver are on the stack. All three
+ // are consumed. Result is returned in v0 (and a0).
+ void CallKeyedStoreIC();
+
// Call into an IC stub given the number of arguments it removes
- // from the stack. Register arguments are passed as results and
- // consumed by the call.
- void CallCodeObject(Handle<Code> ic,
- RelocInfo::Mode rmode,
- int dropped_args);
+ // from the stack. Register arguments to the IC stub are implicit,
+ // and depend on the type of IC stub.
void CallCodeObject(Handle<Code> ic,
RelocInfo::Mode rmode,
- Result* arg,
int dropped_args);
- void CallCodeObject(Handle<Code> ic,
- RelocInfo::Mode rmode,
- Result* arg0,
- Result* arg1,
- int dropped_args,
- bool set_auto_args_slots = false);
// Drop a number of elements from the top of the expression stack. May
// emit code to affect the physical frame. Does not clobber any registers
// excepting possibly the stack pointer.
void Drop(int count);
- // Similar to VirtualFrame::Drop but we don't modify the actual stack.
- // This is because we need to manually restore sp to the correct position.
- void DropFromVFrameOnly(int count);
// Drop one element.
void Drop() { Drop(1); }
- void DropFromVFrameOnly() { DropFromVFrameOnly(1); }
- // Duplicate the top element of the frame.
- void Dup() { PushFrameSlotAt(element_count() - 1); }
+ // Pop an element from the top of the expression stack. Discards
+ // the result.
+ void Pop();
+
+ // Pop an element from the top of the expression stack. The register
+ // will be one normally used for the top of stack register allocation
+ // so you can't hold on to it if you push on the stack.
+ Register PopToRegister(Register but_not_to_this_one = no_reg);
+
+ // Look at the top of the stack. The register returned is aliased and
+ // must be copied to a scratch register before modification.
+ Register Peek();
+
+ // Look at the value beneath the top of the stack. The register returned is
+ // aliased and must be copied to a scratch register before modification.
+ Register Peek2();
+
+ // Duplicate the top of stack.
+ void Dup();
+
+ // Duplicate the two elements on top of stack.
+ void Dup2();
- // Pop an element from the top of the expression stack. Returns a
- // Result, which may be a constant or a register.
- Result Pop();
+ // Flushes all registers, but it puts a copy of the top-of-stack in a0.
+ void SpillAllButCopyTOSToA0();
+
+ // Flushes all registers, but it puts a copy of the top-of-stack in a1.
+ void SpillAllButCopyTOSToA1();
+
+ // Flushes all registers, but it puts a copy of the top-of-stack in a1
+ // and the next value on the stack in a0.
+ void SpillAllButCopyTOSToA1A0();
// Pop and save an element from the top of the expression stack and
// emit a corresponding pop instruction.
@@ -355,40 +370,41 @@ class VirtualFrame : public ZoneObject {
void EmitMultiPop(RegList regs);
void EmitMultiPopReversed(RegList regs);
+
+ // Takes the top two elements and puts them in a0 (top element) and a1
+ // (second element).
+ void PopToA1A0();
+
+ // Takes the top element and puts it in a1.
+ void PopToA1();
+
+ // Takes the top element and puts it in a0.
+ void PopToA0();
+
// Push an element on top of the expression stack and emit a
// corresponding push instruction.
- void EmitPush(Register reg);
- // Same but for multiple registers.
- void EmitMultiPush(RegList regs);
- void EmitMultiPushReversed(RegList regs);
+ void EmitPush(Register reg, TypeInfo type_info = TypeInfo::Unknown());
+ void EmitPush(Operand operand, TypeInfo type_info = TypeInfo::Unknown());
+ void EmitPush(MemOperand operand, TypeInfo type_info = TypeInfo::Unknown());
+ void EmitPushRoot(Heap::RootListIndex index);
- // Push an element on the virtual frame.
- inline void Push(Register reg, NumberInfo info = NumberInfo::Unknown());
- inline void Push(Handle<Object> value);
- inline void Push(Smi* value);
+ // Overwrite the nth thing on the stack. If the nth position is in a
+ // register then this turns into a Move, otherwise an sw. Afterwards
+ // you can still use the register even if it is a register that can be
+ // used for TOS (a0 or a1).
+ void SetElementAt(Register reg, int this_far_down);
- // Pushing a result invalidates it (its contents become owned by the frame).
- void Push(Result* result) {
- if (result->is_register()) {
- Push(result->reg());
- } else {
- ASSERT(result->is_constant());
- Push(result->handle());
- }
- result->Unuse();
- }
-
- // Nip removes zero or more elements from immediately below the top
- // of the frame, leaving the previous top-of-frame value on top of
- // the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
- inline void Nip(int num_dropped);
+ // Get a register which is free and which must be immediately used to
+ // push on the top of the stack.
+ Register GetTOSRegister();
- // This pushes 4 arguments slots on the stack and saves asked 'a' registers
- // 'a' registers are arguments register a0 to a3.
- void EmitArgumentSlots(RegList reglist);
+ // Same but for multiple registers.
+ void EmitMultiPush(RegList regs);
+ void EmitMultiPushReversed(RegList regs);
- inline void SetTypeForLocalAt(int index, NumberInfo info);
- inline void SetTypeForParamAt(int index, NumberInfo info);
+ static Register scratch0() { return t4; }
+ static Register scratch1() { return t5; }
+ static Register scratch2() { return t6; }
private:
static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
@@ -398,24 +414,51 @@ class VirtualFrame : public ZoneObject {
static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize;
static const int kPreallocatedElements = 5 + 8; // 8 expression stack slots.
- ZoneList<FrameElement> elements_;
+ // 5 states for the top of stack, which can be in memory or in a0 and a1.
+ enum TopOfStack { NO_TOS_REGISTERS, A0_TOS, A1_TOS, A1_A0_TOS, A0_A1_TOS,
+ TOS_STATES};
+ static const int kMaxTOSRegisters = 2;
+
+ static const bool kA0InUse[TOS_STATES];
+ static const bool kA1InUse[TOS_STATES];
+ static const int kVirtualElements[TOS_STATES];
+ static const TopOfStack kStateAfterPop[TOS_STATES];
+ static const TopOfStack kStateAfterPush[TOS_STATES];
+ static const Register kTopRegister[TOS_STATES];
+ static const Register kBottomRegister[TOS_STATES];
+
+ // We allocate up to 5 locals in registers.
+ static const int kNumberOfAllocatedRegisters = 5;
+ // r2 to r6 are allocated to locals.
+ static const int kFirstAllocatedRegister = 2;
+
+ static const Register kAllocatedRegisters[kNumberOfAllocatedRegisters];
+
+ static Register AllocatedRegister(int r) {
+ ASSERT(r >= 0 && r < kNumberOfAllocatedRegisters);
+ return kAllocatedRegisters[r];
+ }
- // The index of the element that is at the processor's stack pointer
- // (the sp register).
- int stack_pointer_;
+ // The number of elements on the stack frame.
+ int element_count_;
+ TopOfStack top_of_stack_state_:3;
+ int register_allocation_map_:kNumberOfAllocatedRegisters;
+ static const int kTOSKnownSmiMapSize = 4;
+ unsigned tos_known_smi_map_:kTOSKnownSmiMapSize;
- // The index of the register frame element using each register, or
- // kIllegalIndex if a register is not on the frame.
- int register_locations_[RegisterAllocator::kNumRegisters];
+ // The index of the element that is at the processor's stack pointer
+ // (the sp register). For now since everything is in memory it is given
+ // by the number of elements on the not-very-virtual stack frame.
+ int stack_pointer() { return element_count_ - 1; }
// The number of frame-allocated locals and parameters respectively.
- int parameter_count() { return cgen()->scope()->num_parameters(); }
- int local_count() { return cgen()->scope()->num_stack_slots(); }
+ inline int parameter_count() const;
+ inline int local_count() const;
// The index of the element that is at the processor's frame pointer
// (the fp register). The parameters, receiver, function, and context
// are below the frame pointer.
- int frame_pointer() { return parameter_count() + 3; }
+ inline int frame_pointer() const;
// The index of the first parameter. The receiver lies below the first
// parameter.
@@ -423,75 +466,22 @@ class VirtualFrame : public ZoneObject {
// The index of the context slot in the frame. It is immediately
// below the frame pointer.
- int context_index() { return frame_pointer() - 1; }
+ inline int context_index();
// The index of the function slot in the frame. It is below the frame
// pointer and context slot.
- int function_index() { return frame_pointer() - 2; }
+ inline int function_index();
// The index of the first local. Between the frame pointer and the
// locals lies the return address.
- int local0_index() { return frame_pointer() + 2; }
+ inline int local0_index() const;
// The index of the base of the expression stack.
- int expression_base_index() { return local0_index() + local_count(); }
+ inline int expression_base_index() const;
// Convert a frame index into a frame pointer relative offset into the
// actual stack.
- int fp_relative(int index) {
- ASSERT(index < element_count());
- ASSERT(frame_pointer() < element_count()); // FP is on the frame.
- return (frame_pointer() - index) * kPointerSize;
- }
-
- // Record an occurrence of a register in the virtual frame. This has the
- // effect of incrementing the register's external reference count and
- // of updating the index of the register's location in the frame.
- void Use(Register reg, int index) {
- ASSERT(!is_used(reg));
- set_register_location(reg, index);
- cgen()->allocator()->Use(reg);
- }
-
- // Record that a register reference has been dropped from the frame. This
- // decrements the register's external reference count and invalidates the
- // index of the register's location in the frame.
- void Unuse(Register reg) {
- ASSERT(is_used(reg));
- set_register_location(reg, kIllegalIndex);
- cgen()->allocator()->Unuse(reg);
- }
-
- // Spill the element at a particular index---write it to memory if
- // necessary, free any associated register, and forget its value if
- // constant.
- void SpillElementAt(int index);
-
- // Sync the element at a particular index. If it is a register or
- // constant that disagrees with the value on the stack, write it to memory.
- // Keep the element type as register or constant, and clear the dirty bit.
- void SyncElementAt(int index);
-
- // Sync the range of elements in [begin, end] with memory.
- void SyncRange(int begin, int end);
-
- // Sync a single unsynced element that lies beneath or at the stack pointer.
- void SyncElementBelowStackPointer(int index);
-
- // Sync a single unsynced element that lies just above the stack pointer.
- void SyncElementByPushing(int index);
-
- // Push a copy of a frame slot (typically a local or parameter) on top of
- // the frame.
- inline void PushFrameSlotAt(int index);
-
- // Push a the value of a frame slot (typically a local or parameter) on
- // top of the frame and invalidate the slot.
- void TakeFrameSlotAt(int index);
-
- // Store the value on top of the frame to a frame slot (typically a local
- // or parameter).
- void StoreToFrameSlotAt(int index);
+ inline int fp_relative(int index);
// Spill all elements in registers. Spill the top spilled_args elements
// on the frame. Sync all other frame elements.
@@ -499,45 +489,37 @@ class VirtualFrame : public ZoneObject {
// the effect of an upcoming call that will drop them from the stack.
void PrepareForCall(int spilled_args, int dropped_args);
- // Move frame elements currently in registers or constants, that
- // should be in memory in the expected frame, to memory.
- void MergeMoveRegistersToMemory(VirtualFrame* expected);
-
- // Make the register-to-register moves necessary to
- // merge this frame with the expected frame.
- // Register to memory moves must already have been made,
- // and memory to register moves must follow this call.
- // This is because some new memory-to-register moves are
- // created in order to break cycles of register moves.
- // Used in the implementation of MergeTo().
- void MergeMoveRegistersToRegisters(VirtualFrame* expected);
-
- // Make the memory-to-register and constant-to-register moves
- // needed to make this frame equal the expected frame.
- // Called after all register-to-memory and register-to-register
- // moves have been made. After this function returns, the frames
- // should be equal.
- void MergeMoveMemoryToRegisters(VirtualFrame* expected);
-
- // Invalidates a frame slot (puts an invalid frame element in it).
- // Copies on the frame are correctly handled, and if this slot was
- // the backing store of copies, the index of the new backing store
- // is returned. Otherwise, returns kIllegalIndex.
- // Register counts are correctly updated.
- int InvalidateFrameSlotAt(int index);
-
- // Call a code stub that has already been prepared for calling (via
- // PrepareForCall).
- void RawCallStub(CodeStub* stub);
-
- // Calls a code object which has already been prepared for calling
- // (via PrepareForCall).
- void RawCallCodeObject(Handle<Code> code, RelocInfo::Mode rmode);
-
- inline bool Equals(VirtualFrame* other);
-
- // Classes that need raw access to the elements_ array.
- friend class DeferredCode;
+ // If all top-of-stack registers are in use then the lowest one is pushed
+ // onto the physical stack and made free.
+ void EnsureOneFreeTOSRegister();
+
+ // Emit instructions to get the top of stack state from where we are to where
+ // we want to be.
+ void MergeTOSTo(TopOfStack expected_state,
+ Condition cond = al,
+ Register r1 = no_reg,
+ const Operand& r2 = Operand(no_reg));
+
+ inline bool Equals(const VirtualFrame* other);
+
+ inline void LowerHeight(int count) {
+ element_count_ -= count;
+ if (count >= kTOSKnownSmiMapSize) {
+ tos_known_smi_map_ = 0;
+ } else {
+ tos_known_smi_map_ >>= count;
+ }
+ }
+
+ inline void RaiseHeight(int count, unsigned known_smi_map = 0) {
+ ASSERT(known_smi_map < (1u << count));
+ element_count_ += count;
+ if (count >= kTOSKnownSmiMapSize) {
+ tos_known_smi_map_ = known_smi_map;
+ } else {
+ tos_known_smi_map_ = ((tos_known_smi_map_ << count) | known_smi_map);
+ }
+ }
friend class JumpTarget;
};
diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js
index 416f8879..99e98197 100644
--- a/src/mirror-debugger.js
+++ b/src/mirror-debugger.js
@@ -170,14 +170,15 @@ PropertyKind.Indexed = 2;
// A copy of the PropertyType enum from global.h
PropertyType = {};
-PropertyType.Normal = 0;
-PropertyType.Field = 1;
-PropertyType.ConstantFunction = 2;
-PropertyType.Callbacks = 3;
-PropertyType.Interceptor = 4;
-PropertyType.MapTransition = 5;
-PropertyType.ConstantTransition = 6;
-PropertyType.NullDescriptor = 7;
+PropertyType.Normal = 0;
+PropertyType.Field = 1;
+PropertyType.ConstantFunction = 2;
+PropertyType.Callbacks = 3;
+PropertyType.Interceptor = 4;
+PropertyType.MapTransition = 5;
+PropertyType.ExternalArrayTransition = 6;
+PropertyType.ConstantTransition = 7;
+PropertyType.NullDescriptor = 8;
// Different attributes for a property.
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index a30b4507..6ecbc8c5 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -223,12 +223,12 @@ int main(int argc, char** argv) {
// Make sure all builtin scripts are cached.
{ HandleScope scope;
for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) {
- i::Bootstrapper::NativesSourceLookup(i);
+ i::Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
}
}
// If we don't do this then we end up with a stray root pointing at the
// context even after we have disposed of the context.
- i::Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
i::Object* raw_context = *(v8::Utils::OpenHandle(*context));
context.Dispose();
CppByteSink sink(argv[1]);
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index c1caef2d..dd606dcd 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -91,8 +91,8 @@ void HeapObject::HeapObjectVerify() {
case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayVerify();
break;
- case PIXEL_ARRAY_TYPE:
- PixelArray::cast(this)->PixelArrayVerify();
+ case EXTERNAL_PIXEL_ARRAY_TYPE:
+ ExternalPixelArray::cast(this)->ExternalPixelArrayVerify();
break;
case EXTERNAL_BYTE_ARRAY_TYPE:
ExternalByteArray::cast(this)->ExternalByteArrayVerify();
@@ -178,7 +178,7 @@ void HeapObject::HeapObjectVerify() {
void HeapObject::VerifyHeapPointer(Object* p) {
ASSERT(p->IsHeapObject());
- ASSERT(Heap::Contains(HeapObject::cast(p)));
+ ASSERT(HEAP->Contains(HeapObject::cast(p)));
}
@@ -192,8 +192,8 @@ void ByteArray::ByteArrayVerify() {
}
-void PixelArray::PixelArrayVerify() {
- ASSERT(IsPixelArray());
+void ExternalPixelArray::ExternalPixelArrayVerify() {
+ ASSERT(IsExternalPixelArray());
}
@@ -241,18 +241,18 @@ void JSObject::JSObjectVerify() {
map()->NextFreePropertyIndex()));
}
ASSERT(map()->has_fast_elements() ==
- (elements()->map() == Heap::fixed_array_map() ||
- elements()->map() == Heap::fixed_cow_array_map()));
+ (elements()->map() == GetHeap()->fixed_array_map() ||
+ elements()->map() == GetHeap()->fixed_cow_array_map()));
ASSERT(map()->has_fast_elements() == HasFastElements());
}
void Map::MapVerify() {
- ASSERT(!Heap::InNewSpace(this));
+ ASSERT(!HEAP->InNewSpace(this));
ASSERT(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE);
ASSERT(instance_size() == kVariableSizeSentinel ||
(kPointerSize <= instance_size() &&
- instance_size() < Heap::Capacity()));
+ instance_size() < HEAP->Capacity()));
VerifyHeapPointer(prototype());
VerifyHeapPointer(instance_descriptors());
}
@@ -261,8 +261,7 @@ void Map::MapVerify() {
void Map::SharedMapVerify() {
MapVerify();
ASSERT(is_shared());
- ASSERT_EQ(Heap::empty_descriptor_array(), instance_descriptors());
- ASSERT_EQ(Heap::empty_fixed_array(), code_cache());
+ ASSERT_EQ(GetHeap()->empty_descriptor_array(), instance_descriptors());
ASSERT_EQ(0, pre_allocated_property_fields());
ASSERT_EQ(0, unused_property_fields());
ASSERT_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()),
@@ -316,7 +315,7 @@ void String::StringVerify() {
CHECK(IsString());
CHECK(length() >= 0 && length() <= Smi::kMaxValue);
if (IsSymbol()) {
- CHECK(!Heap::InNewSpace(this));
+ CHECK(!HEAP->InNewSpace(this));
}
}
@@ -380,7 +379,7 @@ void Oddball::OddballVerify() {
VerifyHeapPointer(to_string());
Object* number = to_number();
if (number->IsHeapObject()) {
- ASSERT(number == Heap::nan_value());
+ ASSERT(number == HEAP->nan_value());
} else {
ASSERT(number->IsSmi());
int value = Smi::cast(number)->value();
@@ -591,16 +590,17 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) {
int holes = 0;
FixedArray* e = FixedArray::cast(elements());
int len = e->length();
+ Heap* heap = HEAP;
for (int i = 0; i < len; i++) {
- if (e->get(i) == Heap::the_hole_value()) holes++;
+ if (e->get(i) == heap->the_hole_value()) holes++;
}
info->number_of_fast_used_elements_ += len - holes;
info->number_of_fast_unused_elements_ += holes;
break;
}
- case PIXEL_ELEMENTS: {
+ case EXTERNAL_PIXEL_ELEMENTS: {
info->number_of_objects_with_fast_elements_++;
- PixelArray* e = PixelArray::cast(elements());
+ ExternalPixelArray* e = ExternalPixelArray::cast(elements());
info->number_of_fast_used_elements_ += e->length();
break;
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index dedb1995..5395bbbf 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -39,9 +39,10 @@
#include "contexts.h"
#include "conversions-inl.h"
#include "heap.h"
-#include "memory.h"
+#include "isolate.h"
#include "property.h"
#include "spaces.h"
+#include "v8memory.h"
namespace v8 {
namespace internal {
@@ -78,7 +79,16 @@ PropertyDetails PropertyDetails::AsDeleted() {
type* holder::name() { return type::cast(READ_FIELD(this, offset)); } \
void holder::set_##name(type* value, WriteBarrierMode mode) { \
WRITE_FIELD(this, offset, value); \
- CONDITIONAL_WRITE_BARRIER(this, offset, mode); \
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, mode); \
+ }
+
+
+// GC-safe accessors do not use HeapObject::GetHeap(), but access TLS instead.
+#define ACCESSORS_GCSAFE(holder, name, type, offset) \
+ type* holder::name() { return type::cast(READ_FIELD(this, offset)); } \
+ void holder::set_##name(type* value, WriteBarrierMode mode) { \
+ WRITE_FIELD(this, offset, value); \
+ CONDITIONAL_WRITE_BARRIER(HEAP, this, offset, mode); \
}
@@ -330,9 +340,10 @@ bool Object::IsByteArray() {
}
-bool Object::IsPixelArray() {
+bool Object::IsExternalPixelArray() {
return Object::IsHeapObject() &&
- HeapObject::cast(this)->map()->instance_type() == PIXEL_ARRAY_TYPE;
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_PIXEL_ARRAY_TYPE;
}
@@ -418,7 +429,7 @@ bool MaybeObject::IsException() {
bool MaybeObject::IsTheHole() {
- return this == Heap::the_hole_value();
+ return !IsFailure() && ToObjectUnchecked()->IsTheHole();
}
@@ -486,22 +497,27 @@ bool Object::IsDeoptimizationOutputData() {
bool Object::IsContext() {
- return Object::IsHeapObject()
- && (HeapObject::cast(this)->map() == Heap::context_map() ||
- HeapObject::cast(this)->map() == Heap::catch_context_map() ||
- HeapObject::cast(this)->map() == Heap::global_context_map());
+ if (Object::IsHeapObject()) {
+ Heap* heap = HeapObject::cast(this)->GetHeap();
+ return (HeapObject::cast(this)->map() == heap->context_map() ||
+ HeapObject::cast(this)->map() == heap->catch_context_map() ||
+ HeapObject::cast(this)->map() == heap->global_context_map());
+ }
+ return false;
}
bool Object::IsCatchContext() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map() == Heap::catch_context_map();
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map() ==
+ HeapObject::cast(this)->GetHeap()->catch_context_map();
}
bool Object::IsGlobalContext() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map() == Heap::global_context_map();
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map() ==
+ HeapObject::cast(this)->GetHeap()->global_context_map();
}
@@ -523,6 +539,7 @@ bool Object::IsCode() {
bool Object::IsOddball() {
+ ASSERT(HEAP->is_safe_to_read_maps());
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == ODDBALL_TYPE;
}
@@ -567,7 +584,8 @@ bool Object::IsProxy() {
bool Object::IsBoolean() {
- return IsTrue() || IsFalse();
+ return IsOddball() &&
+ ((Oddball::cast(this)->kind() & Oddball::kNotBooleanMask) == 0);
}
@@ -589,18 +607,21 @@ template <> inline bool Is<JSArray>(Object* obj) {
bool Object::IsHashTable() {
- return Object::IsHeapObject()
- && HeapObject::cast(this)->map() == Heap::hash_table_map();
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map() ==
+ HeapObject::cast(this)->GetHeap()->hash_table_map();
}
bool Object::IsDictionary() {
- return IsHashTable() && this != Heap::symbol_table();
+ return IsHashTable() && this !=
+ HeapObject::cast(this)->GetHeap()->symbol_table();
}
bool Object::IsSymbolTable() {
- return IsHashTable() && this == Heap::raw_unchecked_symbol_table();
+ return IsHashTable() && this ==
+ HeapObject::cast(this)->GetHeap()->raw_unchecked_symbol_table();
}
@@ -717,27 +738,32 @@ bool Object::IsStruct() {
bool Object::IsUndefined() {
- return this == Heap::undefined_value();
+ return IsOddball() && Oddball::cast(this)->kind() == Oddball::kUndefined;
}
bool Object::IsNull() {
- return this == Heap::null_value();
+ return IsOddball() && Oddball::cast(this)->kind() == Oddball::kNull;
+}
+
+
+bool Object::IsTheHole() {
+ return IsOddball() && Oddball::cast(this)->kind() == Oddball::kTheHole;
}
bool Object::IsTrue() {
- return this == Heap::true_value();
+ return IsOddball() && Oddball::cast(this)->kind() == Oddball::kTrue;
}
bool Object::IsFalse() {
- return this == Heap::false_value();
+ return IsOddball() && Oddball::cast(this)->kind() == Oddball::kFalse;
}
bool Object::IsArgumentsMarker() {
- return this == Heap::arguments_marker();
+ return IsOddball() && Oddball::cast(this)->kind() == Oddball::kArgumentMarker;
}
@@ -749,7 +775,6 @@ double Object::Number() {
}
-
MaybeObject* Object::ToSmi() {
if (IsSmi()) return this;
if (IsHeapNumber()) {
@@ -772,7 +797,7 @@ MaybeObject* Object::GetElement(uint32_t index) {
// GetElement can trigger a getter which can cause allocation.
// This was not always the case. This ASSERT is here to catch
// leftover incorrect uses.
- ASSERT(Heap::IsAllocationAllowed());
+ ASSERT(HEAP->IsAllocationAllowed());
return GetElementWithReceiver(this, index);
}
@@ -806,28 +831,62 @@ MaybeObject* Object::GetProperty(String* key, PropertyAttributes* attributes) {
#define WRITE_FIELD(p, offset, value) \
(*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value)
-
+// TODO(isolates): Pass heap in to these macros.
#define WRITE_BARRIER(object, offset) \
- Heap::RecordWrite(object->address(), offset);
+ object->GetHeap()->RecordWrite(object->address(), offset);
// CONDITIONAL_WRITE_BARRIER must be issued after the actual
// write due to the assert validating the written value.
-#define CONDITIONAL_WRITE_BARRIER(object, offset, mode) \
+#define CONDITIONAL_WRITE_BARRIER(heap, object, offset, mode) \
if (mode == UPDATE_WRITE_BARRIER) { \
- Heap::RecordWrite(object->address(), offset); \
+ heap->RecordWrite(object->address(), offset); \
} else { \
ASSERT(mode == SKIP_WRITE_BARRIER); \
- ASSERT(Heap::InNewSpace(object) || \
- !Heap::InNewSpace(READ_FIELD(object, offset)) || \
+ ASSERT(heap->InNewSpace(object) || \
+ !heap->InNewSpace(READ_FIELD(object, offset)) || \
Page::FromAddress(object->address())-> \
IsRegionDirty(object->address() + offset)); \
}
-#define READ_DOUBLE_FIELD(p, offset) \
- (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)))
+#ifndef V8_TARGET_ARCH_MIPS
+ #define READ_DOUBLE_FIELD(p, offset) \
+ (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)))
+#else // V8_TARGET_ARCH_MIPS
+ // Prevent gcc from using load-double (mips ldc1) on (possibly)
+ // non-64-bit aligned HeapNumber::value.
+ static inline double read_double_field(HeapNumber* p, int offset) {
+ union conversion {
+ double d;
+ uint32_t u[2];
+ } c;
+ c.u[0] = (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset)));
+ c.u[1] = (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset + 4)));
+ return c.d;
+ }
+ #define READ_DOUBLE_FIELD(p, offset) read_double_field(p, offset)
+#endif // V8_TARGET_ARCH_MIPS
+
+
+#ifndef V8_TARGET_ARCH_MIPS
+ #define WRITE_DOUBLE_FIELD(p, offset, value) \
+ (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)) = value)
+#else // V8_TARGET_ARCH_MIPS
+ // Prevent gcc from using store-double (mips sdc1) on (possibly)
+ // non-64-bit aligned HeapNumber::value.
+ static inline void write_double_field(HeapNumber* p, int offset,
+ double value) {
+ union conversion {
+ double d;
+ uint32_t u[2];
+ } c;
+ c.d = value;
+ (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset))) = c.u[0];
+ (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset + 4))) = c.u[1];
+ }
+ #define WRITE_DOUBLE_FIELD(p, offset, value) \
+ write_double_field(p, offset, value)
+#endif // V8_TARGET_ARCH_MIPS
-#define WRITE_DOUBLE_FIELD(p, offset, value) \
- (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)) = value)
#define READ_INT_FIELD(p, offset) \
(*reinterpret_cast<int*>(FIELD_ADDR(p, offset)))
@@ -1098,6 +1157,21 @@ void HeapObject::VerifySmiField(int offset) {
#endif
+Heap* HeapObject::GetHeap() {
+ // During GC, the map pointer in HeapObject is used in various ways that
+ // prevent us from retrieving Heap from the map.
+ // Assert that we are not in GC, implement GC code in a way that it doesn't
+ // pull heap from the map.
+ ASSERT(HEAP->is_safe_to_read_maps());
+ return map()->heap();
+}
+
+
+Isolate* HeapObject::GetIsolate() {
+ return GetHeap()->isolate();
+}
+
+
Map* HeapObject::map() {
return map_word().ToMap();
}
@@ -1215,34 +1289,32 @@ ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
HeapObject* JSObject::elements() {
Object* array = READ_FIELD(this, kElementsOffset);
// In the assert below Dictionary is covered under FixedArray.
- ASSERT(array->IsFixedArray() || array->IsPixelArray() ||
- array->IsExternalArray());
+ ASSERT(array->IsFixedArray() || array->IsExternalArray());
return reinterpret_cast<HeapObject*>(array);
}
void JSObject::set_elements(HeapObject* value, WriteBarrierMode mode) {
ASSERT(map()->has_fast_elements() ==
- (value->map() == Heap::fixed_array_map() ||
- value->map() == Heap::fixed_cow_array_map()));
+ (value->map() == GetHeap()->fixed_array_map() ||
+ value->map() == GetHeap()->fixed_cow_array_map()));
// In the assert below Dictionary is covered under FixedArray.
- ASSERT(value->IsFixedArray() || value->IsPixelArray() ||
- value->IsExternalArray());
+ ASSERT(value->IsFixedArray() || value->IsExternalArray());
WRITE_FIELD(this, kElementsOffset, value);
- CONDITIONAL_WRITE_BARRIER(this, kElementsOffset, mode);
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kElementsOffset, mode);
}
void JSObject::initialize_properties() {
- ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
- WRITE_FIELD(this, kPropertiesOffset, Heap::empty_fixed_array());
+ ASSERT(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array()));
+ WRITE_FIELD(this, kPropertiesOffset, GetHeap()->empty_fixed_array());
}
void JSObject::initialize_elements() {
ASSERT(map()->has_fast_elements());
- ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
- WRITE_FIELD(this, kElementsOffset, Heap::empty_fixed_array());
+ ASSERT(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array()));
+ WRITE_FIELD(this, kElementsOffset, GetHeap()->empty_fixed_array());
}
@@ -1261,6 +1333,16 @@ ACCESSORS(Oddball, to_string, String, kToStringOffset)
ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
+byte Oddball::kind() {
+ return READ_BYTE_FIELD(this, kKindOffset);
+}
+
+
+void Oddball::set_kind(byte value) {
+ WRITE_BYTE_FIELD(this, kKindOffset, value);
+}
+
+
Object* JSGlobalPropertyCell::value() {
return READ_FIELD(this, kValueOffset);
}
@@ -1314,6 +1396,12 @@ int JSObject::GetInternalFieldCount() {
}
+int JSObject::GetInternalFieldOffset(int index) {
+ ASSERT(index < GetInternalFieldCount() && index >= 0);
+ return GetHeaderSize() + (kPointerSize * index);
+}
+
+
Object* JSObject::GetInternalField(int index) {
ASSERT(index < GetInternalFieldCount() && index >= 0);
// Internal objects do follow immediately after the header, whereas in-object
@@ -1365,6 +1453,14 @@ Object* JSObject::FastPropertyAtPut(int index, Object* value) {
}
+int JSObject::GetInObjectPropertyOffset(int index) {
+ // Adjust for the number of properties stored in the object.
+ index -= map()->inobject_properties();
+ ASSERT(index < 0);
+ return map()->instance_size() + (index * kPointerSize);
+}
+
+
Object* JSObject::InObjectPropertyAt(int index) {
// Adjust for the number of properties stored in the object.
index -= map()->inobject_properties();
@@ -1382,14 +1478,14 @@ Object* JSObject::InObjectPropertyAtPut(int index,
ASSERT(index < 0);
int offset = map()->instance_size() + (index * kPointerSize);
WRITE_FIELD(this, offset, value);
- CONDITIONAL_WRITE_BARRIER(this, offset, mode);
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, mode);
return value;
}
void JSObject::InitializeBody(int object_size, Object* value) {
- ASSERT(!value->IsHeapObject() || !Heap::InNewSpace(value));
+ ASSERT(!value->IsHeapObject() || !GetHeap()->InNewSpace(value));
for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) {
WRITE_FIELD(this, offset, value);
}
@@ -1412,7 +1508,7 @@ int JSObject::MaxFastProperties() {
void Struct::InitializeBody(int object_size) {
- Object* value = Heap::undefined_value();
+ Object* value = GetHeap()->undefined_value();
for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) {
WRITE_FIELD(this, offset, value);
}
@@ -1458,7 +1554,7 @@ Object* FixedArray::get(int index) {
void FixedArray::set(int index, Smi* value) {
- ASSERT(map() != Heap::fixed_cow_array_map());
+ ASSERT(map() != HEAP->fixed_cow_array_map());
ASSERT(reinterpret_cast<Object*>(value)->IsSmi());
int offset = kHeaderSize + index * kPointerSize;
WRITE_FIELD(this, offset, value);
@@ -1466,7 +1562,7 @@ void FixedArray::set(int index, Smi* value) {
void FixedArray::set(int index, Object* value) {
- ASSERT(map() != Heap::fixed_cow_array_map());
+ ASSERT(map() != HEAP->fixed_cow_array_map());
ASSERT(index >= 0 && index < this->length());
int offset = kHeaderSize + index * kPointerSize;
WRITE_FIELD(this, offset, value);
@@ -1475,7 +1571,7 @@ void FixedArray::set(int index, Object* value) {
WriteBarrierMode HeapObject::GetWriteBarrierMode(const AssertNoAllocation&) {
- if (Heap::InNewSpace(this)) return SKIP_WRITE_BARRIER;
+ if (GetHeap()->InNewSpace(this)) return SKIP_WRITE_BARRIER;
return UPDATE_WRITE_BARRIER;
}
@@ -1483,44 +1579,55 @@ WriteBarrierMode HeapObject::GetWriteBarrierMode(const AssertNoAllocation&) {
void FixedArray::set(int index,
Object* value,
WriteBarrierMode mode) {
- ASSERT(map() != Heap::fixed_cow_array_map());
+ ASSERT(map() != HEAP->fixed_cow_array_map());
ASSERT(index >= 0 && index < this->length());
int offset = kHeaderSize + index * kPointerSize;
WRITE_FIELD(this, offset, value);
- CONDITIONAL_WRITE_BARRIER(this, offset, mode);
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, mode);
}
void FixedArray::fast_set(FixedArray* array, int index, Object* value) {
- ASSERT(array->map() != Heap::raw_unchecked_fixed_cow_array_map());
+ ASSERT(array->map() != HEAP->raw_unchecked_fixed_cow_array_map());
ASSERT(index >= 0 && index < array->length());
- ASSERT(!Heap::InNewSpace(value));
+ ASSERT(!HEAP->InNewSpace(value));
WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value);
}
void FixedArray::set_undefined(int index) {
- ASSERT(map() != Heap::fixed_cow_array_map());
+ ASSERT(map() != HEAP->fixed_cow_array_map());
+ set_undefined(GetHeap(), index);
+}
+
+
+void FixedArray::set_undefined(Heap* heap, int index) {
ASSERT(index >= 0 && index < this->length());
- ASSERT(!Heap::InNewSpace(Heap::undefined_value()));
+ ASSERT(!heap->InNewSpace(heap->undefined_value()));
WRITE_FIELD(this, kHeaderSize + index * kPointerSize,
- Heap::undefined_value());
+ heap->undefined_value());
}
void FixedArray::set_null(int index) {
- ASSERT(map() != Heap::fixed_cow_array_map());
+ set_null(GetHeap(), index);
+}
+
+
+void FixedArray::set_null(Heap* heap, int index) {
ASSERT(index >= 0 && index < this->length());
- ASSERT(!Heap::InNewSpace(Heap::null_value()));
- WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::null_value());
+ ASSERT(!heap->InNewSpace(heap->null_value()));
+ WRITE_FIELD(this, kHeaderSize + index * kPointerSize, heap->null_value());
}
void FixedArray::set_the_hole(int index) {
- ASSERT(map() != Heap::fixed_cow_array_map());
+ ASSERT(map() != HEAP->fixed_cow_array_map());
ASSERT(index >= 0 && index < this->length());
- ASSERT(!Heap::InNewSpace(Heap::the_hole_value()));
- WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::the_hole_value());
+ ASSERT(!HEAP->InNewSpace(HEAP->the_hole_value()));
+ WRITE_FIELD(this,
+ kHeaderSize + index * kPointerSize,
+ GetHeap()->the_hole_value());
}
@@ -1531,19 +1638,20 @@ void FixedArray::set_unchecked(int index, Smi* value) {
}
-void FixedArray::set_unchecked(int index,
+void FixedArray::set_unchecked(Heap* heap,
+ int index,
Object* value,
WriteBarrierMode mode) {
int offset = kHeaderSize + index * kPointerSize;
WRITE_FIELD(this, offset, value);
- CONDITIONAL_WRITE_BARRIER(this, offset, mode);
+ CONDITIONAL_WRITE_BARRIER(heap, this, offset, mode);
}
-void FixedArray::set_null_unchecked(int index) {
+void FixedArray::set_null_unchecked(Heap* heap, int index) {
ASSERT(index >= 0 && index < this->length());
- ASSERT(!Heap::InNewSpace(Heap::null_value()));
- WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::null_value());
+ ASSERT(!HEAP->InNewSpace(heap->null_value()));
+ WRITE_FIELD(this, kHeaderSize + index * kPointerSize, heap->null_value());
}
@@ -1553,9 +1661,9 @@ Object** FixedArray::data_start() {
bool DescriptorArray::IsEmpty() {
- ASSERT(this == Heap::empty_descriptor_array() ||
- this->length() > 2);
- return this == Heap::empty_descriptor_array();
+ ASSERT(this->length() > kFirstIndex ||
+ this == HEAP->empty_descriptor_array());
+ return length() <= kFirstIndex;
}
@@ -1585,10 +1693,10 @@ int DescriptorArray::Search(String* name) {
int DescriptorArray::SearchWithCache(String* name) {
- int number = DescriptorLookupCache::Lookup(this, name);
+ int number = GetIsolate()->descriptor_lookup_cache()->Lookup(this, name);
if (number == DescriptorLookupCache::kAbsent) {
number = Search(name);
- DescriptorLookupCache::Update(this, name, number);
+ GetIsolate()->descriptor_lookup_cache()->Update(this, name, number);
}
return number;
}
@@ -1648,7 +1756,8 @@ bool DescriptorArray::IsProperty(int descriptor_number) {
bool DescriptorArray::IsTransition(int descriptor_number) {
PropertyType t = GetType(descriptor_number);
- return t == MAP_TRANSITION || t == CONSTANT_TRANSITION;
+ return t == MAP_TRANSITION || t == CONSTANT_TRANSITION ||
+ t == EXTERNAL_ARRAY_TRANSITION;
}
@@ -1674,8 +1783,8 @@ void DescriptorArray::Set(int descriptor_number, Descriptor* desc) {
ASSERT(descriptor_number < number_of_descriptors());
// Make sure none of the elements in desc are in new space.
- ASSERT(!Heap::InNewSpace(desc->GetKey()));
- ASSERT(!Heap::InNewSpace(desc->GetValue()));
+ ASSERT(!HEAP->InNewSpace(desc->GetKey()));
+ ASSERT(!HEAP->InNewSpace(desc->GetValue()));
fast_set(this, ToKeyIndex(descriptor_number), desc->GetKey());
FixedArray* content_array = GetContentArray();
@@ -1700,6 +1809,30 @@ void DescriptorArray::Swap(int first, int second) {
}
+template<typename Shape, typename Key>
+int HashTable<Shape, Key>::FindEntry(Key key) {
+ return FindEntry(GetIsolate(), key);
+}
+
+
+// Find entry for key otherwise return kNotFound.
+template<typename Shape, typename Key>
+int HashTable<Shape, Key>::FindEntry(Isolate* isolate, Key key) {
+ uint32_t capacity = Capacity();
+ uint32_t entry = FirstProbe(Shape::Hash(key), capacity);
+ uint32_t count = 1;
+ // EnsureCapacity will guarantee the hash table is never full.
+ while (true) {
+ Object* element = KeyAt(entry);
+ if (element == isolate->heap()->undefined_value()) break; // Empty entry.
+ if (element != isolate->heap()->null_value() &&
+ Shape::IsMatch(key, element)) return entry;
+ entry = NextProbe(entry, count++, capacity);
+ }
+ return kNotFound;
+}
+
+
bool NumberDictionary::requires_slow_elements() {
Object* max_index_object = get(kMaxNumberKeyIndex);
if (!max_index_object->IsSmi()) return false;
@@ -1760,7 +1893,6 @@ CAST_ACCESSOR(JSArray)
CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(Proxy)
CAST_ACCESSOR(ByteArray)
-CAST_ACCESSOR(PixelArray)
CAST_ACCESSOR(ExternalArray)
CAST_ACCESSOR(ExternalByteArray)
CAST_ACCESSOR(ExternalUnsignedByteArray)
@@ -1769,6 +1901,7 @@ CAST_ACCESSOR(ExternalUnsignedShortArray)
CAST_ACCESSOR(ExternalIntArray)
CAST_ACCESSOR(ExternalUnsignedIntArray)
CAST_ACCESSOR(ExternalFloatArray)
+CAST_ACCESSOR(ExternalPixelArray)
CAST_ACCESSOR(Struct)
@@ -1787,7 +1920,6 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
SMI_ACCESSORS(FixedArray, length, kLengthOffset)
SMI_ACCESSORS(ByteArray, length, kLengthOffset)
-INT_ACCESSORS(PixelArray, length, kLengthOffset)
INT_ACCESSORS(ExternalArray, length, kLengthOffset)
@@ -1947,7 +2079,7 @@ Object* ConsString::unchecked_first() {
void ConsString::set_first(String* value, WriteBarrierMode mode) {
WRITE_FIELD(this, kFirstOffset, value);
- CONDITIONAL_WRITE_BARRIER(this, kFirstOffset, mode);
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kFirstOffset, mode);
}
@@ -1963,7 +2095,7 @@ Object* ConsString::unchecked_second() {
void ConsString::set_second(String* value, WriteBarrierMode mode) {
WRITE_FIELD(this, kSecondOffset, value);
- CONDITIONAL_WRITE_BARRIER(this, kSecondOffset, mode);
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kSecondOffset, mode);
}
@@ -1999,7 +2131,7 @@ void JSFunctionResultCache::Clear() {
int cache_size = size();
Object** entries_start = RawField(this, OffsetOfElementAt(kEntriesIndex));
MemsetPointer(entries_start,
- Heap::the_hole_value(),
+ GetHeap()->the_hole_value(),
cache_size - kEntriesIndex);
MakeZeroSize();
}
@@ -2054,28 +2186,21 @@ Address ByteArray::GetDataStartAddress() {
}
-uint8_t* PixelArray::external_pointer() {
- intptr_t ptr = READ_INTPTR_FIELD(this, kExternalPointerOffset);
- return reinterpret_cast<uint8_t*>(ptr);
-}
-
-
-void PixelArray::set_external_pointer(uint8_t* value, WriteBarrierMode mode) {
- intptr_t ptr = reinterpret_cast<intptr_t>(value);
- WRITE_INTPTR_FIELD(this, kExternalPointerOffset, ptr);
+uint8_t* ExternalPixelArray::external_pixel_pointer() {
+ return reinterpret_cast<uint8_t*>(external_pointer());
}
-uint8_t PixelArray::get(int index) {
+uint8_t ExternalPixelArray::get(int index) {
ASSERT((index >= 0) && (index < this->length()));
- uint8_t* ptr = external_pointer();
+ uint8_t* ptr = external_pixel_pointer();
return ptr[index];
}
-void PixelArray::set(int index, uint8_t value) {
+void ExternalPixelArray::set(int index, uint8_t value) {
ASSERT((index >= 0) && (index < this->length()));
- uint8_t* ptr = external_pointer();
+ uint8_t* ptr = external_pixel_pointer();
ptr[index] = value;
}
@@ -2553,6 +2678,19 @@ void Code::set_check_type(CheckType value) {
}
+ExternalArrayType Code::external_array_type() {
+ ASSERT(is_external_array_load_stub() || is_external_array_store_stub());
+ byte type = READ_BYTE_FIELD(this, kExternalArrayTypeOffset);
+ return static_cast<ExternalArrayType>(type);
+}
+
+
+void Code::set_external_array_type(ExternalArrayType value) {
+ ASSERT(is_external_array_load_stub() || is_external_array_store_stub());
+ WRITE_BYTE_FIELD(this, kExternalArrayTypeOffset, value);
+}
+
+
byte Code::binary_op_type() {
ASSERT(is_binary_op_stub());
return READ_BYTE_FIELD(this, kBinaryOpTypeOffset);
@@ -2710,6 +2848,20 @@ Code* Code::GetCodeFromTargetAddress(Address address) {
}
+Isolate* Map::isolate() {
+ return heap()->isolate();
+}
+
+
+Heap* Map::heap() {
+ // NOTE: address() helper is not used to save one instruction.
+ Heap* heap = Page::FromAddress(reinterpret_cast<Address>(this))->heap_;
+ ASSERT(heap != NULL);
+ ASSERT(heap->isolate() == Isolate::Current());
+ return heap;
+}
+
+
Object* Code::GetObjectFromEntryAddress(Address location_of_address) {
return HeapObject::
FromAddress(Memory::Address_at(location_of_address) - Code::kHeaderSize);
@@ -2724,7 +2876,7 @@ Object* Map::prototype() {
void Map::set_prototype(Object* value, WriteBarrierMode mode) {
ASSERT(value->IsNull() || value->IsJSObject());
WRITE_FIELD(this, kPrototypeOffset, value);
- CONDITIONAL_WRITE_BARRIER(this, kPrototypeOffset, mode);
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kPrototypeOffset, mode);
}
@@ -2736,7 +2888,7 @@ MaybeObject* Map::GetFastElementsMap() {
}
Map* new_map = Map::cast(obj);
new_map->set_has_fast_elements(true);
- Counters::map_slow_to_fast_elements.Increment();
+ isolate()->counters()->map_slow_to_fast_elements()->Increment();
return new_map;
}
@@ -2749,23 +2901,7 @@ MaybeObject* Map::GetSlowElementsMap() {
}
Map* new_map = Map::cast(obj);
new_map->set_has_fast_elements(false);
- Counters::map_fast_to_slow_elements.Increment();
- return new_map;
-}
-
-
-MaybeObject* Map::GetPixelArrayElementsMap() {
- if (has_pixel_array_elements()) return this;
- // TODO(danno): Special case empty object map (or most common case)
- // to return a pre-canned pixel array map.
- Object* obj;
- { MaybeObject* maybe_obj = CopyDropTransitions();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- Map* new_map = Map::cast(obj);
- new_map->set_has_fast_elements(false);
- new_map->set_has_pixel_array_elements(true);
- Counters::map_to_pixel_array_elements.Increment();
+ isolate()->counters()->map_fast_to_slow_elements()->Increment();
return new_map;
}
@@ -2777,7 +2913,8 @@ ACCESSORS(Map, constructor, Object, kConstructorOffset)
ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
ACCESSORS(JSFunction, literals, FixedArray, kLiteralsOffset)
-ACCESSORS(JSFunction, next_function_link, Object, kNextFunctionLinkOffset)
+ACCESSORS_GCSAFE(JSFunction, next_function_link, Object,
+ kNextFunctionLinkOffset)
ACCESSORS(GlobalObject, builtins, JSBuiltinsObject, kBuiltinsOffset)
ACCESSORS(GlobalObject, global_context, Context, kGlobalContextOffset)
@@ -2866,8 +3003,8 @@ ACCESSORS(BreakPointInfo, break_point_objects, Object, kBreakPointObjectsIndex)
#endif
ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset)
-ACCESSORS(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset)
-ACCESSORS(SharedFunctionInfo, initial_map, Object, kInitialMapOffset)
+ACCESSORS_GCSAFE(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset)
+ACCESSORS_GCSAFE(SharedFunctionInfo, initial_map, Object, kInitialMapOffset)
ACCESSORS(SharedFunctionInfo, instance_class_name, Object,
kInstanceClassNameOffset)
ACCESSORS(SharedFunctionInfo, function_data, Object, kFunctionDataOffset)
@@ -2995,7 +3132,7 @@ void SharedFunctionInfo::set_live_objects_may_exist(bool value) {
bool SharedFunctionInfo::IsInobjectSlackTrackingInProgress() {
- return initial_map() != Heap::undefined_value();
+ return initial_map() != HEAP->undefined_value();
}
@@ -3074,7 +3211,7 @@ Code* SharedFunctionInfo::unchecked_code() {
void SharedFunctionInfo::set_code(Code* value, WriteBarrierMode mode) {
WRITE_FIELD(this, kCodeOffset, value);
- CONDITIONAL_WRITE_BARRIER(this, kCodeOffset, mode);
+ ASSERT(!Isolate::Current()->heap()->InNewSpace(value));
}
@@ -3087,7 +3224,7 @@ SerializedScopeInfo* SharedFunctionInfo::scope_info() {
void SharedFunctionInfo::set_scope_info(SerializedScopeInfo* value,
WriteBarrierMode mode) {
WRITE_FIELD(this, kScopeInfoOffset, reinterpret_cast<Object*>(value));
- CONDITIONAL_WRITE_BARRIER(this, kScopeInfoOffset, mode);
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kScopeInfoOffset, mode);
}
@@ -3102,7 +3239,8 @@ void SharedFunctionInfo::set_deopt_counter(Smi* value) {
bool SharedFunctionInfo::is_compiled() {
- return code() != Builtins::builtin(Builtins::LazyCompile);
+ return code() !=
+ Isolate::Current()->builtins()->builtin(Builtins::kLazyCompile);
}
@@ -3162,7 +3300,7 @@ bool JSFunction::IsOptimized() {
bool JSFunction::IsMarkedForLazyRecompilation() {
- return code() == Builtins::builtin(Builtins::LazyRecompile);
+ return code() == GetIsolate()->builtins()->builtin(Builtins::kLazyRecompile);
}
@@ -3179,7 +3317,7 @@ Code* JSFunction::unchecked_code() {
void JSFunction::set_code(Code* value) {
// Skip the write barrier because code is never in new space.
- ASSERT(!Heap::InNewSpace(value));
+ ASSERT(!HEAP->InNewSpace(value));
Address entry = value->entry();
WRITE_INTPTR_FIELD(this, kCodeEntryOffset, reinterpret_cast<intptr_t>(entry));
}
@@ -3219,7 +3357,7 @@ SharedFunctionInfo* JSFunction::unchecked_shared() {
void JSFunction::set_context(Object* value) {
- ASSERT(value == Heap::undefined_value() || value->IsContext());
+ ASSERT(value->IsUndefined() || value->IsContext());
WRITE_FIELD(this, kContextOffset, value);
WRITE_BARRIER(this, kContextOffset);
}
@@ -3276,7 +3414,7 @@ bool JSFunction::should_have_prototype() {
bool JSFunction::is_compiled() {
- return code() != Builtins::builtin(Builtins::LazyCompile);
+ return code() != GetIsolate()->builtins()->builtin(Builtins::kLazyCompile);
}
@@ -3309,7 +3447,7 @@ void JSBuiltinsObject::set_javascript_builtin_code(Builtins::JavaScript id,
Code* value) {
ASSERT(id < kJSBuiltinsCount); // id is unsigned.
WRITE_FIELD(this, OffsetOfCodeWithId(id), value);
- ASSERT(!Heap::InNewSpace(value));
+ ASSERT(!HEAP->InNewSpace(value));
}
@@ -3459,8 +3597,8 @@ void JSRegExp::SetDataAt(int index, Object* value) {
JSObject::ElementsKind JSObject::GetElementsKind() {
if (map()->has_fast_elements()) {
- ASSERT(elements()->map() == Heap::fixed_array_map() ||
- elements()->map() == Heap::fixed_cow_array_map());
+ ASSERT(elements()->map() == GetHeap()->fixed_array_map() ||
+ elements()->map() == GetHeap()->fixed_cow_array_map());
return FAST_ELEMENTS;
}
HeapObject* array = elements();
@@ -3470,6 +3608,7 @@ JSObject::ElementsKind JSObject::GetElementsKind() {
ASSERT(array->IsDictionary());
return DICTIONARY_ELEMENTS;
}
+ ASSERT(!map()->has_fast_elements());
if (array->IsExternalArray()) {
switch (array->map()->instance_type()) {
case EXTERNAL_BYTE_ARRAY_TYPE:
@@ -3484,13 +3623,14 @@ JSObject::ElementsKind JSObject::GetElementsKind() {
return EXTERNAL_INT_ELEMENTS;
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
return EXTERNAL_UNSIGNED_INT_ELEMENTS;
+ case EXTERNAL_PIXEL_ARRAY_TYPE:
+ return EXTERNAL_PIXEL_ELEMENTS;
default:
- ASSERT(array->map()->instance_type() == EXTERNAL_FLOAT_ARRAY_TYPE);
- return EXTERNAL_FLOAT_ELEMENTS;
+ break;
}
}
- ASSERT(array->IsPixelArray());
- return PIXEL_ELEMENTS;
+ ASSERT(array->map()->instance_type() == EXTERNAL_FLOAT_ARRAY_TYPE);
+ return EXTERNAL_FLOAT_ELEMENTS;
}
@@ -3504,55 +3644,34 @@ bool JSObject::HasDictionaryElements() {
}
-bool JSObject::HasPixelElements() {
- return GetElementsKind() == PIXEL_ELEMENTS;
-}
-
-
bool JSObject::HasExternalArrayElements() {
- return (HasExternalByteElements() ||
- HasExternalUnsignedByteElements() ||
- HasExternalShortElements() ||
- HasExternalUnsignedShortElements() ||
- HasExternalIntElements() ||
- HasExternalUnsignedIntElements() ||
- HasExternalFloatElements());
-}
-
-
-bool JSObject::HasExternalByteElements() {
- return GetElementsKind() == EXTERNAL_BYTE_ELEMENTS;
-}
-
-
-bool JSObject::HasExternalUnsignedByteElements() {
- return GetElementsKind() == EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
-}
-
-
-bool JSObject::HasExternalShortElements() {
- return GetElementsKind() == EXTERNAL_SHORT_ELEMENTS;
-}
-
-
-bool JSObject::HasExternalUnsignedShortElements() {
- return GetElementsKind() == EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
-}
-
-
-bool JSObject::HasExternalIntElements() {
- return GetElementsKind() == EXTERNAL_INT_ELEMENTS;
+ HeapObject* array = elements();
+ ASSERT(array != NULL);
+ return array->IsExternalArray();
}
-bool JSObject::HasExternalUnsignedIntElements() {
- return GetElementsKind() == EXTERNAL_UNSIGNED_INT_ELEMENTS;
+#define EXTERNAL_ELEMENTS_CHECK(name, type) \
+bool JSObject::HasExternal##name##Elements() { \
+ HeapObject* array = elements(); \
+ ASSERT(array != NULL); \
+ if (!array->IsHeapObject()) \
+ return false; \
+ return array->map()->instance_type() == type; \
}
-bool JSObject::HasExternalFloatElements() {
- return GetElementsKind() == EXTERNAL_FLOAT_ELEMENTS;
-}
+EXTERNAL_ELEMENTS_CHECK(Byte, EXTERNAL_BYTE_ARRAY_TYPE)
+EXTERNAL_ELEMENTS_CHECK(UnsignedByte, EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE)
+EXTERNAL_ELEMENTS_CHECK(Short, EXTERNAL_SHORT_ARRAY_TYPE)
+EXTERNAL_ELEMENTS_CHECK(UnsignedShort,
+ EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE)
+EXTERNAL_ELEMENTS_CHECK(Int, EXTERNAL_INT_ARRAY_TYPE)
+EXTERNAL_ELEMENTS_CHECK(UnsignedInt,
+ EXTERNAL_UNSIGNED_INT_ARRAY_TYPE)
+EXTERNAL_ELEMENTS_CHECK(Float,
+ EXTERNAL_FLOAT_ARRAY_TYPE)
+EXTERNAL_ELEMENTS_CHECK(Pixel, EXTERNAL_PIXEL_ARRAY_TYPE)
bool JSObject::HasNamedInterceptor() {
@@ -3567,7 +3686,7 @@ bool JSObject::HasIndexedInterceptor() {
bool JSObject::AllowsSetElementsLength() {
bool result = elements()->IsFixedArray();
- ASSERT(result == (!HasPixelElements() && !HasExternalArrayElements()));
+ ASSERT(result == !HasExternalArrayElements());
return result;
}
@@ -3575,16 +3694,17 @@ bool JSObject::AllowsSetElementsLength() {
MaybeObject* JSObject::EnsureWritableFastElements() {
ASSERT(HasFastElements());
FixedArray* elems = FixedArray::cast(elements());
- if (elems->map() != Heap::fixed_cow_array_map()) return elems;
+ Isolate* isolate = GetIsolate();
+ if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
Object* writable_elems;
- { MaybeObject* maybe_writable_elems =
- Heap::CopyFixedArrayWithMap(elems, Heap::fixed_array_map());
+ { MaybeObject* maybe_writable_elems = isolate->heap()->CopyFixedArrayWithMap(
+ elems, isolate->heap()->fixed_array_map());
if (!maybe_writable_elems->ToObject(&writable_elems)) {
return maybe_writable_elems;
}
}
set_elements(FixedArray::cast(writable_elems));
- Counters::cow_arrays_converted.Increment();
+ isolate->counters()->cow_arrays_converted()->Increment();
return writable_elems;
}
@@ -3685,6 +3805,22 @@ uint32_t StringHasher::GetHash() {
}
+template <typename schar>
+uint32_t HashSequentialString(const schar* chars, int length) {
+ StringHasher hasher(length);
+ if (!hasher.has_trivial_hash()) {
+ int i;
+ for (i = 0; hasher.is_array_index() && (i < length); i++) {
+ hasher.AddCharacter(chars[i]);
+ }
+ for (; i < length; i++) {
+ hasher.AddCharacterNoIndex(chars[i]);
+ }
+ }
+ return hasher.GetHashField();
+}
+
+
bool String::AsArrayIndex(uint32_t* index) {
uint32_t field = hash_field();
if (IsHashFieldComputed(field) && (field & kIsNotArrayIndexMask)) {
@@ -3708,7 +3844,7 @@ PropertyAttributes JSObject::GetPropertyAttribute(String* key) {
Object* JSObject::BypassGlobalProxy() {
if (IsJSGlobalProxy()) {
Object* proto = GetPrototype();
- if (proto->IsNull()) return Heap::undefined_value();
+ if (proto->IsNull()) return GetHeap()->undefined_value();
ASSERT(proto->IsJSGlobalObject());
return proto;
}
@@ -3719,7 +3855,7 @@ Object* JSObject::BypassGlobalProxy() {
bool JSObject::HasHiddenPropertiesObject() {
ASSERT(!IsJSGlobalProxy());
return GetPropertyAttributePostInterceptor(this,
- Heap::hidden_symbol(),
+ GetHeap()->hidden_symbol(),
false) != ABSENT;
}
@@ -3732,7 +3868,7 @@ Object* JSObject::GetHiddenPropertiesObject() {
// object.
Object* result =
GetLocalPropertyPostInterceptor(this,
- Heap::hidden_symbol(),
+ GetHeap()->hidden_symbol(),
&attributes)->ToObjectUnchecked();
return result;
}
@@ -3740,7 +3876,7 @@ Object* JSObject::GetHiddenPropertiesObject() {
MaybeObject* JSObject::SetHiddenPropertiesObject(Object* hidden_obj) {
ASSERT(!IsJSGlobalProxy());
- return SetPropertyPostInterceptor(Heap::hidden_symbol(),
+ return SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
hidden_obj,
DONT_ENUM,
kNonStrictMode);
@@ -3808,12 +3944,57 @@ void Dictionary<Shape, Key>::SetEntry(int entry,
}
-void Map::ClearCodeCache() {
+bool NumberDictionaryShape::IsMatch(uint32_t key, Object* other) {
+ ASSERT(other->IsNumber());
+ return key == static_cast<uint32_t>(other->Number());
+}
+
+
+uint32_t NumberDictionaryShape::Hash(uint32_t key) {
+ return ComputeIntegerHash(key);
+}
+
+
+uint32_t NumberDictionaryShape::HashForObject(uint32_t key, Object* other) {
+ ASSERT(other->IsNumber());
+ return ComputeIntegerHash(static_cast<uint32_t>(other->Number()));
+}
+
+
+MaybeObject* NumberDictionaryShape::AsObject(uint32_t key) {
+ return Isolate::Current()->heap()->NumberFromUint32(key);
+}
+
+
+bool StringDictionaryShape::IsMatch(String* key, Object* other) {
+ // We know that all entries in a hash table had their hash keys created.
+ // Use that knowledge to have fast failure.
+ if (key->Hash() != String::cast(other)->Hash()) return false;
+ return key->Equals(String::cast(other));
+}
+
+
+uint32_t StringDictionaryShape::Hash(String* key) {
+ return key->Hash();
+}
+
+
+uint32_t StringDictionaryShape::HashForObject(String* key, Object* other) {
+ return String::cast(other)->Hash();
+}
+
+
+MaybeObject* StringDictionaryShape::AsObject(String* key) {
+ return key;
+}
+
+
+void Map::ClearCodeCache(Heap* heap) {
// No write barrier is needed since empty_fixed_array is not in new space.
// Please note this function is used during marking:
// - MarkCompactCollector::MarkUnmarkedObject
- ASSERT(!Heap::InNewSpace(Heap::raw_unchecked_empty_fixed_array()));
- WRITE_FIELD(this, kCodeCacheOffset, Heap::raw_unchecked_empty_fixed_array());
+ ASSERT(!heap->InNewSpace(heap->raw_unchecked_empty_fixed_array()));
+ WRITE_FIELD(this, kCodeCacheOffset, heap->raw_unchecked_empty_fixed_array());
}
@@ -3826,7 +4007,7 @@ void JSArray::EnsureSize(int required_size) {
// constantly growing.
Expand(required_size + (required_size >> 3));
// It's a performance benefit to keep a frequently used array in new-space.
- } else if (!Heap::new_space()->Contains(elts) &&
+ } else if (!GetHeap()->new_space()->Contains(elts) &&
required_size < kArraySizeThatFitsComfortablyInNewSpace) {
// Expand will allocate a new backing store in new space even if the size
// we asked for isn't larger than what we had before.
@@ -3848,7 +4029,22 @@ void JSArray::SetContent(FixedArray* storage) {
MaybeObject* FixedArray::Copy() {
if (length() == 0) return this;
- return Heap::CopyFixedArray(this);
+ return GetHeap()->CopyFixedArray(this);
+}
+
+
+Relocatable::Relocatable(Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ isolate_ = isolate;
+ prev_ = isolate->relocatable_top();
+ isolate->set_relocatable_top(this);
+}
+
+
+Relocatable::~Relocatable() {
+ ASSERT(isolate_ == Isolate::Current());
+ ASSERT_EQ(isolate_->relocatable_top(), this);
+ isolate_->set_relocatable_top(prev_);
}
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 237358dc..b7e2fdd8 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -88,8 +88,8 @@ void HeapObject::HeapObjectPrint(FILE* out) {
case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayPrint(out);
break;
- case PIXEL_ARRAY_TYPE:
- PixelArray::cast(this)->PixelArrayPrint(out);
+ case EXTERNAL_PIXEL_ARRAY_TYPE:
+ ExternalPixelArray::cast(this)->ExternalPixelArrayPrint(out);
break;
case EXTERNAL_BYTE_ARRAY_TYPE:
ExternalByteArray::cast(this)->ExternalByteArrayPrint(out);
@@ -177,8 +177,8 @@ void ByteArray::ByteArrayPrint(FILE* out) {
}
-void PixelArray::PixelArrayPrint(FILE* out) {
- PrintF(out, "pixel array");
+void ExternalPixelArray::ExternalPixelArrayPrint(FILE* out) {
+ PrintF(out, "external pixel array");
}
@@ -271,8 +271,8 @@ void JSObject::PrintElements(FILE* out) {
}
break;
}
- case PIXEL_ELEMENTS: {
- PixelArray* p = PixelArray::cast(elements());
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ ExternalPixelArray* p = ExternalPixelArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
PrintF(out, " %d: %d\n", i, p->get(i));
}
@@ -372,7 +372,7 @@ static const char* TypeToString(InstanceType type) {
case EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
- case PIXEL_ARRAY_TYPE: return "PIXEL_ARRAY";
+ case EXTERNAL_PIXEL_ARRAY_TYPE: return "EXTERNAL_PIXEL_ARRAY";
case EXTERNAL_BYTE_ARRAY_TYPE: return "EXTERNAL_BYTE_ARRAY";
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
return "EXTERNAL_UNSIGNED_BYTE_ARRAY";
diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc
index 5f054bd3..5a23658c 100644
--- a/src/objects-visiting.cc
+++ b/src/objects-visiting.cc
@@ -113,7 +113,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
return kVisitJSFunction;
case HEAP_NUMBER_TYPE:
- case PIXEL_ARRAY_TYPE:
+ case EXTERNAL_PIXEL_ARRAY_TYPE:
case EXTERNAL_BYTE_ARRAY_TYPE:
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
case EXTERNAL_SHORT_ARRAY_TYPE:
diff --git a/src/objects-visiting.h b/src/objects-visiting.h
index ea6d7954..42f90608 100644
--- a/src/objects-visiting.h
+++ b/src/objects-visiting.h
@@ -186,14 +186,15 @@ class VisitorDispatchTable {
template<typename StaticVisitor>
class BodyVisitorBase : public AllStatic {
public:
- INLINE(static void IteratePointers(HeapObject* object,
+ INLINE(static void IteratePointers(Heap* heap,
+ HeapObject* object,
int start_offset,
int end_offset)) {
Object** start_slot = reinterpret_cast<Object**>(object->address() +
start_offset);
Object** end_slot = reinterpret_cast<Object**>(object->address() +
end_offset);
- StaticVisitor::VisitPointers(start_slot, end_slot);
+ StaticVisitor::VisitPointers(heap, start_slot, end_slot);
}
};
@@ -204,7 +205,10 @@ class FlexibleBodyVisitor : public BodyVisitorBase<StaticVisitor> {
static inline ReturnType Visit(Map* map, HeapObject* object) {
int object_size = BodyDescriptor::SizeOf(map, object);
BodyVisitorBase<StaticVisitor>::IteratePointers(
- object, BodyDescriptor::kStartOffset, object_size);
+ map->heap(),
+ object,
+ BodyDescriptor::kStartOffset,
+ object_size);
return static_cast<ReturnType>(object_size);
}
@@ -212,7 +216,10 @@ class FlexibleBodyVisitor : public BodyVisitorBase<StaticVisitor> {
static inline ReturnType VisitSpecialized(Map* map, HeapObject* object) {
ASSERT(BodyDescriptor::SizeOf(map, object) == object_size);
BodyVisitorBase<StaticVisitor>::IteratePointers(
- object, BodyDescriptor::kStartOffset, object_size);
+ map->heap(),
+ object,
+ BodyDescriptor::kStartOffset,
+ object_size);
return static_cast<ReturnType>(object_size);
}
};
@@ -223,7 +230,10 @@ class FixedBodyVisitor : public BodyVisitorBase<StaticVisitor> {
public:
static inline ReturnType Visit(Map* map, HeapObject* object) {
BodyVisitorBase<StaticVisitor>::IteratePointers(
- object, BodyDescriptor::kStartOffset, BodyDescriptor::kEndOffset);
+ map->heap(),
+ object,
+ BodyDescriptor::kStartOffset,
+ BodyDescriptor::kEndOffset);
return static_cast<ReturnType>(BodyDescriptor::kSize);
}
};
@@ -299,8 +309,8 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
return table_.GetVisitor(map)(map, obj);
}
- static inline void VisitPointers(Object** start, Object** end) {
- for (Object** p = start; p < end; p++) StaticVisitor::VisitPointer(p);
+ static inline void VisitPointers(Heap* heap, Object** start, Object** end) {
+ for (Object** p = start; p < end; p++) StaticVisitor::VisitPointer(heap, p);
}
private:
@@ -372,7 +382,7 @@ void Code::CodeIterateBody(ObjectVisitor* v) {
template<typename StaticVisitor>
-void Code::CodeIterateBody() {
+void Code::CodeIterateBody(Heap* heap) {
int mode_mask = RelocInfo::kCodeTargetMask |
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
@@ -386,12 +396,14 @@ void Code::CodeIterateBody() {
RelocIterator it(this, mode_mask);
StaticVisitor::VisitPointer(
+ heap,
reinterpret_cast<Object**>(this->address() + kRelocationInfoOffset));
StaticVisitor::VisitPointer(
+ heap,
reinterpret_cast<Object**>(this->address() + kDeoptimizationDataOffset));
for (; !it.done(); it.next()) {
- it.rinfo()->template Visit<StaticVisitor>();
+ it.rinfo()->template Visit<StaticVisitor>(heap);
}
}
diff --git a/src/objects.cc b/src/objects.cc
index 4c005918..8cb36e91 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -51,7 +51,6 @@
#include "disassembler.h"
#endif
-
namespace v8 {
namespace internal {
@@ -64,7 +63,8 @@ const int kSetterIndex = 1;
MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
Object* value) {
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateJSObject(constructor);
+ { MaybeObject* maybe_result =
+ constructor->GetHeap()->AllocateJSObject(constructor);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
JSValue::cast(result)->set_value(value);
@@ -86,14 +86,19 @@ MaybeObject* Object::ToObject(Context* global_context) {
MaybeObject* Object::ToObject() {
- Context* global_context = Top::context()->global_context();
if (IsJSObject()) {
return this;
} else if (IsNumber()) {
+ Isolate* isolate = Isolate::Current();
+ Context* global_context = isolate->context()->global_context();
return CreateJSValue(global_context->number_function(), this);
} else if (IsBoolean()) {
+ Isolate* isolate = HeapObject::cast(this)->GetIsolate();
+ Context* global_context = isolate->context()->global_context();
return CreateJSValue(global_context->boolean_function(), this);
} else if (IsString()) {
+ Isolate* isolate = HeapObject::cast(this)->GetIsolate();
+ Context* global_context = isolate->context()->global_context();
return CreateJSValue(global_context->string_function(), this);
}
@@ -103,35 +108,43 @@ MaybeObject* Object::ToObject() {
Object* Object::ToBoolean() {
- if (IsTrue()) return Heap::true_value();
- if (IsFalse()) return Heap::false_value();
+ if (IsTrue()) return this;
+ if (IsFalse()) return this;
if (IsSmi()) {
- return Heap::ToBoolean(Smi::cast(this)->value() != 0);
+ return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
+ }
+ if (IsUndefined() || IsNull()) {
+ return HeapObject::cast(this)->GetHeap()->false_value();
}
- if (IsUndefined() || IsNull()) return Heap::false_value();
// Undetectable object is false
if (IsUndetectableObject()) {
- return Heap::false_value();
+ return HeapObject::cast(this)->GetHeap()->false_value();
}
if (IsString()) {
- return Heap::ToBoolean(String::cast(this)->length() != 0);
+ return HeapObject::cast(this)->GetHeap()->ToBoolean(
+ String::cast(this)->length() != 0);
}
if (IsHeapNumber()) {
return HeapNumber::cast(this)->HeapNumberToBoolean();
}
- return Heap::true_value();
+ return Isolate::Current()->heap()->true_value();
}
void Object::Lookup(String* name, LookupResult* result) {
if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result);
Object* holder = NULL;
- Context* global_context = Top::context()->global_context();
if (IsString()) {
+ Heap* heap = HeapObject::cast(this)->GetHeap();
+ Context* global_context = heap->isolate()->context()->global_context();
holder = global_context->string_function()->instance_prototype();
} else if (IsNumber()) {
+ Heap* heap = Isolate::Current()->heap();
+ Context* global_context = heap->isolate()->context()->global_context();
holder = global_context->number_function()->instance_prototype();
} else if (IsBoolean()) {
+ Heap* heap = HeapObject::cast(this)->GetHeap();
+ Context* global_context = heap->isolate()->context()->global_context();
holder = global_context->boolean_function()->instance_prototype();
}
ASSERT(holder != NULL); // Cannot handle null or undefined.
@@ -154,6 +167,7 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
Object* structure,
String* name,
Object* holder) {
+ Isolate* isolate = name->GetIsolate();
// To accommodate both the old and the new api we switch on the
// data structure used to store the callbacks. Eventually proxy
// callbacks should be phased out.
@@ -161,7 +175,7 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
AccessorDescriptor* callback =
reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
MaybeObject* value = (callback->getter)(receiver, callback->data);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return value;
}
@@ -174,17 +188,19 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
JSObject* self = JSObject::cast(receiver);
JSObject* holder_handle = JSObject::cast(holder);
Handle<String> key(name);
- LOG(ApiNamedPropertyAccess("load", self, name));
- CustomArguments args(data->data(), self, holder_handle);
+ LOG(isolate, ApiNamedPropertyAccess("load", self, name));
+ CustomArguments args(isolate, data->data(), self, holder_handle);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = call_fun(v8::Utils::ToLocal(key), info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
- if (result.IsEmpty()) return Heap::undefined_value();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
+ if (result.IsEmpty()) {
+ return isolate->heap()->undefined_value();
+ }
return *v8::Utils::OpenHandle(*result);
}
@@ -196,7 +212,7 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
JSFunction::cast(getter));
}
// Getter is not a function.
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
UNREACHABLE();
@@ -210,9 +226,10 @@ MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
Handle<JSFunction> fun(JSFunction::cast(getter));
Handle<Object> self(receiver);
#ifdef ENABLE_DEBUGGER_SUPPORT
+ Debug* debug = fun->GetHeap()->isolate()->debug();
// Handle stepping into a getter if step into is active.
- if (Debug::StepInActive()) {
- Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
+ if (debug->StepInActive()) {
+ debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
}
#endif
bool has_pending_exception;
@@ -230,6 +247,7 @@ MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
LookupResult* result,
String* name,
PropertyAttributes* attributes) {
+ Heap* heap = name->GetHeap();
if (result->IsProperty()) {
switch (result->type()) {
case CALLBACKS: {
@@ -281,8 +299,8 @@ MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
// No accessible property found.
*attributes = ABSENT;
- Top::ReportFailedAccessCheck(this, v8::ACCESS_GET);
- return Heap::undefined_value();
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
+ return heap->undefined_value();
}
@@ -291,6 +309,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
LookupResult* result,
String* name,
bool continue_search) {
+ Heap* heap = name->GetHeap();
if (result->IsProperty()) {
switch (result->type()) {
case CALLBACKS: {
@@ -344,7 +363,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
}
}
- Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return ABSENT;
}
@@ -378,16 +397,14 @@ MaybeObject* JSObject::SetNormalizedProperty(String* name,
Object* value,
PropertyDetails details) {
ASSERT(!HasFastProperties());
+ Heap* heap = name->GetHeap();
int entry = property_dictionary()->FindEntry(name);
if (entry == StringDictionary::kNotFound) {
Object* store_value = value;
if (IsGlobalObject()) {
- { MaybeObject* maybe_store_value =
- Heap::AllocateJSGlobalPropertyCell(value);
- if (!maybe_store_value->ToObject(&store_value)) {
- return maybe_store_value;
- }
- }
+ MaybeObject* maybe_store_value =
+ heap->AllocateJSGlobalPropertyCell(value);
+ if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
}
Object* dict;
{ MaybeObject* maybe_dict =
@@ -416,6 +433,7 @@ MaybeObject* JSObject::SetNormalizedProperty(String* name,
MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
ASSERT(!HasFastProperties());
+ Heap* heap = GetHeap();
StringDictionary* dictionary = property_dictionary();
int entry = dictionary->FindEntry(name);
if (entry != StringDictionary::kNotFound) {
@@ -423,7 +441,7 @@ MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
if (IsGlobalObject()) {
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.IsDontDelete()) {
- if (mode != FORCE_DELETION) return Heap::false_value();
+ if (mode != FORCE_DELETION) return heap->false_value();
// When forced to delete global properties, we have to make a
// map change to invalidate any ICs that think they can load
// from the DontDelete cell without checking if it contains
@@ -436,13 +454,13 @@ MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
}
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
- cell->set_value(Heap::the_hole_value());
+ cell->set_value(heap->the_hole_value());
dictionary->DetailsAtPut(entry, details.AsDeleted());
} else {
return dictionary->DeleteProperty(entry, mode);
}
}
- return Heap::true_value();
+ return heap->true_value();
}
@@ -468,6 +486,7 @@ MaybeObject* Object::GetProperty(Object* receiver,
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
+ Heap* heap = name->GetHeap();
// Traverse the prototype chain from the current object (this) to
// the holder and check for access rights. This avoid traversing the
@@ -475,7 +494,7 @@ MaybeObject* Object::GetProperty(Object* receiver,
// holder will always be the interceptor holder and the search may
// only continue with a current object just after the interceptor
// holder in the prototype chain.
- Object* last = result->IsProperty() ? result->holder() : Heap::null_value();
+ Object* last = result->IsProperty() ? result->holder() : heap->null_value();
for (Object* current = this; true; current = current->GetPrototype()) {
if (current->IsAccessCheckNeeded()) {
// Check if we're allowed to read from the current object. Note
@@ -483,7 +502,7 @@ MaybeObject* Object::GetProperty(Object* receiver,
// property from the current object, we still check that we have
// access to it.
JSObject* checked = JSObject::cast(current);
- if (!Top::MayNamedAccess(checked, name, v8::ACCESS_GET)) {
+ if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
return checked->GetPropertyWithFailedAccessCheck(receiver,
result,
name,
@@ -498,7 +517,7 @@ MaybeObject* Object::GetProperty(Object* receiver,
if (!result->IsProperty()) {
*attributes = ABSENT;
- return Heap::undefined_value();
+ return heap->undefined_value();
}
*attributes = result->GetAttributes();
Object* value;
@@ -507,11 +526,11 @@ MaybeObject* Object::GetProperty(Object* receiver,
case NORMAL:
value = holder->GetNormalizedProperty(result);
ASSERT(!value->IsTheHole() || result->IsReadOnly());
- return value->IsTheHole() ? Heap::undefined_value() : value;
+ return value->IsTheHole() ? heap->undefined_value() : value;
case FIELD:
value = holder->FastPropertyAt(result->GetFieldIndex());
ASSERT(!value->IsTheHole() || result->IsReadOnly());
- return value->IsTheHole() ? Heap::undefined_value() : value;
+ return value->IsTheHole() ? heap->undefined_value() : value;
case CONSTANT_FUNCTION:
return result->GetConstantFunction();
case CALLBACKS:
@@ -536,7 +555,7 @@ MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
}
Object* holder = NULL;
- Context* global_context = Top::context()->global_context();
+ Context* global_context = Isolate::Current()->context()->global_context();
if (IsString()) {
holder = global_context->string_function()->instance_prototype();
} else if (IsNumber()) {
@@ -546,7 +565,7 @@ MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
} else {
// Undefined and null have no indexed properties.
ASSERT(IsUndefined() || IsNull());
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
return JSObject::cast(holder)->GetElementWithReceiver(receiver, index);
@@ -556,14 +575,15 @@ MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Object* Object::GetPrototype() {
// The object is either a number, a string, a boolean, or a real JS object.
if (IsJSObject()) return JSObject::cast(this)->map()->prototype();
- Context* context = Top::context()->global_context();
+ Heap* heap = Isolate::Current()->heap();
+ Context* context = heap->isolate()->context()->global_context();
if (IsNumber()) return context->number_function()->instance_prototype();
if (IsString()) return context->string_function()->instance_prototype();
if (IsBoolean()) {
return context->boolean_function()->instance_prototype();
} else {
- return Heap::null_value();
+ return heap->null_value();
}
}
@@ -637,9 +657,10 @@ MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
// allowed. This is to avoid an assertion failure when allocating.
// Flattening strings is the only case where we always allow
// allocation because no GC is performed if the allocation fails.
- if (!Heap::IsAllocationAllowed()) return this;
+ if (!HEAP->IsAllocationAllowed()) return this;
#endif
+ Heap* heap = GetHeap();
switch (StringShape(this).representation_tag()) {
case kConsStringTag: {
ConsString* cs = ConsString::cast(this);
@@ -649,12 +670,12 @@ MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
// There's little point in putting the flat string in new space if the
// cons string is in old space. It can never get GCed until there is
// an old space GC.
- PretenureFlag tenure = Heap::InNewSpace(this) ? pretenure : TENURED;
+ PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
int len = length();
Object* object;
String* result;
if (IsAsciiRepresentation()) {
- { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(len, tenure);
+ { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
result = String::cast(object);
@@ -669,7 +690,7 @@ MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
len - first_length);
} else {
{ MaybeObject* maybe_object =
- Heap::AllocateRawTwoByteString(len, tenure);
+ heap->AllocateRawTwoByteString(len, tenure);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
result = String::cast(object);
@@ -684,7 +705,7 @@ MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
len - first_length);
}
cs->set_first(result);
- cs->set_second(Heap::empty_string());
+ cs->set_second(heap->empty_string());
return result;
}
default:
@@ -708,7 +729,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
resource->length() * sizeof(smart_chars[0])) == 0);
}
#endif // DEBUG
-
+ Heap* heap = GetHeap();
int size = this->Size(); // Byte size of the original string.
if (size < ExternalString::kSize) {
// The string is too small to fit an external String in its place. This can
@@ -724,8 +745,8 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
// Morph the object to an external string by adjusting the map and
// reinitializing the fields.
this->set_map(is_ascii ?
- Heap::external_string_with_ascii_data_map() :
- Heap::external_string_map());
+ heap->external_string_with_ascii_data_map() :
+ heap->external_string_map());
ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
self->set_length(length);
self->set_hash_field(hash_field);
@@ -736,13 +757,13 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
self->Hash(); // Force regeneration of the hash value.
// Now morph this external string into a external symbol.
this->set_map(is_ascii ?
- Heap::external_symbol_with_ascii_data_map() :
- Heap::external_symbol_map());
+ heap->external_symbol_with_ascii_data_map() :
+ heap->external_symbol_map());
}
// Fill the remainder of the string with dead wood.
int new_size = this->Size(); // Byte size of the external String object.
- Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size);
+ heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
return true;
}
@@ -759,7 +780,7 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
resource->length() * sizeof(smart_chars[0])) == 0);
}
#endif // DEBUG
-
+ Heap* heap = GetHeap();
int size = this->Size(); // Byte size of the original string.
if (size < ExternalString::kSize) {
// The string is too small to fit an external String in its place. This can
@@ -773,7 +794,7 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
// Morph the object to an external string by adjusting the map and
// reinitializing the fields.
- this->set_map(Heap::external_ascii_string_map());
+ this->set_map(heap->external_ascii_string_map());
ExternalAsciiString* self = ExternalAsciiString::cast(this);
self->set_length(length);
self->set_hash_field(hash_field);
@@ -783,12 +804,12 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
if (is_symbol) {
self->Hash(); // Force regeneration of the hash value.
// Now morph this external string into a external symbol.
- this->set_map(Heap::external_ascii_symbol_map());
+ this->set_map(heap->external_ascii_symbol_map());
}
// Fill the remainder of the string with dead wood.
int new_size = this->Size(); // Byte size of the external String object.
- Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size);
+ heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
return true;
}
@@ -887,15 +908,16 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
// All other JSObjects are rather similar to each other (JSObject,
// JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
default: {
+ Heap* heap = GetHeap();
Object* constructor = map()->constructor();
bool printed = false;
if (constructor->IsHeapObject() &&
- !Heap::Contains(HeapObject::cast(constructor))) {
+ !heap->Contains(HeapObject::cast(constructor))) {
accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
} else {
bool global_object = IsJSGlobalProxy();
if (constructor->IsJSFunction()) {
- if (!Heap::Contains(JSFunction::cast(constructor)->shared())) {
+ if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
} else {
Object* constructor_name =
@@ -930,12 +952,13 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
- // if (!Heap::InNewSpace(this)) PrintF("*", this);
- if (!Heap::Contains(this)) {
+ // if (!HEAP->InNewSpace(this)) PrintF("*", this);
+ Heap* heap = GetHeap();
+ if (!heap->Contains(this)) {
accumulator->Add("!!!INVALID POINTER!!!");
return;
}
- if (!Heap::Contains(map())) {
+ if (!heap->Contains(map())) {
accumulator->Add("!!!INVALID MAP!!!");
return;
}
@@ -960,8 +983,9 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
case BYTE_ARRAY_TYPE:
accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
break;
- case PIXEL_ARRAY_TYPE:
- accumulator->Add("<PixelArray[%u]>", PixelArray::cast(this)->length());
+ case EXTERNAL_PIXEL_ARRAY_TYPE:
+ accumulator->Add("<ExternalPixelArray[%u]>",
+ ExternalPixelArray::cast(this)->length());
break;
case EXTERNAL_BYTE_ARRAY_TYPE:
accumulator->Add("<ExternalByteArray[%u]>",
@@ -1112,7 +1136,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case HEAP_NUMBER_TYPE:
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
- case PIXEL_ARRAY_TYPE:
+ case EXTERNAL_PIXEL_ARRAY_TYPE:
case EXTERNAL_BYTE_ARRAY_TYPE:
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
case EXTERNAL_SHORT_ARRAY_TYPE:
@@ -1149,14 +1173,14 @@ Object* HeapNumber::HeapNumberToBoolean() {
if (u.bits.exp == 2047) {
// Detect NaN for IEEE double precision floating point.
if ((u.bits.man_low | u.bits.man_high) != 0)
- return Heap::false_value();
+ return GetHeap()->false_value();
}
if (u.bits.exp == 0) {
// Detect +0, and -0 for IEEE double precision floating point.
if ((u.bits.man_low | u.bits.man_high) == 0)
- return Heap::false_value();
+ return GetHeap()->false_value();
}
- return Heap::true_value();
+ return GetHeap()->true_value();
}
@@ -1180,14 +1204,14 @@ void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
String* JSObject::class_name() {
if (IsJSFunction()) {
- return Heap::function_class_symbol();
+ return GetHeap()->function_class_symbol();
}
if (map()->constructor()->IsJSFunction()) {
JSFunction* constructor = JSFunction::cast(map()->constructor());
return String::cast(constructor->shared()->instance_class_name());
}
// If the constructor is not present, return "Object".
- return Heap::Object_symbol();
+ return GetHeap()->Object_symbol();
}
@@ -1202,7 +1226,7 @@ String* JSObject::constructor_name() {
if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
}
// If the constructor is not present, return "Object".
- return Heap::Object_symbol();
+ return GetHeap()->Object_symbol();
}
@@ -1232,9 +1256,10 @@ MaybeObject* JSObject::AddFastProperty(String* name,
// Normalize the object if the name is an actual string (not the
// hidden symbols) and is not a real identifier.
+ Isolate* isolate = GetHeap()->isolate();
StringInputBuffer buffer(name);
- if (!ScannerConstants::IsIdentifier(&buffer)
- && name != Heap::hidden_symbol()) {
+ if (!isolate->scanner_constants()->IsIdentifier(&buffer)
+ && name != isolate->heap()->hidden_symbol()) {
Object* obj;
{ MaybeObject* maybe_obj =
NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
@@ -1257,11 +1282,21 @@ MaybeObject* JSObject::AddFastProperty(String* name,
}
}
- // Only allow map transition if the object's map is NOT equal to the
- // global object_function's map and there is not a transition for name.
+ // Only allow map transition if the object isn't the global object and there
+ // is not a transition for the name, or there's a transition for the name but
+ // it's unrelated to properties.
+ int descriptor_index = old_descriptors->Search(name);
+
+ // External array transitions are stored in the descriptor for property "",
+ // which is not a identifier and should have forced a switch to slow
+ // properties above.
+ ASSERT(descriptor_index == DescriptorArray::kNotFound ||
+ old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
+ bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
+ old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
bool allow_map_transition =
- !old_descriptors->Contains(name) &&
- (Top::context()->global_context()->object_function()->map() != map());
+ can_insert_transition &&
+ (isolate->context()->global_context()->object_function()->map() != map());
ASSERT(index < map()->inobject_properties() ||
(index - map()->inobject_properties()) < properties()->length() ||
@@ -1315,7 +1350,8 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
String* name,
JSFunction* function,
PropertyAttributes attributes) {
- ASSERT(!Heap::InNewSpace(function));
+ Heap* heap = GetHeap();
+ ASSERT(!heap->InNewSpace(function));
// Allocate new instance descriptors with (name, function) added
ConstantFunctionDescriptor d(name, function, attributes);
@@ -1340,7 +1376,8 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
// If the old map is the global object map (from new Object()),
// then transitions are not added to it, so we are done.
- if (old_map == Top::context()->global_context()->object_function()->map()) {
+ if (old_map == heap->isolate()->context()->global_context()->
+ object_function()->map()) {
return function;
}
@@ -1375,6 +1412,7 @@ MaybeObject* JSObject::AddSlowProperty(String* name,
Object* value,
PropertyAttributes attributes) {
ASSERT(!HasFastProperties());
+ Heap* heap = GetHeap();
StringDictionary* dict = property_dictionary();
Object* store_value = value;
if (IsGlobalObject()) {
@@ -1392,7 +1430,7 @@ MaybeObject* JSObject::AddSlowProperty(String* name,
return value;
}
{ MaybeObject* maybe_store_value =
- Heap::AllocateJSGlobalPropertyCell(value);
+ heap->AllocateJSGlobalPropertyCell(value);
if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
}
JSGlobalPropertyCell::cast(store_value)->set_value(value);
@@ -1409,18 +1447,25 @@ MaybeObject* JSObject::AddSlowProperty(String* name,
MaybeObject* JSObject::AddProperty(String* name,
Object* value,
- PropertyAttributes attributes) {
+ PropertyAttributes attributes,
+ StrictModeFlag strict_mode) {
ASSERT(!IsJSGlobalProxy());
+ Heap* heap = GetHeap();
if (!map()->is_extensible()) {
- Handle<Object> args[1] = {Handle<String>(name)};
- return Top::Throw(*Factory::NewTypeError("object_not_extensible",
- HandleVector(args, 1)));
+ if (strict_mode == kNonStrictMode) {
+ return heap->undefined_value();
+ } else {
+ Handle<Object> args[1] = {Handle<String>(name)};
+ return heap->isolate()->Throw(
+ *FACTORY->NewTypeError("object_not_extensible",
+ HandleVector(args, 1)));
+ }
}
if (HasFastProperties()) {
// Ensure the descriptor array does not get too big.
if (map()->instance_descriptors()->number_of_descriptors() <
DescriptorArray::kMaxNumberOfDescriptors) {
- if (value->IsJSFunction() && !Heap::InNewSpace(value)) {
+ if (value->IsJSFunction() && !heap->InNewSpace(value)) {
return AddConstantFunctionProperty(name,
JSFunction::cast(value),
attributes);
@@ -1455,7 +1500,7 @@ MaybeObject* JSObject::SetPropertyPostInterceptor(
return SetProperty(&result, name, value, attributes, strict_mode);
}
// Add a new real property.
- return AddProperty(name, value, attributes);
+ return AddProperty(name, value, attributes, strict_mode);
}
@@ -1492,7 +1537,8 @@ MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
return result;
}
// Do not add transitions to the map of "new Object()".
- if (map() == Top::context()->global_context()->object_function()->map()) {
+ if (map() == GetHeap()->isolate()->context()->global_context()->
+ object_function()->map()) {
return result;
}
@@ -1579,29 +1625,31 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
Object* value,
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
- HandleScope scope;
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
Handle<JSObject> this_handle(this);
Handle<String> name_handle(name);
- Handle<Object> value_handle(value);
+ Handle<Object> value_handle(value, isolate);
Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
if (!interceptor->setter()->IsUndefined()) {
- LOG(ApiNamedPropertyAccess("interceptor-named-set", this, name));
- CustomArguments args(interceptor->data(), this, this);
+ LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
+ CustomArguments args(isolate, interceptor->data(), this, this);
v8::AccessorInfo info(args.end());
v8::NamedPropertySetter setter =
v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
Handle<Object> value_unhole(value->IsTheHole() ?
- Heap::undefined_value() :
- value);
+ isolate->heap()->undefined_value() :
+ value,
+ isolate);
result = setter(v8::Utils::ToLocal(name_handle),
v8::Utils::ToLocal(value_unhole),
info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) return *value_handle;
}
MaybeObject* raw_result =
@@ -1609,7 +1657,7 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
*value_handle,
attributes,
strict_mode);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return raw_result;
}
@@ -1628,12 +1676,13 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
String* name,
Object* value,
JSObject* holder) {
- HandleScope scope;
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
// We should never get here to initialize a const with the hole
// value since a const declaration would conflict with the setter.
ASSERT(!value->IsTheHole());
- Handle<Object> value_handle(value);
+ Handle<Object> value_handle(value, isolate);
// To accommodate both the old and the new api we switch on the
// data structure used to store the callbacks. Eventually proxy
@@ -1642,7 +1691,7 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
AccessorDescriptor* callback =
reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
MaybeObject* obj = (callback->setter)(this, value, callback->data);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (obj->IsFailure()) return obj;
return *value_handle;
}
@@ -1654,17 +1703,17 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
if (call_fun == NULL) return value;
Handle<String> key(name);
- LOG(ApiNamedPropertyAccess("store", this, name));
- CustomArguments args(data->data(), this, JSObject::cast(holder));
+ LOG(isolate, ApiNamedPropertyAccess("store", this, name));
+ CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
v8::AccessorInfo info(args.end());
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
call_fun(v8::Utils::ToLocal(key),
v8::Utils::ToLocal(value_handle),
info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return *value_handle;
}
@@ -1674,10 +1723,11 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
} else {
Handle<String> key(name);
- Handle<Object> holder_handle(holder);
+ Handle<Object> holder_handle(holder, isolate);
Handle<Object> args[2] = { key, holder_handle };
- return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
- HandleVector(args, 2)));
+ return isolate->Throw(
+ *isolate->factory()->NewTypeError("no_setter_in_callback",
+ HandleVector(args, 2)));
}
}
@@ -1688,13 +1738,15 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
Object* value) {
- Handle<Object> value_handle(value);
- Handle<JSFunction> fun(JSFunction::cast(setter));
- Handle<JSObject> self(this);
+ Isolate* isolate = GetIsolate();
+ Handle<Object> value_handle(value, isolate);
+ Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
+ Handle<JSObject> self(this, isolate);
#ifdef ENABLE_DEBUGGER_SUPPORT
+ Debug* debug = isolate->debug();
// Handle stepping into a setter if step into is active.
- if (Debug::StepInActive()) {
- Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
+ if (debug->StepInActive()) {
+ debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
}
#endif
bool has_pending_exception;
@@ -1708,8 +1760,9 @@ MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
void JSObject::LookupCallbackSetterInPrototypes(String* name,
LookupResult* result) {
+ Heap* heap = GetHeap();
for (Object* pt = GetPrototype();
- pt != Heap::null_value();
+ pt != heap->null_value();
pt = pt->GetPrototype()) {
JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
if (result->IsProperty()) {
@@ -1729,8 +1782,9 @@ void JSObject::LookupCallbackSetterInPrototypes(String* name,
MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index,
Object* value,
bool* found) {
+ Heap* heap = GetHeap();
for (Object* pt = GetPrototype();
- pt != Heap::null_value();
+ pt != heap->null_value();
pt = pt->GetPrototype()) {
if (!JSObject::cast(pt)->HasDictionaryElements()) {
continue;
@@ -1747,7 +1801,7 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index,
}
}
*found = false;
- return Heap::the_hole_value();
+ return heap->the_hole_value();
}
@@ -1766,10 +1820,11 @@ void Map::LookupInDescriptors(JSObject* holder,
String* name,
LookupResult* result) {
DescriptorArray* descriptors = instance_descriptors();
- int number = DescriptorLookupCache::Lookup(descriptors, name);
+ DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
+ int number = cache->Lookup(descriptors, name);
if (number == DescriptorLookupCache::kAbsent) {
number = descriptors->Search(name);
- DescriptorLookupCache::Update(descriptors, name, number);
+ cache->Update(descriptors, name, number);
}
if (number != DescriptorArray::kNotFound) {
result->DescriptorResult(holder, descriptors->GetDetails(number), number);
@@ -1779,6 +1834,77 @@ void Map::LookupInDescriptors(JSObject* holder,
}
+MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
+ bool safe_to_add_transition) {
+ DescriptorArray* descriptors = instance_descriptors();
+ String* external_array_sentinel_name = GetIsolate()->heap()->empty_symbol();
+
+ if (safe_to_add_transition) {
+ // It's only safe to manipulate the descriptor array if it would be
+ // safe to add a transition.
+
+ ASSERT(!is_shared()); // no transitions can be added to shared maps.
+ // Check if the external array transition already exists.
+ DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
+ int index = cache->Lookup(descriptors, external_array_sentinel_name);
+ if (index == DescriptorLookupCache::kAbsent) {
+ index = descriptors->Search(external_array_sentinel_name);
+ cache->Update(descriptors,
+ external_array_sentinel_name,
+ index);
+ }
+
+ // If the transition already exists, check the type. If there is a match,
+ // return it.
+ if (index != DescriptorArray::kNotFound) {
+ PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
+ if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
+ details.array_type() == array_type) {
+ return descriptors->GetValue(index);
+ } else {
+ safe_to_add_transition = false;
+ }
+ }
+ }
+
+ // No transition to an existing external array map. Make a new one.
+ Object* obj;
+ { MaybeObject* maybe_map = CopyDropTransitions();
+ if (!maybe_map->ToObject(&obj)) return maybe_map;
+ }
+ Map* new_map = Map::cast(obj);
+
+ new_map->set_has_fast_elements(false);
+ new_map->set_has_external_array_elements(true);
+ GetIsolate()->counters()->map_to_external_array_elements()->Increment();
+
+ // Only remember the map transition if the object's map is NOT equal to the
+ // global object_function's map and there is not an already existing
+ // non-matching external array transition.
+ bool allow_map_transition =
+ safe_to_add_transition &&
+ (GetIsolate()->context()->global_context()->object_function()->map() !=
+ map());
+ if (allow_map_transition) {
+ // Allocate new instance descriptors for the old map with map transition.
+ ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
+ Map::cast(new_map),
+ array_type);
+ Object* new_descriptors;
+ MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
+ &desc,
+ KEEP_TRANSITIONS);
+ if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
+ return maybe_new_descriptors;
+ }
+ descriptors = DescriptorArray::cast(new_descriptors);
+ set_instance_descriptors(descriptors);
+ }
+
+ return new_map;
+}
+
+
void JSObject::LocalLookupRealNamedProperty(String* name,
LookupResult* result) {
if (IsJSGlobalProxy()) {
@@ -1837,8 +1963,9 @@ void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
LookupResult* result) {
+ Heap* heap = GetHeap();
for (Object* pt = GetPrototype();
- pt != Heap::null_value();
+ pt != heap->null_value();
pt = JSObject::cast(pt)->GetPrototype()) {
JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
@@ -1852,6 +1979,7 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
String* name,
Object* value,
bool check_prototype) {
+ Heap* heap = GetHeap();
if (check_prototype && !result->IsProperty()) {
LookupCallbackSetterInPrototypes(name, result);
}
@@ -1892,7 +2020,7 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
HandleScope scope;
Handle<Object> value_handle(value);
- Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle;
}
@@ -1902,6 +2030,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
Object* value,
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
+ Heap* heap = GetHeap();
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc;
@@ -1911,7 +2040,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
// reallocating them.
if (!name->IsSymbol() && name->length() <= 2) {
Object* symbol_version;
- { MaybeObject* maybe_symbol_version = Heap::LookupSymbol(name);
+ { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
if (maybe_symbol_version->ToObject(&symbol_version)) {
name = String::cast(symbol_version);
}
@@ -1920,7 +2049,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
// Check access rights if needed.
if (IsAccessCheckNeeded()
- && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
+ && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(result, name, value, true);
}
@@ -1946,7 +2075,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
}
if (!result->IsFound()) {
// Neither properties nor transitions found.
- return AddProperty(name, value, attributes);
+ return AddProperty(name, value, attributes, strict_mode);
}
if (result->IsReadOnly() && result->IsProperty()) {
if (strict_mode == kStrictMode) {
@@ -1954,8 +2083,8 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
Handle<String> key(name);
Handle<Object> holder(this);
Handle<Object> args[2] = { key, holder };
- return Top::Throw(*Factory::NewTypeError("strict_read_only_property",
- HandleVector(args, 2)));
+ return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
+ "strict_read_only_property", HandleVector(args, 2)));
} else {
return value;
}
@@ -1998,7 +2127,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
JSFunction* function =
JSFunction::cast(target_descriptors->GetValue(number));
- ASSERT(!Heap::InNewSpace(function));
+ ASSERT(!HEAP->InNewSpace(function));
if (value == function) {
set_map(target_map);
return value;
@@ -2008,6 +2137,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
}
case NULL_DESCRIPTOR:
+ case EXTERNAL_ARRAY_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
default:
UNREACHABLE();
@@ -2027,6 +2157,8 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
String* name,
Object* value,
PropertyAttributes attributes) {
+ Heap* heap = GetHeap();
+
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc;
@@ -2034,7 +2166,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
LocalLookup(name, &result);
// Check access rights if needed.
if (IsAccessCheckNeeded()
- && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
+ && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(&result, name, value, false);
}
@@ -2051,7 +2183,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
// Check for accessor in prototype chain removed here in clone.
if (!result.IsFound()) {
// Neither properties nor transitions found.
- return AddProperty(name, value, attributes);
+ return AddProperty(name, value, attributes, kNonStrictMode);
}
PropertyDetails details = PropertyDetails(attributes, NORMAL);
@@ -2085,6 +2217,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
// if the value is a function.
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case NULL_DESCRIPTOR:
+ case EXTERNAL_ARRAY_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
default:
UNREACHABLE();
@@ -2106,7 +2239,7 @@ PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
if (continue_search) {
// Continue searching via the prototype chain.
Object* pt = GetPrototype();
- if (pt != Heap::null_value()) {
+ if (!pt->IsNull()) {
return JSObject::cast(pt)->
GetPropertyAttributeWithReceiver(receiver, name);
}
@@ -2119,25 +2252,28 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
JSObject* receiver,
String* name,
bool continue_search) {
+ Isolate* isolate = GetIsolate();
+
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
Handle<JSObject> receiver_handle(receiver);
Handle<JSObject> holder_handle(this);
Handle<String> name_handle(name);
- CustomArguments args(interceptor->data(), receiver, this);
+ CustomArguments args(isolate, interceptor->data(), receiver, this);
v8::AccessorInfo info(args.end());
if (!interceptor->query()->IsUndefined()) {
v8::NamedPropertyQuery query =
v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
- LOG(ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
+ LOG(isolate,
+ ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
v8::Handle<v8::Integer> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = query(v8::Utils::ToLocal(name_handle), info);
}
if (!result.IsEmpty()) {
@@ -2147,11 +2283,12 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
} else if (!interceptor->getter()->IsUndefined()) {
v8::NamedPropertyGetter getter =
v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
- LOG(ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
+ LOG(isolate,
+ ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = getter(v8::Utils::ToLocal(name_handle), info);
}
if (!result.IsEmpty()) return DONT_ENUM;
@@ -2181,9 +2318,10 @@ PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
LookupResult* result,
String* name,
bool continue_search) {
+ Heap* heap = GetHeap();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
+ !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
return GetPropertyAttributeWithFailedAccessCheck(receiver,
result,
name,
@@ -2223,6 +2361,7 @@ PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) {
MaybeObject* NormalizedMapCache::Get(JSObject* obj,
PropertyNormalizationMode mode) {
+ Isolate* isolate = obj->GetIsolate();
Map* fast = obj->map();
int index = Hash(fast) % kEntries;
Object* result = get(index);
@@ -2249,7 +2388,7 @@ MaybeObject* NormalizedMapCache::Get(JSObject* obj,
if (!maybe_result->ToObject(&result)) return maybe_result;
}
set(index, result);
- Counters::normalized_maps.Increment();
+ isolate->counters()->normalized_maps()->Increment();
return result;
}
@@ -2309,7 +2448,7 @@ MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
UNIQUE_NORMALIZED_MAP);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- Counters::normalized_maps.Increment();
+ GetIsolate()->counters()->normalized_maps()->Increment();
set_map(Map::cast(obj));
}
@@ -2323,10 +2462,11 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
// The global object is always normalized.
ASSERT(!IsGlobalObject());
-
// JSGlobalProxy must never be normalized
ASSERT(!IsJSGlobalProxy());
+ Heap* heap = GetHeap();
+
// Allocate new content.
int property_count = map()->NumberOfDescribedProperties();
if (expected_additional_properties > 0) {
@@ -2395,8 +2535,8 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
int index = map()->instance_descriptors()->NextEnumerationIndex();
dictionary->SetNextEnumerationIndex(index);
- { MaybeObject* maybe_obj = Top::context()->global_context()->
- normalized_map_cache()->Get(this, mode);
+ { MaybeObject* maybe_obj = heap->isolate()->context()->global_context()->
+ normalized_map_cache()->Get(this, mode);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
Map* new_map = Map::cast(obj);
@@ -2408,14 +2548,15 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
int new_instance_size = new_map->instance_size();
int instance_size_delta = map()->instance_size() - new_instance_size;
ASSERT(instance_size_delta >= 0);
- Heap::CreateFillerObjectAt(this->address() + new_instance_size,
+ heap->CreateFillerObjectAt(this->address() + new_instance_size,
instance_size_delta);
set_map(new_map);
+ map()->set_instance_descriptors(heap->empty_descriptor_array());
set_properties(dictionary);
- Counters::props_to_dictionary.Increment();
+ heap->isolate()->counters()->props_to_dictionary()->Increment();
#ifdef DEBUG
if (FLAG_trace_normalization) {
@@ -2436,7 +2577,7 @@ MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
MaybeObject* JSObject::NormalizeElements() {
- ASSERT(!HasPixelElements() && !HasExternalArrayElements());
+ ASSERT(!HasExternalArrayElements());
if (HasDictionaryElements()) return this;
ASSERT(map()->has_fast_elements());
@@ -2476,7 +2617,8 @@ MaybeObject* JSObject::NormalizeElements() {
set_map(new_map);
set_elements(dictionary);
- Counters::elements_to_dictionary.Increment();
+ new_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
+ Increment();
#ifdef DEBUG
if (FLAG_trace_normalization) {
@@ -2492,9 +2634,10 @@ MaybeObject* JSObject::NormalizeElements() {
MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
DeleteMode mode) {
// Check local property, ignore interceptor.
+ Heap* heap = GetHeap();
LookupResult result;
LocalLookupRealNamedProperty(name, &result);
- if (!result.IsProperty()) return Heap::true_value();
+ if (!result.IsProperty()) return heap->true_value();
// Normalize object if needed.
Object* obj;
@@ -2507,23 +2650,25 @@ MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
- HandleScope scope;
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
Handle<String> name_handle(name);
Handle<JSObject> this_handle(this);
if (!interceptor->deleter()->IsUndefined()) {
v8::NamedPropertyDeleter deleter =
v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
- LOG(ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
- CustomArguments args(interceptor->data(), this, this);
+ LOG(isolate,
+ ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
+ CustomArguments args(isolate, interceptor->data(), this, this);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Boolean> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = deleter(v8::Utils::ToLocal(name_handle), info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) {
ASSERT(result->IsBoolean());
return *v8::Utils::OpenHandle(*result);
@@ -2531,14 +2676,15 @@ MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
}
MaybeObject* raw_result =
this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return raw_result;
}
MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
DeleteMode mode) {
- ASSERT(!HasPixelElements() && !HasExternalArrayElements());
+ Heap* heap = GetHeap();
+ ASSERT(!HasExternalArrayElements());
switch (GetElementsKind()) {
case FAST_ELEMENTS: {
Object* obj;
@@ -2565,52 +2711,56 @@ MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
UNREACHABLE();
break;
}
- return Heap::true_value();
+ return heap->true_value();
}
MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
+ Isolate* isolate = GetIsolate();
+ Heap* heap = isolate->heap();
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
- if (interceptor->deleter()->IsUndefined()) return Heap::false_value();
+ if (interceptor->deleter()->IsUndefined()) return heap->false_value();
v8::IndexedPropertyDeleter deleter =
v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
Handle<JSObject> this_handle(this);
- LOG(ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
- CustomArguments args(interceptor->data(), this, this);
+ LOG(isolate,
+ ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
+ CustomArguments args(isolate, interceptor->data(), this, this);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Boolean> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = deleter(index, info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) {
ASSERT(result->IsBoolean());
return *v8::Utils::OpenHandle(*result);
}
MaybeObject* raw_result =
this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return raw_result;
}
MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
+ Isolate* isolate = GetIsolate();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
- return Heap::false_value();
+ !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
+ isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
+ return isolate->heap()->false_value();
}
if (IsJSGlobalProxy()) {
Object* proto = GetPrototype();
- if (proto->IsNull()) return Heap::false_value();
+ if (proto->IsNull()) return isolate->heap()->false_value();
ASSERT(proto->IsJSGlobalObject());
return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
}
@@ -2637,7 +2787,7 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
}
break;
}
- case PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
@@ -2653,15 +2803,16 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
int entry = dictionary->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
Object* result = dictionary->DeleteProperty(entry, mode);
- if (mode == STRICT_DELETION && result == Heap::false_value()) {
+ if (mode == STRICT_DELETION && result ==
+ isolate->heap()->false_value()) {
// In strict mode, deleting a non-configurable property throws
// exception. dictionary->DeleteProperty will return false_value()
// if a non-configurable property is being deleted.
HandleScope scope;
- Handle<Object> i = Factory::NewNumberFromUint(index);
+ Handle<Object> i = isolate->factory()->NewNumberFromUint(index);
Handle<Object> args[2] = { i, Handle<Object>(this) };
- return Top::Throw(*Factory::NewTypeError("strict_delete_property",
- HandleVector(args, 2)));
+ return isolate->Throw(*isolate->factory()->NewTypeError(
+ "strict_delete_property", HandleVector(args, 2)));
}
}
break;
@@ -2670,24 +2821,25 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
UNREACHABLE();
break;
}
- return Heap::true_value();
+ return isolate->heap()->true_value();
}
MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
+ Isolate* isolate = GetIsolate();
// ECMA-262, 3rd, 8.6.2.5
ASSERT(name->IsString());
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
- return Heap::false_value();
+ !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
+ isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
+ return isolate->heap()->false_value();
}
if (IsJSGlobalProxy()) {
Object* proto = GetPrototype();
- if (proto->IsNull()) return Heap::false_value();
+ if (proto->IsNull()) return isolate->heap()->false_value();
ASSERT(proto->IsJSGlobalObject());
return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
}
@@ -2698,17 +2850,17 @@ MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
} else {
LookupResult result;
LocalLookup(name, &result);
- if (!result.IsProperty()) return Heap::true_value();
+ if (!result.IsProperty()) return isolate->heap()->true_value();
// Ignore attributes if forcing a deletion.
if (result.IsDontDelete() && mode != FORCE_DELETION) {
if (mode == STRICT_DELETION) {
// Deleting a non-configurable property in strict mode.
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
- return Top::Throw(*Factory::NewTypeError("strict_delete_property",
- HandleVector(args, 2)));
+ return isolate->Throw(*isolate->factory()->NewTypeError(
+ "strict_delete_property", HandleVector(args, 2)));
}
- return Heap::false_value();
+ return isolate->heap()->false_value();
}
// Check for interceptor.
if (result.type() == INTERCEPTOR) {
@@ -2732,6 +2884,7 @@ MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
// Check whether this object references another object.
bool JSObject::ReferencesObject(Object* obj) {
+ Heap* heap = GetHeap();
AssertNoAllocation no_alloc;
// Is the object the constructor for this object?
@@ -2746,13 +2899,13 @@ bool JSObject::ReferencesObject(Object* obj) {
// Check if the object is among the named properties.
Object* key = SlowReverseLookup(obj);
- if (key != Heap::undefined_value()) {
+ if (!key->IsUndefined()) {
return true;
}
// Check if the object is among the indexed properties.
switch (GetElementsKind()) {
- case PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
@@ -2777,7 +2930,7 @@ bool JSObject::ReferencesObject(Object* obj) {
}
case DICTIONARY_ELEMENTS: {
key = element_dictionary()->SlowReverseLookup(obj);
- if (key != Heap::undefined_value()) {
+ if (!key->IsUndefined()) {
return true;
}
break;
@@ -2791,7 +2944,8 @@ bool JSObject::ReferencesObject(Object* obj) {
if (IsJSFunction()) {
// Get the constructor function for arguments array.
JSObject* arguments_boilerplate =
- Top::context()->global_context()->arguments_boilerplate();
+ heap->isolate()->context()->global_context()->
+ arguments_boilerplate();
JSFunction* arguments_function =
JSFunction::cast(arguments_boilerplate->map()->constructor());
@@ -2830,10 +2984,13 @@ bool JSObject::ReferencesObject(Object* obj) {
MaybeObject* JSObject::PreventExtensions() {
+ Isolate* isolate = GetIsolate();
if (IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(this, Heap::undefined_value(), v8::ACCESS_KEYS)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
- return Heap::false_value();
+ !isolate->MayNamedAccess(this,
+ isolate->heap()->undefined_value(),
+ v8::ACCESS_KEYS)) {
+ isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
+ return isolate->heap()->false_value();
}
if (IsJSGlobalProxy()) {
@@ -2872,8 +3029,9 @@ MaybeObject* JSObject::PreventExtensions() {
// - This object has no elements.
// - No prototype has enumerable properties/elements.
bool JSObject::IsSimpleEnum() {
+ Heap* heap = GetHeap();
for (Object* o = this;
- o != Heap::null_value();
+ o != heap->null_value();
o = JSObject::cast(o)->GetPrototype()) {
JSObject* curr = JSObject::cast(o);
if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
@@ -2939,6 +3097,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) {
void JSObject::LocalLookup(String* name, LookupResult* result) {
ASSERT(name->IsString());
+ Heap* heap = GetHeap();
+
if (IsJSGlobalProxy()) {
Object* proto = GetPrototype();
if (proto->IsNull()) return result->NotFound();
@@ -2953,13 +3113,14 @@ void JSObject::LocalLookup(String* name, LookupResult* result) {
}
// Check __proto__ before interceptor.
- if (name->Equals(Heap::Proto_symbol()) && !IsJSContextExtensionObject()) {
+ if (name->Equals(heap->Proto_symbol()) &&
+ !IsJSContextExtensionObject()) {
result->ConstantResult(this);
return;
}
// Check for lookup interceptor except when bootstrapping.
- if (HasNamedInterceptor() && !Bootstrapper::IsActive()) {
+ if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
result->InterceptorResult(this);
return;
}
@@ -2970,8 +3131,9 @@ void JSObject::LocalLookup(String* name, LookupResult* result) {
void JSObject::Lookup(String* name, LookupResult* result) {
// Ecma-262 3rd 8.6.2.4
+ Heap* heap = GetHeap();
for (Object* current = this;
- current != Heap::null_value();
+ current != heap->null_value();
current = JSObject::cast(current)->GetPrototype()) {
JSObject::cast(current)->LocalLookup(name, result);
if (result->IsProperty()) return;
@@ -2982,8 +3144,9 @@ void JSObject::Lookup(String* name, LookupResult* result) {
// Search object and it's prototype chain for callback properties.
void JSObject::LookupCallback(String* name, LookupResult* result) {
+ Heap* heap = GetHeap();
for (Object* current = this;
- current != Heap::null_value();
+ current != heap->null_value();
current = JSObject::cast(current)->GetPrototype()) {
JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
if (result->IsProperty() && result->type() == CALLBACKS) return;
@@ -2994,6 +3157,7 @@ void JSObject::LookupCallback(String* name, LookupResult* result) {
MaybeObject* JSObject::DefineGetterSetter(String* name,
PropertyAttributes attributes) {
+ Heap* heap = GetHeap();
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc;
@@ -3002,7 +3166,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
name->TryFlatten();
if (!CanSetCallback(name)) {
- return Heap::undefined_value();
+ return heap->undefined_value();
}
uint32_t index = 0;
@@ -3012,7 +3176,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
switch (GetElementsKind()) {
case FAST_ELEMENTS:
break;
- case PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
@@ -3022,7 +3186,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
case EXTERNAL_FLOAT_ELEMENTS:
// Ignore getters and setters on pixel and external array
// elements.
- return Heap::undefined_value();
+ return heap->undefined_value();
case DICTIONARY_ELEMENTS: {
// Lookup the index.
NumberDictionary* dictionary = element_dictionary();
@@ -3030,7 +3194,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
if (entry != NumberDictionary::kNotFound) {
Object* result = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.IsReadOnly()) return Heap::undefined_value();
+ if (details.IsReadOnly()) return heap->undefined_value();
if (details.type() == CALLBACKS) {
if (result->IsFixedArray()) {
return result;
@@ -3049,7 +3213,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
LookupResult result;
LocalLookup(name, &result);
if (result.IsProperty()) {
- if (result.IsReadOnly()) return Heap::undefined_value();
+ if (result.IsReadOnly()) return heap->undefined_value();
if (result.type() == CALLBACKS) {
Object* obj = result.GetCallbackObject();
// Need to preserve old getters/setters.
@@ -3063,7 +3227,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
// Allocate the fixed array to hold getter and setter.
Object* structure;
- { MaybeObject* maybe_structure = Heap::AllocateFixedArray(2, TENURED);
+ { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
if (!maybe_structure->ToObject(&structure)) return maybe_structure;
}
@@ -3077,7 +3241,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
bool JSObject::CanSetCallback(String* name) {
ASSERT(!IsAccessCheckNeeded()
- || Top::MayNamedAccess(this, name, v8::ACCESS_SET));
+ || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
// Check if there is an API defined callback object which prohibits
// callback overwriting in this object or it's prototype chain.
@@ -3174,11 +3338,12 @@ MaybeObject* JSObject::DefineAccessor(String* name,
Object* fun,
PropertyAttributes attributes) {
ASSERT(fun->IsJSFunction() || fun->IsUndefined());
+ Isolate* isolate = GetIsolate();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
- return Heap::undefined_value();
+ !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
+ isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
+ return isolate->heap()->undefined_value();
}
if (IsJSGlobalProxy()) {
@@ -3200,12 +3365,13 @@ MaybeObject* JSObject::DefineAccessor(String* name,
MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
+ Isolate* isolate = GetIsolate();
String* name = String::cast(info->name());
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
- return Heap::undefined_value();
+ !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
+ isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
+ return isolate->heap()->undefined_value();
}
if (IsJSGlobalProxy()) {
@@ -3223,20 +3389,20 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
name->TryFlatten();
if (!CanSetCallback(name)) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
uint32_t index = 0;
bool is_element = name->AsArrayIndex(&index);
if (is_element) {
- if (IsJSArray()) return Heap::undefined_value();
+ if (IsJSArray()) return isolate->heap()->undefined_value();
// Accessors overwrite previous callbacks (cf. with getters/setters).
switch (GetElementsKind()) {
case FAST_ELEMENTS:
break;
- case PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
@@ -3246,7 +3412,7 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
case EXTERNAL_FLOAT_ELEMENTS:
// Ignore getters and setters on pixel and external array
// elements.
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
case DICTIONARY_ELEMENTS:
break;
default:
@@ -3266,7 +3432,7 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
// ES5 forbids turning a property into an accessor if it's not
// configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
Object* ok;
{ MaybeObject* maybe_ok =
@@ -3280,15 +3446,17 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Object* JSObject::LookupAccessor(String* name, bool is_getter) {
+ Heap* heap = GetHeap();
+
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc;
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
- return Heap::undefined_value();
+ !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ return heap->undefined_value();
}
// Make the lookup and include prototypes.
@@ -3296,7 +3464,7 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) {
uint32_t index = 0;
if (name->AsArrayIndex(&index)) {
for (Object* obj = this;
- obj != Heap::null_value();
+ obj != heap->null_value();
obj = JSObject::cast(obj)->GetPrototype()) {
JSObject* js_object = JSObject::cast(obj);
if (js_object->HasDictionaryElements()) {
@@ -3315,12 +3483,12 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) {
}
} else {
for (Object* obj = this;
- obj != Heap::null_value();
+ obj != heap->null_value();
obj = JSObject::cast(obj)->GetPrototype()) {
LookupResult result;
JSObject::cast(obj)->LocalLookup(name, &result);
if (result.IsProperty()) {
- if (result.IsReadOnly()) return Heap::undefined_value();
+ if (result.IsReadOnly()) return heap->undefined_value();
if (result.type() == CALLBACKS) {
Object* obj = result.GetCallbackObject();
if (obj->IsFixedArray()) {
@@ -3330,11 +3498,12 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) {
}
}
}
- return Heap::undefined_value();
+ return heap->undefined_value();
}
Object* JSObject::SlowReverseLookup(Object* value) {
+ Heap* heap = GetHeap();
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
@@ -3348,7 +3517,7 @@ Object* JSObject::SlowReverseLookup(Object* value) {
}
}
}
- return Heap::undefined_value();
+ return heap->undefined_value();
} else {
return property_dictionary()->SlowReverseLookup(value);
}
@@ -3356,9 +3525,10 @@ Object* JSObject::SlowReverseLookup(Object* value) {
MaybeObject* Map::CopyDropDescriptors() {
+ Heap* heap = GetHeap();
Object* result;
{ MaybeObject* maybe_result =
- Heap::AllocateMap(instance_type(), instance_size());
+ heap->AllocateMap(instance_type(), instance_size());
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Map::cast(result)->set_prototype(prototype());
@@ -3368,7 +3538,8 @@ MaybeObject* Map::CopyDropDescriptors() {
// pointing to the same transition which is bad because the garbage
// collector relies on being able to reverse pointers from transitions
// to maps. If properties need to be retained use CopyDropTransitions.
- Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array());
+ Map::cast(result)->set_instance_descriptors(
+ heap->empty_descriptor_array());
// Please note instance_type and instance_size are set when allocated.
Map::cast(result)->set_inobject_properties(inobject_properties());
Map::cast(result)->set_unused_property_fields(unused_property_fields());
@@ -3391,7 +3562,7 @@ MaybeObject* Map::CopyDropDescriptors() {
Map::cast(result)->set_bit_field(bit_field());
Map::cast(result)->set_bit_field2(bit_field2());
Map::cast(result)->set_is_shared(false);
- Map::cast(result)->ClearCodeCache();
+ Map::cast(result)->ClearCodeCache(heap);
return result;
}
@@ -3405,7 +3576,7 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
Object* result;
{ MaybeObject* maybe_result =
- Heap::AllocateMap(instance_type(), new_instance_size);
+ GetHeap()->AllocateMap(instance_type(), new_instance_size);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
@@ -3450,7 +3621,7 @@ MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
// Allocate the code cache if not present.
if (code_cache()->IsFixedArray()) {
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateCodeCache();
+ { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
if (!maybe_result->ToObject(&result)) return maybe_result;
}
set_code_cache(result);
@@ -3466,7 +3637,7 @@ Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
if (!code_cache()->IsFixedArray()) {
return CodeCache::cast(code_cache())->Lookup(name, flags);
} else {
- return Heap::undefined_value();
+ return GetHeap()->undefined_value();
}
}
@@ -3490,12 +3661,13 @@ void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
Map* current = this;
- while (current != Heap::meta_map()) {
+ Map* meta_map = heap()->meta_map();
+ while (current != meta_map) {
DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
*RawField(current, Map::kInstanceDescriptorsOffset));
- if (d == Heap::empty_descriptor_array()) {
+ if (d == heap()->empty_descriptor_array()) {
Map* prev = current->map();
- current->set_map(Heap::meta_map());
+ current->set_map(meta_map);
callback(current, data);
current = prev;
continue;
@@ -3520,9 +3692,9 @@ void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
}
}
if (!map_done) continue;
- *map_or_index_field = Heap::fixed_array_map();
+ *map_or_index_field = heap()->fixed_array_map();
Map* prev = current->map();
- current->set_map(Heap::meta_map());
+ current->set_map(meta_map);
callback(current, data);
current = prev;
}
@@ -3635,6 +3807,7 @@ Object* CodeCache::Lookup(String* name, Code::Flags flags) {
Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
+ Heap* heap = GetHeap();
FixedArray* cache = default_cache();
int length = cache->length();
for (int i = 0; i < length; i += kCodeCacheEntrySize) {
@@ -3649,7 +3822,7 @@ Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
}
}
}
- return Heap::undefined_value();
+ return heap->undefined_value();
}
@@ -3658,7 +3831,7 @@ Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
return cache->Lookup(name, flags);
} else {
- return Heap::undefined_value();
+ return GetHeap()->undefined_value();
}
}
@@ -3740,7 +3913,7 @@ class CodeCacheHashTableKey : public HashTableKey {
MUST_USE_RESULT MaybeObject* AsObject() {
ASSERT(code_ != NULL);
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArray(2);
+ { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* pair = FixedArray::cast(obj);
@@ -3759,7 +3932,7 @@ class CodeCacheHashTableKey : public HashTableKey {
Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
CodeCacheHashTableKey key(name, flags);
int entry = FindEntry(&key);
- if (entry == kNotFound) return Heap::undefined_value();
+ if (entry == kNotFound) return GetHeap()->undefined_value();
return get(EntryToIndex(entry) + 1);
}
@@ -3796,8 +3969,9 @@ int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
void CodeCacheHashTable::RemoveByIndex(int index) {
ASSERT(index >= 0);
- set(EntryToIndex(index), Heap::null_value());
- set(EntryToIndex(index) + 1, Heap::null_value());
+ Heap* heap = GetHeap();
+ set(EntryToIndex(index), heap->null_value());
+ set(EntryToIndex(index) + 1, heap->null_value());
ElementRemoved();
}
@@ -3817,7 +3991,8 @@ static bool HasKey(FixedArray* array, Object* key) {
MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
- ASSERT(!array->HasPixelElements() && !array->HasExternalArrayElements());
+ Heap* heap = GetHeap();
+ ASSERT(!array->HasExternalArrayElements());
switch (array->GetElementsKind()) {
case JSObject::FAST_ELEMENTS:
return UnionOfKeys(FixedArray::cast(array->elements()));
@@ -3827,7 +4002,7 @@ MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
// Allocate a temporary fixed array.
Object* object;
- { MaybeObject* maybe_object = Heap::AllocateFixedArray(size);
+ { MaybeObject* maybe_object = heap->AllocateFixedArray(size);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
FixedArray* key_array = FixedArray::cast(object);
@@ -3847,11 +4022,12 @@ MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
UNREACHABLE();
}
UNREACHABLE();
- return Heap::null_value(); // Failure case needs to "return" a value.
+ return heap->null_value(); // Failure case needs to "return" a value.
}
MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
+ Heap* heap = GetHeap();
int len0 = length();
#ifdef DEBUG
if (FLAG_enable_slow_asserts) {
@@ -3877,7 +4053,7 @@ MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
// Allocate the result
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArray(len0 + extra);
+ { MaybeObject* maybe_obj = heap->AllocateFixedArray(len0 + extra);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
// Fill in the content
@@ -3906,9 +4082,10 @@ MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
MaybeObject* FixedArray::CopySize(int new_length) {
- if (new_length == 0) return Heap::empty_fixed_array();
+ Heap* heap = GetHeap();
+ if (new_length == 0) return heap->empty_fixed_array();
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArray(new_length);
+ { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* result = FixedArray::cast(obj);
@@ -3946,13 +4123,14 @@ bool FixedArray::IsEqualTo(FixedArray* other) {
MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
+ Heap* heap = Isolate::Current()->heap();
if (number_of_descriptors == 0) {
- return Heap::empty_descriptor_array();
+ return heap->empty_descriptor_array();
}
// Allocate the array of keys.
Object* array;
{ MaybeObject* maybe_array =
- Heap::AllocateFixedArray(ToKeyIndex(number_of_descriptors));
+ heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
if (!maybe_array->ToObject(&array)) return maybe_array;
}
// Do not use DescriptorArray::cast on incomplete object.
@@ -3960,7 +4138,7 @@ MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
// Allocate the content array and set it in the descriptor array.
{ MaybeObject* maybe_array =
- Heap::AllocateFixedArray(number_of_descriptors << 1);
+ heap->AllocateFixedArray(number_of_descriptors << 1);
if (!maybe_array->ToObject(&array)) return maybe_array;
}
result->set(kContentArrayIndex, array);
@@ -4229,15 +4407,15 @@ int DescriptorArray::LinearSearch(String* name, int len) {
MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
PretenureFlag pretenure) {
ASSERT(deopt_entry_count > 0);
- return Heap::AllocateFixedArray(LengthFor(deopt_entry_count),
+ return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
pretenure);
}
MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
PretenureFlag pretenure) {
- if (number_of_deopt_points == 0) return Heap::empty_fixed_array();
- return Heap::AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
+ if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
+ return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
pretenure);
}
@@ -4255,11 +4433,8 @@ bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
#endif
-static StaticResource<StringInputBuffer> string_input_buffer;
-
-
bool String::LooksValid() {
- if (!Heap::Contains(this)) return false;
+ if (!Isolate::Current()->heap()->Contains(this)) return false;
return true;
}
@@ -4270,8 +4445,10 @@ int String::Utf8Length() {
// doesn't make Utf8Length faster, but it is very likely that
// the string will be accessed later (for example by WriteUtf8)
// so it's still a good idea.
+ Heap* heap = GetHeap();
TryFlatten();
- Access<StringInputBuffer> buffer(&string_input_buffer);
+ Access<StringInputBuffer> buffer(
+ heap->isolate()->objects_string_input_buffer());
buffer->Reset(0, this);
int result = 0;
while (buffer->has_more())
@@ -4337,16 +4514,17 @@ SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
int offset,
int length,
int* length_return) {
- ASSERT(NativeAllocationChecker::allocation_allowed());
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
return SmartPointer<char>(NULL);
}
+ Heap* heap = GetHeap();
// Negative length means the to the end of the string.
if (length < 0) length = kMaxInt - offset;
// Compute the size of the UTF-8 string. Start at the specified offset.
- Access<StringInputBuffer> buffer(&string_input_buffer);
+ Access<StringInputBuffer> buffer(
+ heap->isolate()->objects_string_input_buffer());
buffer->Reset(offset, this);
int character_position = offset;
int utf8_bytes = 0;
@@ -4415,13 +4593,13 @@ const uc16* String::GetTwoByteData(unsigned start) {
SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
- ASSERT(NativeAllocationChecker::allocation_allowed());
-
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
return SmartPointer<uc16>();
}
+ Heap* heap = GetHeap();
- Access<StringInputBuffer> buffer(&string_input_buffer);
+ Access<StringInputBuffer> buffer(
+ heap->isolate()->objects_string_input_buffer());
buffer->Reset(this);
uc16* result = NewArray<uc16>(length() + 1);
@@ -4704,11 +4882,9 @@ const unibrow::byte* String::ReadBlock(String* input,
}
-Relocatable* Relocatable::top_ = NULL;
-
-
void Relocatable::PostGarbageCollectionProcessing() {
- Relocatable* current = top_;
+ Isolate* isolate = Isolate::Current();
+ Relocatable* current = isolate->relocatable_top();
while (current != NULL) {
current->PostGarbageCollection();
current = current->prev_;
@@ -4718,21 +4894,23 @@ void Relocatable::PostGarbageCollectionProcessing() {
// Reserve space for statics needing saving and restoring.
int Relocatable::ArchiveSpacePerThread() {
- return sizeof(top_);
+ return sizeof(Isolate::Current()->relocatable_top());
}
// Archive statics that are thread local.
char* Relocatable::ArchiveState(char* to) {
- *reinterpret_cast<Relocatable**>(to) = top_;
- top_ = NULL;
+ Isolate* isolate = Isolate::Current();
+ *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
+ isolate->set_relocatable_top(NULL);
return to + ArchiveSpacePerThread();
}
// Restore statics that are thread local.
char* Relocatable::RestoreState(char* from) {
- top_ = *reinterpret_cast<Relocatable**>(from);
+ Isolate* isolate = Isolate::Current();
+ isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
return from + ArchiveSpacePerThread();
}
@@ -4745,7 +4923,8 @@ char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
void Relocatable::Iterate(ObjectVisitor* v) {
- Iterate(v, top_);
+ Isolate* isolate = Isolate::Current();
+ Iterate(v, isolate->relocatable_top());
}
@@ -4758,15 +4937,17 @@ void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
}
-FlatStringReader::FlatStringReader(Handle<String> str)
- : str_(str.location()),
+FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
+ : Relocatable(isolate),
+ str_(str.location()),
length_(str->length()) {
PostGarbageCollection();
}
-FlatStringReader::FlatStringReader(Vector<const char> input)
- : str_(0),
+FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
+ : Relocatable(isolate),
+ str_(0),
is_ascii_(true),
length_(input.length()),
start_(input.start()) { }
@@ -5096,11 +5277,10 @@ static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
}
-static StringInputBuffer string_compare_buffer_b;
-
-
template <typename IteratorA>
-static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
+static inline bool CompareStringContentsPartial(Isolate* isolate,
+ IteratorA* ia,
+ String* b) {
if (b->IsFlat()) {
if (b->IsAsciiRepresentation()) {
VectorIterator<char> ib(b->ToAsciiVector());
@@ -5110,15 +5290,13 @@ static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
return CompareStringContents(ia, &ib);
}
} else {
- string_compare_buffer_b.Reset(0, b);
- return CompareStringContents(ia, &string_compare_buffer_b);
+ isolate->objects_string_compare_buffer_b()->Reset(0, b);
+ return CompareStringContents(ia,
+ isolate->objects_string_compare_buffer_b());
}
}
-static StringInputBuffer string_compare_buffer_a;
-
-
bool String::SlowEquals(String* other) {
// Fast check: negative check with lengths.
int len = length();
@@ -5146,6 +5324,7 @@ bool String::SlowEquals(String* other) {
Vector<const char>(str2, len));
}
+ Isolate* isolate = GetIsolate();
if (lhs->IsFlat()) {
if (lhs->IsAsciiRepresentation()) {
Vector<const char> vec1 = lhs->ToAsciiVector();
@@ -5160,8 +5339,9 @@ bool String::SlowEquals(String* other) {
}
} else {
VectorIterator<char> buf1(vec1);
- string_compare_buffer_b.Reset(0, rhs);
- return CompareStringContents(&buf1, &string_compare_buffer_b);
+ isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
+ return CompareStringContents(&buf1,
+ isolate->objects_string_compare_buffer_b());
}
} else {
Vector<const uc16> vec1 = lhs->ToUC16Vector();
@@ -5176,13 +5356,15 @@ bool String::SlowEquals(String* other) {
}
} else {
VectorIterator<uc16> buf1(vec1);
- string_compare_buffer_b.Reset(0, rhs);
- return CompareStringContents(&buf1, &string_compare_buffer_b);
+ isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
+ return CompareStringContents(&buf1,
+ isolate->objects_string_compare_buffer_b());
}
}
} else {
- string_compare_buffer_a.Reset(0, lhs);
- return CompareStringContentsPartial(&string_compare_buffer_a, rhs);
+ isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
+ return CompareStringContentsPartial(isolate,
+ isolate->objects_string_compare_buffer_a(), rhs);
}
}
@@ -5191,11 +5373,12 @@ bool String::MarkAsUndetectable() {
if (StringShape(this).IsSymbol()) return false;
Map* map = this->map();
- if (map == Heap::string_map()) {
- this->set_map(Heap::undetectable_string_map());
+ Heap* heap = map->GetHeap();
+ if (map == heap->string_map()) {
+ this->set_map(heap->undetectable_string_map());
return true;
- } else if (map == Heap::ascii_string_map()) {
- this->set_map(Heap::undetectable_ascii_string_map());
+ } else if (map == heap->ascii_string_map()) {
+ this->set_map(heap->undetectable_ascii_string_map());
return true;
}
// Rest cannot be marked as undetectable
@@ -5204,9 +5387,10 @@ bool String::MarkAsUndetectable() {
bool String::IsEqualTo(Vector<const char> str) {
+ Isolate* isolate = GetIsolate();
int slen = length();
Access<ScannerConstants::Utf8Decoder>
- decoder(ScannerConstants::utf8_decoder());
+ decoder(isolate->scanner_constants()->utf8_decoder());
decoder->Reset(str.start(), str.length());
int i;
for (i = 0; i < slen && decoder->has_more(); i++) {
@@ -5237,22 +5421,6 @@ bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
}
-template <typename schar>
-static inline uint32_t HashSequentialString(const schar* chars, int length) {
- StringHasher hasher(length);
- if (!hasher.has_trivial_hash()) {
- int i;
- for (i = 0; hasher.is_array_index() && (i < length); i++) {
- hasher.AddCharacter(chars[i]);
- }
- for (; i < length; i++) {
- hasher.AddCharacterNoIndex(chars[i]);
- }
- }
- return hasher.GetHashField();
-}
-
-
uint32_t String::ComputeAndSetHash() {
// Should only be called if hash code has not yet been computed.
ASSERT(!HasHashCode());
@@ -5384,8 +5552,9 @@ uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
+ Heap* heap = GetHeap();
if (start == 0 && end == length()) return this;
- MaybeObject* result = Heap::AllocateSubString(this, start, end, pretenure);
+ MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
return result;
}
@@ -5402,6 +5571,7 @@ void Map::CreateBackPointers() {
DescriptorArray* descriptors = instance_descriptors();
for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
if (descriptors->GetType(i) == MAP_TRANSITION ||
+ descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
descriptors->GetType(i) == CONSTANT_TRANSITION) {
// Get target.
Map* target = Map::cast(descriptors->GetValue(i));
@@ -5425,12 +5595,12 @@ void Map::CreateBackPointers() {
}
-void Map::ClearNonLiveTransitions(Object* real_prototype) {
+void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
// Live DescriptorArray objects will be marked, so we must use
// low-level accessors to get and modify their data.
DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
*RawField(this, Map::kInstanceDescriptorsOffset));
- if (d == Heap::raw_unchecked_empty_descriptor_array()) return;
+ if (d == heap->raw_unchecked_empty_descriptor_array()) return;
Smi* NullDescriptorDetails =
PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
FixedArray* contents = reinterpret_cast<FixedArray*>(
@@ -5444,13 +5614,14 @@ void Map::ClearNonLiveTransitions(Object* real_prototype) {
// non-live object.
PropertyDetails details(Smi::cast(contents->get(i + 1)));
if (details.type() == MAP_TRANSITION ||
+ details.type() == EXTERNAL_ARRAY_TRANSITION ||
details.type() == CONSTANT_TRANSITION) {
Map* target = reinterpret_cast<Map*>(contents->get(i));
ASSERT(target->IsHeapObject());
if (!target->IsMarked()) {
ASSERT(target->IsMap());
contents->set_unchecked(i + 1, NullDescriptorDetails);
- contents->set_null_unchecked(i);
+ contents->set_null_unchecked(heap, i);
ASSERT(target->prototype() == this ||
target->prototype() == real_prototype);
// Getter prototype() is read-only, set_prototype() has side effects.
@@ -5474,7 +5645,8 @@ void JSFunction::MarkForLazyRecompilation() {
ASSERT(is_compiled() && !IsOptimized());
ASSERT(shared()->allows_lazy_compilation() ||
code()->optimizable());
- ReplaceCode(Builtins::builtin(Builtins::LazyRecompile));
+ Builtins* builtins = GetIsolate()->builtins();
+ ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
}
@@ -5507,7 +5679,7 @@ bool JSFunction::IsInlineable() {
Object* JSFunction::SetInstancePrototype(Object* value) {
ASSERT(value->IsJSObject());
-
+ Heap* heap = GetHeap();
if (has_initial_map()) {
initial_map()->set_prototype(value);
} else {
@@ -5516,7 +5688,7 @@ Object* JSFunction::SetInstancePrototype(Object* value) {
// prototype is put into the initial map where it belongs.
set_prototype_or_initial_map(value);
}
- Heap::ClearInstanceofCache();
+ heap->ClearInstanceofCache();
return value;
}
@@ -5530,6 +5702,7 @@ MaybeObject* JSFunction::SetPrototype(Object* value) {
// used for constructing objects to the original object prototype.
// See ECMA-262 13.2.2.
if (!value->IsJSObject()) {
+ Heap* heap = GetHeap();
// Copy the map so this does not affect unrelated functions.
// Remove map transitions because they point to maps with a
// different prototype.
@@ -5541,7 +5714,8 @@ MaybeObject* JSFunction::SetPrototype(Object* value) {
map()->set_constructor(value);
map()->set_non_instance_prototype(true);
construct_prototype =
- Top::context()->global_context()->initial_object_prototype();
+ heap->isolate()->context()->global_context()->
+ initial_object_prototype();
} else {
map()->set_non_instance_prototype(false);
}
@@ -5551,13 +5725,22 @@ MaybeObject* JSFunction::SetPrototype(Object* value) {
Object* JSFunction::RemovePrototype() {
- if (map() == context()->global_context()->function_without_prototype_map()) {
+ Context* global_context = context()->global_context();
+ Map* no_prototype_map = shared()->strict_mode()
+ ? global_context->strict_mode_function_without_prototype_map()
+ : global_context->function_without_prototype_map();
+
+ if (map() == no_prototype_map) {
// Be idempotent.
return this;
}
- ASSERT(map() == context()->global_context()->function_map());
- set_map(context()->global_context()->function_without_prototype_map());
- set_prototype_or_initial_map(Heap::the_hole_value());
+
+ ASSERT(!shared()->strict_mode() ||
+ map() == global_context->strict_mode_function_map());
+ ASSERT(shared()->strict_mode() || map() == global_context->function_map());
+
+ set_map(no_prototype_map);
+ set_prototype_or_initial_map(GetHeap()->the_hole_value());
return this;
}
@@ -5579,13 +5762,17 @@ Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
}
-MaybeObject* Oddball::Initialize(const char* to_string, Object* to_number) {
+MaybeObject* Oddball::Initialize(const char* to_string,
+ Object* to_number,
+ byte kind) {
Object* symbol;
- { MaybeObject* maybe_symbol = Heap::LookupAsciiSymbol(to_string);
+ { MaybeObject* maybe_symbol =
+ Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
}
set_to_string(String::cast(symbol));
set_to_number(to_number);
+ set_kind(kind);
return this;
}
@@ -5604,10 +5791,11 @@ bool SharedFunctionInfo::HasSourceCode() {
Object* SharedFunctionInfo::GetSourceCode() {
- if (!HasSourceCode()) return Heap::undefined_value();
- HandleScope scope;
+ Isolate* isolate = GetIsolate();
+ if (!HasSourceCode()) return isolate->heap()->undefined_value();
+ HandleScope scope(isolate);
Object* source = Script::cast(script())->source();
- return *SubString(Handle<String>(String::cast(source)),
+ return *SubString(Handle<String>(String::cast(source), isolate),
start_position(), end_position());
}
@@ -5634,6 +5822,8 @@ int SharedFunctionInfo::CalculateInObjectProperties() {
bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
+ Heap* heap = GetHeap();
+
// Check the basic conditions for generating inline constructor code.
if (!FLAG_inline_new
|| !has_only_simple_this_property_assignments()
@@ -5650,7 +5840,7 @@ bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
// Traverse the proposed prototype chain looking for setters for properties of
// the same names as are set by the inline constructor.
for (Object* obj = prototype;
- obj != Heap::null_value();
+ obj != heap->null_value();
obj = obj->GetPrototype()) {
JSObject* js_object = JSObject::cast(obj);
for (int i = 0; i < this_property_assignments_count(); i++) {
@@ -5686,10 +5876,11 @@ void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
+ Heap* heap = GetHeap();
set_compiler_hints(BooleanBit::set(compiler_hints(),
kHasOnlySimpleThisPropertyAssignments,
false));
- set_this_property_assignments(Heap::undefined_value());
+ set_this_property_assignments(heap->undefined_value());
set_this_property_assignments_count(0);
}
@@ -5834,9 +6025,10 @@ void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
set_construction_count(kGenerousAllocationCount);
}
set_initial_map(map);
- ASSERT_EQ(Builtins::builtin(Builtins::JSConstructStubGeneric),
+ Builtins* builtins = map->heap()->isolate()->builtins();
+ ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
construct_stub());
- set_construct_stub(Builtins::builtin(Builtins::JSConstructStubCountdown));
+ set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
}
@@ -5853,10 +6045,11 @@ void SharedFunctionInfo::DetachInitialMap() {
// then StartInobjectTracking will be called again the next time the
// constructor is called. The countdown will continue and (possibly after
// several more GCs) CompleteInobjectSlackTracking will eventually be called.
- set_initial_map(Heap::raw_unchecked_undefined_value());
- ASSERT_EQ(Builtins::builtin(Builtins::JSConstructStubCountdown),
+ set_initial_map(map->heap()->raw_unchecked_undefined_value());
+ Builtins* builtins = map->heap()->isolate()->builtins();
+ ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
*RawField(this, kConstructStubOffset));
- set_construct_stub(Builtins::builtin(Builtins::JSConstructStubGeneric));
+ set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
// It is safe to clear the flag: it will be set again if the map is live.
set_live_objects_may_exist(false);
}
@@ -5869,9 +6062,10 @@ void SharedFunctionInfo::AttachInitialMap(Map* map) {
// Resume inobject slack tracking.
set_initial_map(map);
- ASSERT_EQ(Builtins::builtin(Builtins::JSConstructStubGeneric),
+ Builtins* builtins = map->heap()->isolate()->builtins();
+ ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
*RawField(this, kConstructStubOffset));
- set_construct_stub(Builtins::builtin(Builtins::JSConstructStubCountdown));
+ set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
// The map survived the gc, so there may be objects referencing it.
set_live_objects_may_exist(true);
}
@@ -5900,10 +6094,12 @@ void SharedFunctionInfo::CompleteInobjectSlackTracking() {
ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
Map* map = Map::cast(initial_map());
- set_initial_map(Heap::undefined_value());
- ASSERT_EQ(Builtins::builtin(Builtins::JSConstructStubCountdown),
+ Heap* heap = map->heap();
+ set_initial_map(heap->undefined_value());
+ Builtins* builtins = heap->isolate()->builtins();
+ ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
construct_stub());
- set_construct_stub(Builtins::builtin(Builtins::JSConstructStubGeneric));
+ set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
int slack = map->unused_property_fields();
map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
@@ -5960,8 +6156,7 @@ void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
void Code::InvalidateRelocation() {
- HandleScope scope;
- set_relocation_info(Heap::empty_byte_array());
+ set_relocation_info(GetHeap()->empty_byte_array());
}
@@ -6255,8 +6450,10 @@ const char* Code::Kind2String(Kind kind) {
case BUILTIN: return "BUILTIN";
case LOAD_IC: return "LOAD_IC";
case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
+ case KEYED_EXTERNAL_ARRAY_LOAD_IC: return "KEYED_EXTERNAL_ARRAY_LOAD_IC";
case STORE_IC: return "STORE_IC";
case KEYED_STORE_IC: return "KEYED_STORE_IC";
+ case KEYED_EXTERNAL_ARRAY_STORE_IC: return "KEYED_EXTERNAL_ARRAY_STORE_IC";
case CALL_IC: return "CALL_IC";
case KEYED_CALL_IC: return "KEYED_CALL_IC";
case BINARY_OP_IC: return "BINARY_OP_IC";
@@ -6291,6 +6488,7 @@ const char* Code::PropertyType2String(PropertyType type) {
case CALLBACKS: return "CALLBACKS";
case INTERCEPTOR: return "INTERCEPTOR";
case MAP_TRANSITION: return "MAP_TRANSITION";
+ case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
}
@@ -6405,11 +6603,12 @@ void Code::Disassemble(const char* name, FILE* out) {
MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
int length) {
+ Heap* heap = GetHeap();
// We should never end in here with a pixel or external array.
- ASSERT(!HasPixelElements() && !HasExternalArrayElements());
+ ASSERT(!HasExternalArrayElements());
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(capacity);
+ { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* elems = FixedArray::cast(obj);
@@ -6460,7 +6659,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
MaybeObject* JSObject::SetSlowElements(Object* len) {
// We should never end in here with a pixel or external array.
- ASSERT(!HasPixelElements() && !HasExternalArrayElements());
+ ASSERT(!HasExternalArrayElements());
uint32_t new_length = static_cast<uint32_t>(len->Number());
@@ -6496,14 +6695,15 @@ MaybeObject* JSObject::SetSlowElements(Object* len) {
MaybeObject* JSArray::Initialize(int capacity) {
+ Heap* heap = GetHeap();
ASSERT(capacity >= 0);
set_length(Smi::FromInt(0));
FixedArray* new_elements;
if (capacity == 0) {
- new_elements = Heap::empty_fixed_array();
+ new_elements = heap->empty_fixed_array();
} else {
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(capacity);
+ { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
new_elements = FixedArray::cast(obj);
@@ -6518,21 +6718,23 @@ void JSArray::Expand(int required_size) {
Handle<FixedArray> old_backing(FixedArray::cast(elements()));
int old_size = old_backing->length();
int new_size = required_size > old_size ? required_size : old_size;
- Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size);
+ Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
// Can't use this any more now because we may have had a GC!
for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
self->SetContent(*new_backing);
}
-static Failure* ArrayLengthRangeError() {
+static Failure* ArrayLengthRangeError(Heap* heap) {
HandleScope scope;
- return Top::Throw(*Factory::NewRangeError("invalid_array_length",
- HandleVector<Object>(NULL, 0)));
+ return heap->isolate()->Throw(
+ *FACTORY->NewRangeError("invalid_array_length",
+ HandleVector<Object>(NULL, 0)));
}
MaybeObject* JSObject::SetElementsLength(Object* len) {
+ Heap* heap = GetHeap();
// We should never end in here with a pixel or external array.
ASSERT(AllowsSetElementsLength());
@@ -6540,7 +6742,7 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
Object* smi_length = Smi::FromInt(0);
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
const int value = Smi::cast(smi_length)->value();
- if (value < 0) return ArrayLengthRangeError();
+ if (value < 0) return ArrayLengthRangeError(heap);
switch (GetElementsKind()) {
case FAST_ELEMENTS: {
int old_capacity = FixedArray::cast(elements())->length();
@@ -6606,14 +6808,14 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
if (len->ToArrayIndex(&length)) {
return SetSlowElements(len);
} else {
- return ArrayLengthRangeError();
+ return ArrayLengthRangeError(heap);
}
}
// len is not a number so make the array size one and
// set only element to len.
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArray(1);
+ { MaybeObject* maybe_obj = heap->AllocateFixedArray(1);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray::cast(obj)->set(0, len);
@@ -6625,6 +6827,7 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
MaybeObject* JSObject::SetPrototype(Object* value,
bool skip_hidden_prototypes) {
+ Heap* heap = GetHeap();
// Silently ignore the change if value is not a JSObject or null.
// SpiderMonkey behaves this way.
if (!value->IsJSObject() && !value->IsNull()) return value;
@@ -6633,12 +6836,12 @@ MaybeObject* JSObject::SetPrototype(Object* value,
// prototype cycles are prevented.
// It is sufficient to validate that the receiver is not in the new prototype
// chain.
- for (Object* pt = value; pt != Heap::null_value(); pt = pt->GetPrototype()) {
+ for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
if (JSObject::cast(pt) == this) {
// Cycle detected.
HandleScope scope;
- return Top::Throw(*Factory::NewError("cyclic_proto",
- HandleVector<Object>(NULL, 0)));
+ return heap->isolate()->Throw(
+ *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
}
}
@@ -6663,7 +6866,7 @@ MaybeObject* JSObject::SetPrototype(Object* value,
Map::cast(new_map)->set_prototype(value);
real_receiver->set_map(Map::cast(new_map));
- Heap::ClearInstanceofCache();
+ heap->ClearInstanceofCache();
return value;
}
@@ -6682,8 +6885,8 @@ bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
}
break;
}
- case PIXEL_ELEMENTS: {
- PixelArray* pixels = PixelArray::cast(elements());
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
if (index < static_cast<uint32_t>(pixels->length())) {
return true;
}
@@ -6718,29 +6921,31 @@ bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
if (this->IsStringObjectWithCharacterAt(index)) return true;
Object* pt = GetPrototype();
- if (pt == Heap::null_value()) return false;
+ if (pt->IsNull()) return false;
return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
}
bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
+ Isolate* isolate = GetIsolate();
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Handle<JSObject> receiver_handle(receiver);
Handle<JSObject> holder_handle(this);
- CustomArguments args(interceptor->data(), receiver, this);
+ CustomArguments args(isolate, interceptor->data(), receiver, this);
v8::AccessorInfo info(args.end());
if (!interceptor->query()->IsUndefined()) {
v8::IndexedPropertyQuery query =
v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
- LOG(ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
+ LOG(isolate,
+ ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
v8::Handle<v8::Integer> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = query(index, info);
}
if (!result.IsEmpty()) {
@@ -6750,11 +6955,12 @@ bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
} else if (!interceptor->getter()->IsUndefined()) {
v8::IndexedPropertyGetter getter =
v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
- LOG(ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
+ LOG(isolate,
+ ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = getter(index, info);
}
if (!result.IsEmpty()) return true;
@@ -6764,10 +6970,12 @@ bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
+ Heap* heap = GetHeap();
+
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return UNDEFINED_ELEMENT;
}
@@ -6801,8 +7009,8 @@ JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
}
break;
}
- case PIXEL_ELEMENTS: {
- PixelArray* pixels = PixelArray::cast(elements());
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
break;
}
@@ -6834,10 +7042,12 @@ JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
+ Heap* heap = GetHeap();
+
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return false;
}
@@ -6856,8 +7066,8 @@ bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
!FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
break;
}
- case PIXEL_ELEMENTS: {
- PixelArray* pixels = PixelArray::cast(elements());
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
if (index < static_cast<uint32_t>(pixels->length())) {
return true;
}
@@ -6892,7 +7102,7 @@ bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
if (this->IsStringObjectWithCharacterAt(index)) return true;
Object* pt = GetPrototype();
- if (pt == Heap::null_value()) return false;
+ if (pt->IsNull()) return false;
return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
}
@@ -6901,26 +7111,28 @@ MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Object* value,
StrictModeFlag strict_mode,
bool check_prototype) {
+ Isolate* isolate = GetIsolate();
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Handle<JSObject> this_handle(this);
- Handle<Object> value_handle(value);
+ Handle<Object> value_handle(value, isolate);
if (!interceptor->setter()->IsUndefined()) {
v8::IndexedPropertySetter setter =
v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
- LOG(ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
- CustomArguments args(interceptor->data(), this, this);
+ LOG(isolate,
+ ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
+ CustomArguments args(isolate, interceptor->data(), this, this);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = setter(index, v8::Utils::ToLocal(value_handle), info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) return *value_handle;
}
MaybeObject* raw_result =
@@ -6928,7 +7140,7 @@ MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
*value_handle,
strict_mode,
check_prototype);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return raw_result;
}
@@ -6937,6 +7149,7 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
Object* structure,
uint32_t index,
Object* holder) {
+ Isolate* isolate = GetIsolate();
ASSERT(!structure->IsProxy());
// api style callbacks.
@@ -6944,22 +7157,22 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
AccessorInfo* data = AccessorInfo::cast(structure);
Object* fun_obj = data->getter();
v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<JSObject> self(JSObject::cast(receiver));
Handle<JSObject> holder_handle(JSObject::cast(holder));
- Handle<Object> number = Factory::NewNumberFromUint(index);
- Handle<String> key(Factory::NumberToString(number));
- LOG(ApiNamedPropertyAccess("load", *self, *key));
- CustomArguments args(data->data(), *self, *holder_handle);
+ Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
+ Handle<String> key(isolate->factory()->NumberToString(number));
+ LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
+ CustomArguments args(isolate, data->data(), *self, *holder_handle);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = call_fun(v8::Utils::ToLocal(key), info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
- if (result.IsEmpty()) return Heap::undefined_value();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
+ if (result.IsEmpty()) return isolate->heap()->undefined_value();
return *v8::Utils::OpenHandle(*result);
}
@@ -6971,7 +7184,7 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
JSFunction::cast(getter));
}
// Getter is not a function.
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
UNREACHABLE();
@@ -6983,12 +7196,13 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure,
uint32_t index,
Object* value,
JSObject* holder) {
- HandleScope scope;
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
// We should never get here to initialize a const with the hole
// value since a const declaration would conflict with the setter.
ASSERT(!value->IsTheHole());
- Handle<Object> value_handle(value);
+ Handle<Object> value_handle(value, isolate);
// To accommodate both the old and the new api we switch on the
// data structure used to store the callbacks. Eventually proxy
@@ -7001,19 +7215,19 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure,
Object* call_obj = data->setter();
v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
if (call_fun == NULL) return value;
- Handle<Object> number = Factory::NewNumberFromUint(index);
- Handle<String> key(Factory::NumberToString(number));
- LOG(ApiNamedPropertyAccess("store", this, *key));
- CustomArguments args(data->data(), this, JSObject::cast(holder));
+ Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
+ Handle<String> key(isolate->factory()->NumberToString(number));
+ LOG(isolate, ApiNamedPropertyAccess("store", this, *key));
+ CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
v8::AccessorInfo info(args.end());
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
call_fun(v8::Utils::ToLocal(key),
v8::Utils::ToLocal(value_handle),
info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return *value_handle;
}
@@ -7022,11 +7236,12 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure,
if (setter->IsJSFunction()) {
return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
} else {
- Handle<Object> holder_handle(holder);
- Handle<Object> key(Factory::NewNumberFromUint(index));
+ Handle<Object> holder_handle(holder, isolate);
+ Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Handle<Object> args[2] = { key, holder_handle };
- return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
- HandleVector(args, 2)));
+ return isolate->Throw(
+ *isolate->factory()->NewTypeError("no_setter_in_callback",
+ HandleVector(args, 2)));
}
}
@@ -7105,12 +7320,13 @@ MaybeObject* JSObject::SetElement(uint32_t index,
Object* value,
StrictModeFlag strict_mode,
bool check_prototype) {
+ Heap* heap = GetHeap();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) {
+ !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
HandleScope scope;
Handle<Object> value_handle(value);
- Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle;
}
@@ -7143,12 +7359,13 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Object* value,
StrictModeFlag strict_mode,
bool check_prototype) {
+ Isolate* isolate = GetIsolate();
switch (GetElementsKind()) {
case FAST_ELEMENTS:
// Fast case.
return SetFastElement(index, value, strict_mode, check_prototype);
- case PIXEL_ELEMENTS: {
- PixelArray* pixels = PixelArray::cast(elements());
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
return pixels->SetValue(index, value);
}
case EXTERNAL_BYTE_ELEMENTS: {
@@ -7198,12 +7415,12 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
// If put fails instrict mode, throw exception.
if (!dictionary->ValueAtPut(entry, value) &&
strict_mode == kStrictMode) {
- Handle<Object> number(Factory::NewNumberFromUint(index));
+ Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
Handle<Object> holder(this);
Handle<Object> args[2] = { number, holder };
- return Top::Throw(
- *Factory::NewTypeError("strict_read_only_property",
- HandleVector(args, 2)));
+ return isolate->Throw(
+ *isolate->factory()->NewTypeError("strict_read_only_property",
+ HandleVector(args, 2)));
}
}
} else {
@@ -7218,11 +7435,17 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
// When we set the is_extensible flag to false we always force
// the element into dictionary mode (and force them to stay there).
if (!map()->is_extensible()) {
- Handle<Object> number(Factory::NewNumberFromUint(index));
- Handle<String> index_string(Factory::NumberToString(number));
- Handle<Object> args[1] = { index_string };
- return Top::Throw(*Factory::NewTypeError("object_not_extensible",
- HandleVector(args, 1)));
+ if (strict_mode == kNonStrictMode) {
+ return isolate->heap()->undefined_value();
+ } else {
+ Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
+ Handle<String> index_string(
+ isolate->factory()->NumberToString(number));
+ Handle<Object> args[1] = { index_string };
+ return isolate->Throw(
+ *isolate->factory()->NewTypeError("object_not_extensible",
+ HandleVector(args, 1)));
+ }
}
Object* result;
{ MaybeObject* maybe_result = dictionary->AtNumberPut(index, value);
@@ -7275,7 +7498,7 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
// All possible cases have been handled above. Add a return to avoid the
// complaints from the compiler.
UNREACHABLE();
- return Heap::null_value();
+ return isolate->heap()->null_value();
}
@@ -7288,7 +7511,7 @@ MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
if (index >= old_len && index != 0xffffffff) {
Object* len;
{ MaybeObject* maybe_len =
- Heap::NumberFromDouble(static_cast<double>(index) + 1);
+ GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
if (!maybe_len->ToObject(&len)) return maybe_len;
}
set_length(len);
@@ -7299,6 +7522,7 @@ MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
uint32_t index) {
+ Heap* heap = GetHeap();
// Get element works for both JSObject and JSArray since
// JSArray::length cannot change.
switch (GetElementsKind()) {
@@ -7310,7 +7534,7 @@ MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
}
break;
}
- case PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
@@ -7347,51 +7571,54 @@ MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
// Continue searching via the prototype chain.
Object* pt = GetPrototype();
- if (pt == Heap::null_value()) return Heap::undefined_value();
+ if (pt->IsNull()) return heap->undefined_value();
return pt->GetElementWithReceiver(receiver, index);
}
MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
uint32_t index) {
+ Isolate* isolate = GetIsolate();
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope;
- Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
- Handle<Object> this_handle(receiver);
- Handle<JSObject> holder_handle(this);
+ HandleScope scope(isolate);
+ Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
+ Handle<Object> this_handle(receiver, isolate);
+ Handle<JSObject> holder_handle(this, isolate);
if (!interceptor->getter()->IsUndefined()) {
v8::IndexedPropertyGetter getter =
v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
- LOG(ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
- CustomArguments args(interceptor->data(), receiver, this);
+ LOG(isolate,
+ ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
+ CustomArguments args(isolate, interceptor->data(), receiver, this);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = getter(index, info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
}
MaybeObject* raw_result =
holder_handle->GetElementPostInterceptor(*this_handle, index);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return raw_result;
}
MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
uint32_t index) {
+ Heap* heap = GetHeap();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayIndexedAccess(this, index, v8::ACCESS_GET)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_GET);
- return Heap::undefined_value();
+ !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) {
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
+ return heap->undefined_value();
}
if (HasIndexedInterceptor()) {
@@ -7409,7 +7636,7 @@ MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
}
break;
}
- case PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
@@ -7442,7 +7669,7 @@ MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
}
Object* pt = GetPrototype();
- if (pt == Heap::null_value()) return Heap::undefined_value();
+ if (pt == heap->null_value()) return heap->undefined_value();
return pt->GetElementWithReceiver(receiver, index);
}
@@ -7451,8 +7678,8 @@ MaybeObject* JSObject::GetExternalElement(uint32_t index) {
// Get element works for both JSObject and JSArray since
// JSArray::length cannot change.
switch (GetElementsKind()) {
- case PIXEL_ELEMENTS: {
- PixelArray* pixels = PixelArray::cast(elements());
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
if (index < static_cast<uint32_t>(pixels->length())) {
uint8_t value = pixels->get(index);
return Smi::FromInt(value);
@@ -7497,7 +7724,7 @@ MaybeObject* JSObject::GetExternalElement(uint32_t index) {
ExternalIntArray* array = ExternalIntArray::cast(elements());
if (index < static_cast<uint32_t>(array->length())) {
int32_t value = array->get(index);
- return Heap::NumberFromInt32(value);
+ return GetHeap()->NumberFromInt32(value);
}
break;
}
@@ -7506,7 +7733,7 @@ MaybeObject* JSObject::GetExternalElement(uint32_t index) {
ExternalUnsignedIntArray::cast(elements());
if (index < static_cast<uint32_t>(array->length())) {
uint32_t value = array->get(index);
- return Heap::NumberFromUint32(value);
+ return GetHeap()->NumberFromUint32(value);
}
break;
}
@@ -7514,7 +7741,7 @@ MaybeObject* JSObject::GetExternalElement(uint32_t index) {
ExternalFloatArray* array = ExternalFloatArray::cast(elements());
if (index < static_cast<uint32_t>(array->length())) {
float value = array->get(index);
- return Heap::AllocateHeapNumber(value);
+ return GetHeap()->AllocateHeapNumber(value);
}
break;
}
@@ -7523,7 +7750,7 @@ MaybeObject* JSObject::GetExternalElement(uint32_t index) {
UNREACHABLE();
break;
}
- return Heap::undefined_value();
+ return GetHeap()->undefined_value();
}
@@ -7540,7 +7767,7 @@ bool JSObject::HasDenseElements() {
}
break;
}
- case PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
@@ -7668,6 +7895,7 @@ MaybeObject* JSObject::GetPropertyPostInterceptor(
JSObject* receiver,
String* name,
PropertyAttributes* attributes) {
+ Heap* heap = GetHeap();
// Check local property in holder, ignore interceptor.
LookupResult result;
LocalLookupRealNamedProperty(name, &result);
@@ -7677,7 +7905,7 @@ MaybeObject* JSObject::GetPropertyPostInterceptor(
// Continue searching via the prototype chain.
Object* pt = GetPrototype();
*attributes = ABSENT;
- if (pt == Heap::null_value()) return Heap::undefined_value();
+ if (pt->IsNull()) return heap->undefined_value();
return pt->GetPropertyWithReceiver(receiver, name, attributes);
}
@@ -7686,13 +7914,14 @@ MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
JSObject* receiver,
String* name,
PropertyAttributes* attributes) {
+ Heap* heap = GetHeap();
// Check local property in holder, ignore interceptor.
LookupResult result;
LocalLookupRealNamedProperty(name, &result);
if (result.IsProperty()) {
return GetProperty(receiver, &result, name, attributes);
}
- return Heap::undefined_value();
+ return heap->undefined_value();
}
@@ -7700,8 +7929,9 @@ MaybeObject* JSObject::GetPropertyWithInterceptor(
JSObject* receiver,
String* name,
PropertyAttributes* attributes) {
+ Isolate* isolate = GetIsolate();
InterceptorInfo* interceptor = GetNamedInterceptor();
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<JSObject> receiver_handle(receiver);
Handle<JSObject> holder_handle(this);
Handle<String> name_handle(name);
@@ -7709,16 +7939,17 @@ MaybeObject* JSObject::GetPropertyWithInterceptor(
if (!interceptor->getter()->IsUndefined()) {
v8::NamedPropertyGetter getter =
v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
- LOG(ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
- CustomArguments args(interceptor->data(), receiver, this);
+ LOG(isolate,
+ ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
+ CustomArguments args(isolate, interceptor->data(), receiver, this);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
result = getter(v8::Utils::ToLocal(name_handle), info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) {
*attributes = NONE;
return *v8::Utils::OpenHandle(*result);
@@ -7729,16 +7960,17 @@ MaybeObject* JSObject::GetPropertyWithInterceptor(
*receiver_handle,
*name_handle,
attributes);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return result;
}
bool JSObject::HasRealNamedProperty(String* key) {
+ Heap* heap = GetHeap();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ !heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return false;
}
@@ -7749,10 +7981,11 @@ bool JSObject::HasRealNamedProperty(String* key) {
bool JSObject::HasRealElementProperty(uint32_t index) {
+ Heap* heap = GetHeap();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return false;
}
@@ -7768,8 +8001,8 @@ bool JSObject::HasRealElementProperty(uint32_t index) {
return (index < length) &&
!FixedArray::cast(elements())->get(index)->IsTheHole();
}
- case PIXEL_ELEMENTS: {
- PixelArray* pixels = PixelArray::cast(elements());
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
return index < static_cast<uint32_t>(pixels->length());
}
case EXTERNAL_BYTE_ELEMENTS:
@@ -7792,15 +8025,16 @@ bool JSObject::HasRealElementProperty(uint32_t index) {
}
// All possibilities have been handled above already.
UNREACHABLE();
- return Heap::null_value();
+ return heap->null_value();
}
bool JSObject::HasRealNamedCallbackProperty(String* key) {
+ Heap* heap = GetHeap();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) {
- Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ !heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return false;
}
@@ -8000,8 +8234,8 @@ int JSObject::GetLocalElementKeys(FixedArray* storage,
ASSERT(!storage || storage->length() >= counter);
break;
}
- case PIXEL_ELEMENTS: {
- int length = PixelArray::cast(elements())->length();
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ int length = ExternalPixelArray::cast(elements())->length();
while (counter < length) {
if (storage != NULL) {
storage->set(counter, Smi::FromInt(counter));
@@ -8063,51 +8297,6 @@ int JSObject::GetEnumElementKeys(FixedArray* storage) {
}
-bool NumberDictionaryShape::IsMatch(uint32_t key, Object* other) {
- ASSERT(other->IsNumber());
- return key == static_cast<uint32_t>(other->Number());
-}
-
-
-uint32_t NumberDictionaryShape::Hash(uint32_t key) {
- return ComputeIntegerHash(key);
-}
-
-
-uint32_t NumberDictionaryShape::HashForObject(uint32_t key, Object* other) {
- ASSERT(other->IsNumber());
- return ComputeIntegerHash(static_cast<uint32_t>(other->Number()));
-}
-
-
-MaybeObject* NumberDictionaryShape::AsObject(uint32_t key) {
- return Heap::NumberFromUint32(key);
-}
-
-
-bool StringDictionaryShape::IsMatch(String* key, Object* other) {
- // We know that all entries in a hash table had their hash keys created.
- // Use that knowledge to have fast failure.
- if (key->Hash() != String::cast(other)->Hash()) return false;
- return key->Equals(String::cast(other));
-}
-
-
-uint32_t StringDictionaryShape::Hash(String* key) {
- return key->Hash();
-}
-
-
-uint32_t StringDictionaryShape::HashForObject(String* key, Object* other) {
- return String::cast(other)->Hash();
-}
-
-
-MaybeObject* StringDictionaryShape::AsObject(String* key) {
- return key;
-}
-
-
// StringKey simply carries a string object as key.
class StringKey : public HashTableKey {
public:
@@ -8190,7 +8379,7 @@ class StringSharedKey : public HashTableKey {
MUST_USE_RESULT MaybeObject* AsObject() {
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArray(3);
+ { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* pair = FixedArray::cast(obj);
@@ -8274,7 +8463,8 @@ class Utf8SymbolKey : public HashTableKey {
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- return Heap::AllocateSymbol(string_, chars_, hash_field_);
+ return Isolate::Current()->heap()->AllocateSymbol(
+ string_, chars_, hash_field_);
}
Vector<const char> string_;
@@ -8341,7 +8531,7 @@ class AsciiSymbolKey : public SequentialSymbolKey<char> {
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- return Heap::AllocateAsciiSymbol(string_, hash_field_);
+ return HEAP->AllocateAsciiSymbol(string_, hash_field_);
}
};
@@ -8357,7 +8547,7 @@ class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- return Heap::AllocateTwoByteSymbol(string_, hash_field_);
+ return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
}
};
@@ -8365,7 +8555,8 @@ class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
// SymbolKey carries a string/symbol object as key.
class SymbolKey : public HashTableKey {
public:
- explicit SymbolKey(String* string) : string_(string) { }
+ explicit SymbolKey(String* string)
+ : string_(string) { }
bool IsMatch(Object* string) {
return String::cast(string)->Equals(string_);
@@ -8381,8 +8572,9 @@ class SymbolKey : public HashTableKey {
// Attempt to flatten the string, so that symbols will most often
// be flat strings.
string_ = string_->TryFlattenGetString();
+ Heap* heap = string_->GetHeap();
// Transform string to symbol if possible.
- Map* map = Heap::SymbolMapForString(string_);
+ Map* map = heap->SymbolMapForString(string_);
if (map != NULL) {
string_->set_map(map);
ASSERT(string_->IsSymbol());
@@ -8390,7 +8582,7 @@ class SymbolKey : public HashTableKey {
}
// Otherwise allocate a new symbol.
StringInputBuffer buffer(string_);
- return Heap::AllocateInternalSymbol(&buffer,
+ return heap->AllocateInternalSymbol(&buffer,
string_->length(),
string_->hash_field());
}
@@ -8429,8 +8621,8 @@ MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
}
Object* obj;
- { MaybeObject* maybe_obj =
- Heap::AllocateHashTable(EntryToIndex(capacity), pretenure);
+ { MaybeObject* maybe_obj = Isolate::Current()->heap()->
+ AllocateHashTable(EntryToIndex(capacity), pretenure);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
HashTable::cast(obj)->SetNumberOfElements(0);
@@ -8441,23 +8633,6 @@ MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
// Find entry for key otherwise return kNotFound.
-template<typename Shape, typename Key>
-int HashTable<Shape, Key>::FindEntry(Key key) {
- uint32_t capacity = Capacity();
- uint32_t entry = FirstProbe(Shape::Hash(key), capacity);
- uint32_t count = 1;
- // EnsureCapacity will guarantee the hash table is never full.
- while (true) {
- Object* element = KeyAt(entry);
- if (element->IsUndefined()) break; // Empty entry.
- if (!element->IsNull() && Shape::IsMatch(key, element)) return entry;
- entry = NextProbe(entry, count++, capacity);
- }
- return kNotFound;
-}
-
-
-// Find entry for key otherwise return kNotFound.
int StringDictionary::FindEntry(String* key) {
if (!key->IsSymbol()) {
return HashTable<StringDictionaryShape, String*>::FindEntry(key);
@@ -8499,6 +8674,7 @@ int StringDictionary::FindEntry(String* key) {
template<typename Shape, typename Key>
MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
+ Heap* heap = GetHeap();
int capacity = Capacity();
int nof = NumberOfElements() + n;
int nod = NumberOfDeletedElements();
@@ -8512,7 +8688,7 @@ MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
const int kMinCapacityForPretenure = 256;
bool pretenure =
- (capacity > kMinCapacityForPretenure) && !Heap::InNewSpace(this);
+ (capacity > kMinCapacityForPretenure) && !heap->InNewSpace(this);
Object* obj;
{ MaybeObject* maybe_obj =
Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
@@ -8644,6 +8820,7 @@ int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
// Collates undefined and unexisting elements below limit from position
// zero of the elements. The object stays in Dictionary mode.
MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
+ Heap* heap = GetHeap();
ASSERT(HasDictionaryElements());
// Must stay in dictionary mode, either because of requires_slow_elements,
// or because we are not going to sort (and therefore compact) all of the
@@ -8653,7 +8830,7 @@ MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
// Allocate space for result before we start mutating the object.
Object* new_double;
- { MaybeObject* maybe_new_double = Heap::AllocateHeapNumber(0.0);
+ { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
}
result_double = HeapNumber::cast(new_double);
@@ -8719,7 +8896,7 @@ MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
// allocation. Bailout.
return Smi::FromInt(-1);
}
- new_dict->AddNumberEntry(pos, Heap::undefined_value(), no_details)->
+ new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
ToObjectUnchecked();
pos++;
undefs--;
@@ -8742,7 +8919,8 @@ MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
// If the object is in dictionary mode, it is converted to fast elements
// mode.
MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
- ASSERT(!HasPixelElements() && !HasExternalArrayElements());
+ Heap* heap = GetHeap();
+ ASSERT(!HasExternalArrayElements());
if (HasDictionaryElements()) {
// Convert to fast elements containing only the existing properties.
@@ -8760,10 +8938,10 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
}
Map* new_map = Map::cast(obj);
- PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED;
+ PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
Object* new_array;
{ MaybeObject* maybe_new_array =
- Heap::AllocateFixedArray(dict->NumberOfElements(), tenure);
+ heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
}
FixedArray* fast_elements = FixedArray::cast(new_array);
@@ -8796,7 +8974,7 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
// Pessimistically allocate space for return value before
// we start mutating the array.
Object* new_double;
- { MaybeObject* maybe_new_double = Heap::AllocateHeapNumber(0.0);
+ { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
}
result_double = HeapNumber::cast(new_double);
@@ -8854,7 +9032,7 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
}
-Object* PixelArray::SetValue(uint32_t index, Object* value) {
+Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
uint8_t clamped_value = 0;
if (index < static_cast<uint32_t>(length())) {
if (value->IsSmi()) {
@@ -8890,7 +9068,8 @@ Object* PixelArray::SetValue(uint32_t index, Object* value) {
template<typename ExternalArrayClass, typename ValueType>
-static MaybeObject* ExternalArrayIntSetter(ExternalArrayClass* receiver,
+static MaybeObject* ExternalArrayIntSetter(Heap* heap,
+ ExternalArrayClass* receiver,
uint32_t index,
Object* value) {
ValueType cast_value = 0;
@@ -8908,45 +9087,46 @@ static MaybeObject* ExternalArrayIntSetter(ExternalArrayClass* receiver,
}
receiver->set(index, cast_value);
}
- return Heap::NumberFromInt32(cast_value);
+ return heap->NumberFromInt32(cast_value);
}
MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
return ExternalArrayIntSetter<ExternalByteArray, int8_t>
- (this, index, value);
+ (GetHeap(), this, index, value);
}
MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
Object* value) {
return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
- (this, index, value);
+ (GetHeap(), this, index, value);
}
MaybeObject* ExternalShortArray::SetValue(uint32_t index,
Object* value) {
return ExternalArrayIntSetter<ExternalShortArray, int16_t>
- (this, index, value);
+ (GetHeap(), this, index, value);
}
MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
Object* value) {
return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
- (this, index, value);
+ (GetHeap(), this, index, value);
}
MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
return ExternalArrayIntSetter<ExternalIntArray, int32_t>
- (this, index, value);
+ (GetHeap(), this, index, value);
}
MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
uint32_t cast_value = 0;
+ Heap* heap = GetHeap();
if (index < static_cast<uint32_t>(length())) {
if (value->IsSmi()) {
int int_value = Smi::cast(value)->value();
@@ -8961,12 +9141,13 @@ MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
}
set(index, cast_value);
}
- return Heap::NumberFromUint32(cast_value);
+ return heap->NumberFromUint32(cast_value);
}
MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
float cast_value = 0;
+ Heap* heap = GetHeap();
if (index < static_cast<uint32_t>(length())) {
if (value->IsSmi()) {
int int_value = Smi::cast(value)->value();
@@ -8981,7 +9162,7 @@ MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
}
set(index, cast_value);
}
- return Heap::AllocateHeapNumber(cast_value);
+ return heap->AllocateHeapNumber(cast_value);
}
@@ -8994,11 +9175,12 @@ JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
ASSERT(!HasFastProperties());
+ Heap* heap = GetHeap();
int entry = property_dictionary()->FindEntry(name);
if (entry == StringDictionary::kNotFound) {
Object* cell;
{ MaybeObject* maybe_cell =
- Heap::AllocateJSGlobalPropertyCell(Heap::the_hole_value());
+ heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
if (!maybe_cell->ToObject(&cell)) return maybe_cell;
}
PropertyDetails details(NONE, NORMAL);
@@ -9170,9 +9352,10 @@ MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Object* CompilationCacheTable::Lookup(String* src) {
+ Heap* heap = GetHeap();
StringKey key(src);
int entry = FindEntry(&key);
- if (entry == kNotFound) return Heap::undefined_value();
+ if (entry == kNotFound) return heap->undefined_value();
return get(EntryToIndex(entry) + 1);
}
@@ -9182,16 +9365,17 @@ Object* CompilationCacheTable::LookupEval(String* src,
StrictModeFlag strict_mode) {
StringSharedKey key(src, context->closure()->shared(), strict_mode);
int entry = FindEntry(&key);
- if (entry == kNotFound) return Heap::undefined_value();
+ if (entry == kNotFound) return GetHeap()->undefined_value();
return get(EntryToIndex(entry) + 1);
}
Object* CompilationCacheTable::LookupRegExp(String* src,
JSRegExp::Flags flags) {
+ Heap* heap = GetHeap();
RegExpKey key(src, flags);
int entry = FindEntry(&key);
- if (entry == kNotFound) return Heap::undefined_value();
+ if (entry == kNotFound) return heap->undefined_value();
return get(EntryToIndex(entry) + 1);
}
@@ -9262,12 +9446,13 @@ MaybeObject* CompilationCacheTable::PutRegExp(String* src,
void CompilationCacheTable::Remove(Object* value) {
+ Object* null_value = GetHeap()->null_value();
for (int entry = 0, size = Capacity(); entry < size; entry++) {
int entry_index = EntryToIndex(entry);
int value_index = entry_index + 1;
if (get(value_index) == value) {
- fast_set(this, entry_index, Heap::null_value());
- fast_set(this, value_index, Heap::null_value());
+ fast_set(this, entry_index, null_value);
+ fast_set(this, value_index, null_value);
ElementRemoved();
}
}
@@ -9310,9 +9495,10 @@ class SymbolsKey : public HashTableKey {
Object* MapCache::Lookup(FixedArray* array) {
+ Heap* heap = GetHeap();
SymbolsKey key(array);
int entry = FindEntry(&key);
- if (entry == kNotFound) return Heap::undefined_value();
+ if (entry == kNotFound) return heap->undefined_value();
return get(EntryToIndex(entry) + 1);
}
@@ -9349,11 +9535,12 @@ MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
template<typename Shape, typename Key>
MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
+ Heap* heap = Dictionary<Shape, Key>::GetHeap();
int length = HashTable<Shape, Key>::NumberOfElements();
// Allocate and initialize iteration order array.
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArray(length);
+ { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* iteration_order = FixedArray::cast(obj);
@@ -9362,7 +9549,7 @@ MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
}
// Allocate array with enumeration order.
- { MaybeObject* maybe_obj = Heap::AllocateFixedArray(length);
+ { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* enumeration_order = FixedArray::cast(obj);
@@ -9423,8 +9610,9 @@ void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
// Do nothing if the interval [from, to) is empty.
if (from >= to) return;
+ Heap* heap = GetHeap();
int removed_entries = 0;
- Object* sentinel = Heap::null_value();
+ Object* sentinel = heap->null_value();
int capacity = Capacity();
for (int i = 0; i < capacity; i++) {
Object* key = KeyAt(i);
@@ -9445,14 +9633,15 @@ void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
template<typename Shape, typename Key>
Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
JSObject::DeleteMode mode) {
+ Heap* heap = Dictionary<Shape, Key>::GetHeap();
PropertyDetails details = DetailsAt(entry);
// Ignore attributes if forcing a deletion.
if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) {
- return Heap::false_value();
+ return heap->false_value();
}
- SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0));
+ SetEntry(entry, heap->null_value(), heap->null_value(), Smi::FromInt(0));
HashTable<Shape, Key>::ElementRemoved();
- return Heap::true_value();
+ return heap->true_value();
}
@@ -9665,6 +9854,7 @@ void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
// Backwards lookup (slow).
template<typename Shape, typename Key>
Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
+ Heap* heap = Dictionary<Shape, Key>::GetHeap();
int capacity = HashTable<Shape, Key>::Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
@@ -9676,12 +9866,13 @@ Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
if (e == value) return k;
}
}
- return Heap::undefined_value();
+ return heap->undefined_value();
}
MaybeObject* StringDictionary::TransformPropertiesToFastFor(
JSObject* obj, int unused_property_fields) {
+ Heap* heap = GetHeap();
// Make sure we preserve dictionary representation if there are too many
// descriptors.
if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
@@ -9711,7 +9902,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
ASSERT(type != FIELD);
instance_descriptor_length++;
if (type == NORMAL &&
- (!value->IsJSFunction() || Heap::InNewSpace(value))) {
+ (!value->IsJSFunction() || heap->InNewSpace(value))) {
number_of_fields += 1;
}
}
@@ -9739,7 +9930,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
// Allocate the fixed array for the fields.
Object* fields;
{ MaybeObject* maybe_fields =
- Heap::AllocateFixedArray(number_of_allocated_fields);
+ heap->AllocateFixedArray(number_of_allocated_fields);
if (!maybe_fields->ToObject(&fields)) return maybe_fields;
}
@@ -9752,13 +9943,13 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Object* value = ValueAt(i);
// Ensure the key is a symbol before writing into the instance descriptor.
Object* key;
- { MaybeObject* maybe_key = Heap::LookupSymbol(String::cast(k));
+ { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
if (!maybe_key->ToObject(&key)) return maybe_key;
}
PropertyDetails details = DetailsAt(i);
PropertyType type = details.type();
- if (value->IsJSFunction() && !Heap::InNewSpace(value)) {
+ if (value->IsJSFunction() && !heap->InNewSpace(value)) {
ConstantFunctionDescriptor d(String::cast(key),
JSFunction::cast(value),
details.attributes(),
@@ -9829,11 +10020,12 @@ bool DebugInfo::HasBreakPoint(int code_position) {
// Get the break point info object for this code position.
Object* DebugInfo::GetBreakPointInfo(int code_position) {
+ Heap* heap = GetHeap();
// Find the index of the break point info object for this code position.
int index = GetBreakPointInfoIndex(code_position);
// Return the break point info object if any.
- if (index == kNoBreakPointInfo) return Heap::undefined_value();
+ if (index == kNoBreakPointInfo) return heap->undefined_value();
return BreakPointInfo::cast(break_points()->get(index));
}
@@ -9855,6 +10047,7 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
int source_position,
int statement_position,
Handle<Object> break_point_object) {
+ Isolate* isolate = Isolate::Current();
Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
if (!break_point_info->IsUndefined()) {
BreakPointInfo::SetBreakPoint(
@@ -9877,8 +10070,9 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
Handle<FixedArray> old_break_points =
Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Handle<FixedArray> new_break_points =
- Factory::NewFixedArray(old_break_points->length() +
- Debug::kEstimatedNofBreakPointsInFunction);
+ isolate->factory()->NewFixedArray(
+ old_break_points->length() +
+ Debug::kEstimatedNofBreakPointsInFunction);
debug_info->set_break_points(*new_break_points);
for (int i = 0; i < old_break_points->length(); i++) {
@@ -9889,13 +10083,14 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
ASSERT(index != kNoBreakPointInfo);
// Allocate new BreakPointInfo object and set the break point.
- Handle<BreakPointInfo> new_break_point_info =
- Handle<BreakPointInfo>::cast(Factory::NewStruct(BREAK_POINT_INFO_TYPE));
+ Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
+ isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
new_break_point_info->set_code_position(Smi::FromInt(code_position));
new_break_point_info->set_source_position(Smi::FromInt(source_position));
new_break_point_info->
set_statement_position(Smi::FromInt(statement_position));
- new_break_point_info->set_break_point_objects(Heap::undefined_value());
+ new_break_point_info->set_break_point_objects(
+ isolate->heap()->undefined_value());
BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
debug_info->break_points()->set(index, *new_break_point_info);
}
@@ -9903,9 +10098,10 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
// Get the break point objects for a code position.
Object* DebugInfo::GetBreakPointObjects(int code_position) {
+ Heap* heap = GetHeap();
Object* break_point_info = GetBreakPointInfo(code_position);
if (break_point_info->IsUndefined()) {
- return Heap::undefined_value();
+ return heap->undefined_value();
}
return BreakPointInfo::cast(break_point_info)->break_point_objects();
}
@@ -9928,7 +10124,8 @@ int DebugInfo::GetBreakPointCount() {
Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
Handle<Object> break_point_object) {
- if (debug_info->break_points()->IsUndefined()) return Heap::undefined_value();
+ Heap* heap = Isolate::Current()->heap();
+ if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
for (int i = 0; i < debug_info->break_points()->length(); i++) {
if (!debug_info->break_points()->get(i)->IsUndefined()) {
Handle<BreakPointInfo> break_point_info =
@@ -9940,7 +10137,7 @@ Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
}
}
}
- return Heap::undefined_value();
+ return heap->undefined_value();
}
@@ -9964,12 +10161,14 @@ int DebugInfo::GetBreakPointInfoIndex(int code_position) {
// Remove the specified break point object.
void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<Object> break_point_object) {
+ Isolate* isolate = Isolate::Current();
// If there are no break points just ignore.
if (break_point_info->break_point_objects()->IsUndefined()) return;
// If there is a single break point clear it if it is the same.
if (!break_point_info->break_point_objects()->IsFixedArray()) {
if (break_point_info->break_point_objects() == *break_point_object) {
- break_point_info->set_break_point_objects(Heap::undefined_value());
+ break_point_info->set_break_point_objects(
+ isolate->heap()->undefined_value());
}
return;
}
@@ -9979,7 +10178,7 @@ void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<FixedArray>(
FixedArray::cast(break_point_info->break_point_objects()));
Handle<FixedArray> new_array =
- Factory::NewFixedArray(old_array->length() - 1);
+ isolate->factory()->NewFixedArray(old_array->length() - 1);
int found_count = 0;
for (int i = 0; i < old_array->length(); i++) {
if (old_array->get(i) == *break_point_object) {
@@ -10006,7 +10205,7 @@ void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
if (break_point_info->break_point_objects() == *break_point_object) return;
// If there was one break point object before replace with array.
if (!break_point_info->break_point_objects()->IsFixedArray()) {
- Handle<FixedArray> array = Factory::NewFixedArray(2);
+ Handle<FixedArray> array = FACTORY->NewFixedArray(2);
array->set(0, break_point_info->break_point_objects());
array->set(1, *break_point_object);
break_point_info->set_break_point_objects(*array);
@@ -10017,7 +10216,7 @@ void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<FixedArray>(
FixedArray::cast(break_point_info->break_point_objects()));
Handle<FixedArray> new_array =
- Factory::NewFixedArray(old_array->length() + 1);
+ FACTORY->NewFixedArray(old_array->length() + 1);
for (int i = 0; i < old_array->length(); i++) {
// If the break point was there before just ignore.
if (old_array->get(i) == *break_point_object) return;
diff --git a/src/objects.h b/src/objects.h
index d7b87c65..96e5cb69 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -57,8 +57,8 @@
// - JSValue
// - JSMessageObject
// - ByteArray
-// - PixelArray
// - ExternalArray
+// - ExternalPixelArray
// - ExternalByteArray
// - ExternalUnsignedByteArray
// - ExternalShortArray
@@ -135,19 +135,37 @@ class PropertyDetails BASE_EMBEDDED {
PropertyDetails(PropertyAttributes attributes,
PropertyType type,
int index = 0) {
+ ASSERT(type != EXTERNAL_ARRAY_TRANSITION);
ASSERT(TypeField::is_valid(type));
ASSERT(AttributesField::is_valid(attributes));
- ASSERT(IndexField::is_valid(index));
+ ASSERT(StorageField::is_valid(index));
value_ = TypeField::encode(type)
| AttributesField::encode(attributes)
- | IndexField::encode(index);
+ | StorageField::encode(index);
ASSERT(type == this->type());
ASSERT(attributes == this->attributes());
ASSERT(index == this->index());
}
+ PropertyDetails(PropertyAttributes attributes,
+ PropertyType type,
+ ExternalArrayType array_type) {
+ ASSERT(type == EXTERNAL_ARRAY_TRANSITION);
+ ASSERT(TypeField::is_valid(type));
+ ASSERT(AttributesField::is_valid(attributes));
+ ASSERT(StorageField::is_valid(static_cast<int>(array_type)));
+
+ value_ = TypeField::encode(type)
+ | AttributesField::encode(attributes)
+ | StorageField::encode(static_cast<int>(array_type));
+
+ ASSERT(type == this->type());
+ ASSERT(attributes == this->attributes());
+ ASSERT(array_type == this->array_type());
+ }
+
// Conversion for storing details as Object*.
inline PropertyDetails(Smi* smi);
inline Smi* AsSmi();
@@ -157,7 +175,8 @@ class PropertyDetails BASE_EMBEDDED {
bool IsTransition() {
PropertyType t = type();
ASSERT(t != INTERCEPTOR);
- return t == MAP_TRANSITION || t == CONSTANT_TRANSITION;
+ return t == MAP_TRANSITION || t == CONSTANT_TRANSITION ||
+ t == EXTERNAL_ARRAY_TRANSITION;
}
bool IsProperty() {
@@ -166,11 +185,18 @@ class PropertyDetails BASE_EMBEDDED {
PropertyAttributes attributes() { return AttributesField::decode(value_); }
- int index() { return IndexField::decode(value_); }
+ int index() { return StorageField::decode(value_); }
+
+ ExternalArrayType array_type() {
+ ASSERT(type() == EXTERNAL_ARRAY_TRANSITION);
+ return static_cast<ExternalArrayType>(StorageField::decode(value_));
+ }
inline PropertyDetails AsDeleted();
- static bool IsValidIndex(int index) { return IndexField::is_valid(index); }
+ static bool IsValidIndex(int index) {
+ return StorageField::is_valid(index);
+ }
bool IsReadOnly() { return (attributes() & READ_ONLY) != 0; }
bool IsDontDelete() { return (attributes() & DONT_DELETE) != 0; }
@@ -179,10 +205,10 @@ class PropertyDetails BASE_EMBEDDED {
// Bit fields in value_ (type, shift, size). Must be public so the
// constants can be embedded in generated code.
- class TypeField: public BitField<PropertyType, 0, 3> {};
- class AttributesField: public BitField<PropertyAttributes, 3, 3> {};
- class DeletedField: public BitField<uint32_t, 6, 1> {};
- class IndexField: public BitField<uint32_t, 7, 32-7> {};
+ class TypeField: public BitField<PropertyType, 0, 4> {};
+ class AttributesField: public BitField<PropertyAttributes, 4, 3> {};
+ class DeletedField: public BitField<uint32_t, 7, 1> {};
+ class StorageField: public BitField<uint32_t, 8, 32-8> {};
static const int kInitialIndex = 1;
private:
@@ -262,7 +288,6 @@ static const int kVariableSizeSentinel = 0;
V(HEAP_NUMBER_TYPE) \
V(PROXY_TYPE) \
V(BYTE_ARRAY_TYPE) \
- V(PIXEL_ARRAY_TYPE) \
/* Note: the order of these external array */ \
/* types is relied upon in */ \
/* Object::IsExternalArray(). */ \
@@ -273,6 +298,7 @@ static const int kVariableSizeSentinel = 0;
V(EXTERNAL_INT_ARRAY_TYPE) \
V(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE) \
V(EXTERNAL_FLOAT_ARRAY_TYPE) \
+ V(EXTERNAL_PIXEL_ARRAY_TYPE) \
V(FILLER_TYPE) \
\
V(ACCESSOR_INFO_TYPE) \
@@ -490,14 +516,14 @@ enum InstanceType {
HEAP_NUMBER_TYPE,
PROXY_TYPE,
BYTE_ARRAY_TYPE,
- PIXEL_ARRAY_TYPE,
EXTERNAL_BYTE_ARRAY_TYPE, // FIRST_EXTERNAL_ARRAY_TYPE
EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
EXTERNAL_SHORT_ARRAY_TYPE,
EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
EXTERNAL_INT_ARRAY_TYPE,
EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
- EXTERNAL_FLOAT_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE
+ EXTERNAL_FLOAT_ARRAY_TYPE,
+ EXTERNAL_PIXEL_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE
FILLER_TYPE, // LAST_DATA_TYPE
// Structs.
@@ -544,7 +570,7 @@ enum InstanceType {
LAST_STRING_TYPE = FIRST_NONSTRING_TYPE - 1,
// Boundaries for testing for an external array.
FIRST_EXTERNAL_ARRAY_TYPE = EXTERNAL_BYTE_ARRAY_TYPE,
- LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_FLOAT_ARRAY_TYPE,
+ LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_PIXEL_ARRAY_TYPE,
// Boundary for promotion to old data space/old pointer space.
LAST_DATA_TYPE = FILLER_TYPE,
// Boundaries for testing the type is a JavaScript "object". Note that
@@ -557,6 +583,8 @@ enum InstanceType {
FIRST_FUNCTION_CLASS_TYPE = JS_REGEXP_TYPE
};
+static const int kExternalArrayTypeCount = LAST_EXTERNAL_ARRAY_TYPE -
+ FIRST_EXTERNAL_ARRAY_TYPE + 1;
STATIC_CHECK(JS_OBJECT_TYPE == Internals::kJSObjectType);
STATIC_CHECK(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType);
@@ -655,7 +683,6 @@ class MaybeObject BASE_EMBEDDED {
V(SeqTwoByteString) \
V(SeqAsciiString) \
\
- V(PixelArray) \
V(ExternalArray) \
V(ExternalByteArray) \
V(ExternalUnsignedByteArray) \
@@ -664,6 +691,7 @@ class MaybeObject BASE_EMBEDDED {
V(ExternalIntArray) \
V(ExternalUnsignedIntArray) \
V(ExternalFloatArray) \
+ V(ExternalPixelArray) \
V(ByteArray) \
V(JSObject) \
V(JSContextExtensionObject) \
@@ -729,6 +757,7 @@ class Object : public MaybeObject {
// Oddball testing.
INLINE(bool IsUndefined());
INLINE(bool IsNull());
+ INLINE(bool IsTheHole()); // Shadows MaybeObject's implementation.
INLINE(bool IsTrue());
INLINE(bool IsFalse());
inline bool IsArgumentsMarker();
@@ -885,7 +914,7 @@ class Failure: public MaybeObject {
enum Type {
RETRY_AFTER_GC = 0,
EXCEPTION = 1, // Returning this marker tells the real exception
- // is in Top::pending_exception.
+ // is in Isolate::pending_exception.
INTERNAL_ERROR = 2,
OUT_OF_MEMORY_EXCEPTION = 3
};
@@ -1073,6 +1102,14 @@ class HeapObject: public Object {
inline MapWord map_word();
inline void set_map_word(MapWord map_word);
+ // The Heap the object was allocated in. Used also to access Isolate.
+ // This method can not be used during GC, it ASSERTs this.
+ inline Heap* GetHeap();
+ // Convenience method to get current isolate. This method can be
+ // accessed only when its result is the same as
+ // Isolate::Current(), it ASSERTs this. See also comment for GetHeap.
+ inline Isolate* GetIsolate();
+
// Converts an address to a HeapObject pointer.
static inline HeapObject* FromAddress(Address address);
@@ -1297,14 +1334,14 @@ class JSObject: public HeapObject {
FAST_ELEMENTS,
// All the kinds below are "slow".
DICTIONARY_ELEMENTS,
- PIXEL_ELEMENTS,
EXTERNAL_BYTE_ELEMENTS,
EXTERNAL_UNSIGNED_BYTE_ELEMENTS,
EXTERNAL_SHORT_ELEMENTS,
EXTERNAL_UNSIGNED_SHORT_ELEMENTS,
EXTERNAL_INT_ELEMENTS,
EXTERNAL_UNSIGNED_INT_ELEMENTS,
- EXTERNAL_FLOAT_ELEMENTS
+ EXTERNAL_FLOAT_ELEMENTS,
+ EXTERNAL_PIXEL_ELEMENTS
};
// [properties]: Backing storage for properties.
@@ -1329,15 +1366,14 @@ class JSObject: public HeapObject {
// few objects and so before writing to any element the array must
// be copied. Use EnsureWritableFastElements in this case.
//
- // In the slow mode elements is either a NumberDictionary or a
- // PixelArray or an ExternalArray.
+ // In the slow mode elements is either a NumberDictionary or an ExternalArray.
DECL_ACCESSORS(elements, HeapObject)
inline void initialize_elements();
MUST_USE_RESULT inline MaybeObject* ResetElements();
inline ElementsKind GetElementsKind();
inline bool HasFastElements();
inline bool HasDictionaryElements();
- inline bool HasPixelElements();
+ inline bool HasExternalPixelElements();
inline bool HasExternalArrayElements();
inline bool HasExternalByteElements();
inline bool HasExternalUnsignedByteElements();
@@ -1588,6 +1624,7 @@ class JSObject: public HeapObject {
inline int GetHeaderSize();
inline int GetInternalFieldCount();
+ inline int GetInternalFieldOffset(int index);
inline Object* GetInternalField(int index);
inline void SetInternalField(int index, Object* value);
@@ -1682,7 +1719,8 @@ class JSObject: public HeapObject {
// Add a property to an object.
MUST_USE_RESULT MaybeObject* AddProperty(String* name,
Object* value,
- PropertyAttributes attributes);
+ PropertyAttributes attributes,
+ StrictModeFlag strict_mode);
// Convert the object to use the canonical dictionary
// representation. If the object is expected to have additional properties
@@ -1705,6 +1743,7 @@ class JSObject: public HeapObject {
inline Object* FastPropertyAtPut(int index, Object* value);
// Access to in object properties.
+ inline int GetInObjectPropertyOffset(int index);
inline Object* InObjectPropertyAt(int index);
inline Object* InObjectPropertyAtPut(int index,
Object* value,
@@ -1891,13 +1930,18 @@ class FixedArray: public HeapObject {
// Setters for frequently used oddballs located in old space.
inline void set_undefined(int index);
+ // TODO(isolates): duplicate.
+ inline void set_undefined(Heap* heap, int index);
inline void set_null(int index);
+ // TODO(isolates): duplicate.
+ inline void set_null(Heap* heap, int index);
inline void set_the_hole(int index);
// Setters with less debug checks for the GC to use.
inline void set_unchecked(int index, Smi* value);
- inline void set_null_unchecked(int index);
- inline void set_unchecked(int index, Object* value, WriteBarrierMode mode);
+ inline void set_null_unchecked(Heap* heap, int index);
+ inline void set_unchecked(Heap* heap, int index, Object* value,
+ WriteBarrierMode mode);
// Gives access to raw memory which stores the array's data.
inline Object** data_start();
@@ -1992,7 +2036,9 @@ class DescriptorArray: public FixedArray {
// Returns the number of descriptors in the array.
int number_of_descriptors() {
- return IsEmpty() ? 0 : length() - kFirstIndex;
+ ASSERT(length() > kFirstIndex || IsEmpty());
+ int len = length();
+ return len <= kFirstIndex ? 0 : len - kFirstIndex;
}
int NextEnumerationIndex() {
@@ -2284,7 +2330,8 @@ class HashTable: public FixedArray {
(FixedArray::kMaxLength - kElementsStartOffset) / kEntrySize;
// Find entry for key otherwise return kNotFound.
- int FindEntry(Key key);
+ inline int FindEntry(Key key);
+ int FindEntry(Isolate* isolate, Key key);
protected:
@@ -2356,16 +2403,16 @@ class HashTableKey {
class SymbolTableShape {
public:
- static bool IsMatch(HashTableKey* key, Object* value) {
+ static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
}
- static uint32_t Hash(HashTableKey* key) {
+ static inline uint32_t Hash(HashTableKey* key) {
return key->Hash();
}
- static uint32_t HashForObject(HashTableKey* key, Object* object) {
+ static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
return key->HashForObject(object);
}
- MUST_USE_RESULT static MaybeObject* AsObject(HashTableKey* key) {
+ MUST_USE_RESULT static inline MaybeObject* AsObject(HashTableKey* key) {
return key->AsObject();
}
@@ -2408,18 +2455,18 @@ class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> {
class MapCacheShape {
public:
- static bool IsMatch(HashTableKey* key, Object* value) {
+ static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
}
- static uint32_t Hash(HashTableKey* key) {
+ static inline uint32_t Hash(HashTableKey* key) {
return key->Hash();
}
- static uint32_t HashForObject(HashTableKey* key, Object* object) {
+ static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
return key->HashForObject(object);
}
- MUST_USE_RESULT static MaybeObject* AsObject(HashTableKey* key) {
+ MUST_USE_RESULT static inline MaybeObject* AsObject(HashTableKey* key) {
return key->AsObject();
}
@@ -2775,59 +2822,6 @@ class ByteArray: public HeapObject {
};
-// A PixelArray represents a fixed-size byte array with special semantics
-// used for implementing the CanvasPixelArray object. Please see the
-// specification at:
-// http://www.whatwg.org/specs/web-apps/current-work/
-// multipage/the-canvas-element.html#canvaspixelarray
-// In particular, write access clamps the value written to 0 or 255 if the
-// value written is outside this range.
-class PixelArray: public HeapObject {
- public:
- // [length]: length of the array.
- inline int length();
- inline void set_length(int value);
-
- // [external_pointer]: The pointer to the external memory area backing this
- // pixel array.
- DECL_ACCESSORS(external_pointer, uint8_t) // Pointer to the data store.
-
- // Setter and getter.
- inline uint8_t get(int index);
- inline void set(int index, uint8_t value);
-
- // This accessor applies the correct conversion from Smi, HeapNumber and
- // undefined and clamps the converted value between 0 and 255.
- Object* SetValue(uint32_t index, Object* value);
-
- // Casting.
- static inline PixelArray* cast(Object* obj);
-
-#ifdef OBJECT_PRINT
- inline void PixelArrayPrint() {
- PixelArrayPrint(stdout);
- }
- void PixelArrayPrint(FILE* out);
-#endif
-#ifdef DEBUG
- void PixelArrayVerify();
-#endif // DEBUG
-
- // Maximal acceptable length for a pixel array.
- static const int kMaxLength = 0x3fffffff;
-
- // PixelArray headers are not quadword aligned.
- static const int kLengthOffset = HeapObject::kHeaderSize;
- static const int kExternalPointerOffset =
- POINTER_SIZE_ALIGN(kLengthOffset + kIntSize);
- static const int kHeaderSize = kExternalPointerOffset + kPointerSize;
- static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(PixelArray);
-};
-
-
// An ExternalArray represents a fixed-size array of primitive values
// which live outside the JavaScript heap. Its subclasses are used to
// implement the CanvasArray types being defined in the WebGL
@@ -2867,6 +2861,44 @@ class ExternalArray: public HeapObject {
};
+// A ExternalPixelArray represents a fixed-size byte array with special
+// semantics used for implementing the CanvasPixelArray object. Please see the
+// specification at:
+
+// http://www.whatwg.org/specs/web-apps/current-work/
+// multipage/the-canvas-element.html#canvaspixelarray
+// In particular, write access clamps the value written to 0 or 255 if the
+// value written is outside this range.
+class ExternalPixelArray: public ExternalArray {
+ public:
+ inline uint8_t* external_pixel_pointer();
+
+ // Setter and getter.
+ inline uint8_t get(int index);
+ inline void set(int index, uint8_t value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber and
+ // undefined and clamps the converted value between 0 and 255.
+ Object* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline ExternalPixelArray* cast(Object* obj);
+
+#ifdef OBJECT_PRINT
+ inline void ExternalPixelArrayPrint() {
+ ExternalPixelArrayPrint(stdout);
+ }
+ void ExternalPixelArrayPrint(FILE* out);
+#endif
+#ifdef DEBUG
+ void ExternalPixelArrayVerify();
+#endif // DEBUG
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalPixelArray);
+};
+
+
class ExternalByteArray: public ExternalArray {
public:
// Setter and getter.
@@ -3201,10 +3233,12 @@ class Code: public HeapObject {
BUILTIN,
LOAD_IC,
KEYED_LOAD_IC,
+ KEYED_EXTERNAL_ARRAY_LOAD_IC,
CALL_IC,
KEYED_CALL_IC,
STORE_IC,
KEYED_STORE_IC,
+ KEYED_EXTERNAL_ARRAY_STORE_IC,
BINARY_OP_IC,
TYPE_RECORDING_BINARY_OP_IC,
COMPARE_IC,
@@ -3279,6 +3313,12 @@ class Code: public HeapObject {
return kind() == TYPE_RECORDING_BINARY_OP_IC;
}
inline bool is_compare_ic_stub() { return kind() == COMPARE_IC; }
+ inline bool is_external_array_load_stub() {
+ return kind() == KEYED_EXTERNAL_ARRAY_LOAD_IC;
+ }
+ inline bool is_external_array_store_stub() {
+ return kind() == KEYED_EXTERNAL_ARRAY_STORE_IC;
+ }
// [major_key]: For kind STUB or BINARY_OP_IC, the major key.
inline int major_key();
@@ -3320,6 +3360,12 @@ class Code: public HeapObject {
inline CheckType check_type();
inline void set_check_type(CheckType value);
+ // [external array type]: For kind KEYED_EXTERNAL_ARRAY_LOAD_IC and
+ // KEYED_EXTERNAL_ARRAY_STORE_IC, identifies the type of external
+ // array that the code stub is specialized for.
+ inline ExternalArrayType external_array_type();
+ inline void set_external_array_type(ExternalArrayType value);
+
// [binary op type]: For all BINARY_OP_IC.
inline byte binary_op_type();
inline void set_binary_op_type(byte value);
@@ -3430,7 +3476,7 @@ class Code: public HeapObject {
inline void CodeIterateBody(ObjectVisitor* v);
template<typename StaticVisitor>
- inline void CodeIterateBody();
+ inline void CodeIterateBody(Heap* heap);
#ifdef OBJECT_PRINT
inline void CodePrint() {
CodePrint(stdout);
@@ -3468,6 +3514,7 @@ class Code: public HeapObject {
static const int kOptimizableOffset = kKindSpecificFlagsOffset;
static const int kStackSlotsOffset = kKindSpecificFlagsOffset;
static const int kCheckTypeOffset = kKindSpecificFlagsOffset;
+ static const int kExternalArrayTypeOffset = kKindSpecificFlagsOffset;
static const int kCompareStateOffset = kStubMajorKeyOffset + 1;
static const int kBinaryOpTypeOffset = kStubMajorKeyOffset + 1;
@@ -3484,18 +3531,18 @@ class Code: public HeapObject {
static const int kFlagsICStateShift = 0;
static const int kFlagsICInLoopShift = 3;
static const int kFlagsTypeShift = 4;
- static const int kFlagsKindShift = 7;
- static const int kFlagsICHolderShift = 11;
- static const int kFlagsExtraICStateShift = 12;
- static const int kFlagsArgumentsCountShift = 14;
+ static const int kFlagsKindShift = 8;
+ static const int kFlagsICHolderShift = 12;
+ static const int kFlagsExtraICStateShift = 13;
+ static const int kFlagsArgumentsCountShift = 15;
static const int kFlagsICStateMask = 0x00000007; // 00000000111
static const int kFlagsICInLoopMask = 0x00000008; // 00000001000
- static const int kFlagsTypeMask = 0x00000070; // 00001110000
- static const int kFlagsKindMask = 0x00000780; // 11110000000
- static const int kFlagsCacheInPrototypeMapMask = 0x00000800;
- static const int kFlagsExtraICStateMask = 0x00003000;
- static const int kFlagsArgumentsCountMask = 0xFFFFC000;
+ static const int kFlagsTypeMask = 0x000000F0; // 00001110000
+ static const int kFlagsKindMask = 0x00000F00; // 11110000000
+ static const int kFlagsCacheInPrototypeMapMask = 0x00001000;
+ static const int kFlagsExtraICStateMask = 0x00006000;
+ static const int kFlagsArgumentsCountMask = 0xFFFF8000;
static const int kFlagsNotUsedInLookup =
(kFlagsICInLoopMask | kFlagsTypeMask | kFlagsCacheInPrototypeMapMask);
@@ -3625,16 +3672,16 @@ class Map: public HeapObject {
}
// Tells whether an instance has pixel array elements.
- inline void set_has_pixel_array_elements(bool value) {
+ inline void set_has_external_array_elements(bool value) {
if (value) {
- set_bit_field2(bit_field2() | (1 << kHasPixelArrayElements));
+ set_bit_field2(bit_field2() | (1 << kHasExternalArrayElements));
} else {
- set_bit_field2(bit_field2() & ~(1 << kHasPixelArrayElements));
+ set_bit_field2(bit_field2() & ~(1 << kHasExternalArrayElements));
}
}
- inline bool has_pixel_array_elements() {
- return ((1 << kHasPixelArrayElements) & bit_field2()) != 0;
+ inline bool has_external_array_elements() {
+ return ((1 << kHasExternalArrayElements) & bit_field2()) != 0;
}
// Tells whether the map is attached to SharedFunctionInfo
@@ -3695,10 +3742,11 @@ class Map: public HeapObject {
// from the descriptors and the fast elements bit cleared.
MUST_USE_RESULT inline MaybeObject* GetSlowElementsMap();
- // Returns this map if it has the pixel array elements bit is set, otherwise
- // returns a copy of the map, with all transitions dropped from the
- // descriptors and the pixel array elements bit set.
- MUST_USE_RESULT inline MaybeObject* GetPixelArrayElementsMap();
+ // Returns a new map with all transitions dropped from the descriptors and the
+ // external array elements bit set.
+ MUST_USE_RESULT MaybeObject* GetExternalArrayElementsMap(
+ ExternalArrayType array_type,
+ bool safe_to_add_transition);
// Returns the property index for name (only valid for FAST MODE).
int PropertyIndexFor(String* name);
@@ -3718,7 +3766,7 @@ class Map: public HeapObject {
// Code cache operations.
// Clears the code cache.
- inline void ClearCodeCache();
+ inline void ClearCodeCache(Heap* heap);
// Update code cache.
MUST_USE_RESULT MaybeObject* UpdateCodeCache(String* name, Code* code);
@@ -3742,7 +3790,7 @@ class Map: public HeapObject {
// Also, restore the original prototype on the targets of these
// transitions, so that we do not process this map again while
// following back pointers.
- void ClearNonLiveTransitions(Object* real_prototype);
+ void ClearNonLiveTransitions(Heap* heap, Object* real_prototype);
// Dispatched behavior.
#ifdef OBJECT_PRINT
@@ -3759,6 +3807,10 @@ class Map: public HeapObject {
inline int visitor_id();
inline void set_visitor_id(int visitor_id);
+ // Returns the isolate/heap this map belongs to.
+ inline Isolate* isolate();
+ inline Heap* heap();
+
typedef void (*TraverseCallback)(Map* map, void* data);
void TraverseTransitionTree(TraverseCallback callback, void* data);
@@ -3818,7 +3870,7 @@ class Map: public HeapObject {
static const int kStringWrapperSafeForDefaultValueOf = 3;
static const int kAttachedToSharedFunctionInfo = 4;
static const int kIsShared = 5;
- static const int kHasPixelArrayElements = 6;
+ static const int kHasExternalArrayElements = 6;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
@@ -5156,6 +5208,11 @@ class StringHasher {
};
+// Calculates string hash.
+template <typename schar>
+inline uint32_t HashSequentialString(const schar* chars, int length);
+
+
// The characteristics of a string are stored in its map. Retrieving these
// few bits of information is moderately expensive, involving two memory
// loads where the second is dependent on the first. To improve efficiency
@@ -5799,11 +5856,8 @@ class ExternalTwoByteString: public ExternalString {
// iterating or updating after gc.
class Relocatable BASE_EMBEDDED {
public:
- inline Relocatable() : prev_(top_) { top_ = this; }
- virtual ~Relocatable() {
- ASSERT_EQ(top_, this);
- top_ = prev_;
- }
+ explicit inline Relocatable(Isolate* isolate);
+ inline virtual ~Relocatable();
virtual void IterateInstance(ObjectVisitor* v) { }
virtual void PostGarbageCollection() { }
@@ -5815,7 +5869,7 @@ class Relocatable BASE_EMBEDDED {
static void Iterate(ObjectVisitor* v, Relocatable* top);
static char* Iterate(ObjectVisitor* v, char* t);
private:
- static Relocatable* top_;
+ Isolate* isolate_;
Relocatable* prev_;
};
@@ -5825,8 +5879,8 @@ class Relocatable BASE_EMBEDDED {
// must be valid as long as the reader is being used.
class FlatStringReader : public Relocatable {
public:
- explicit FlatStringReader(Handle<String> str);
- explicit FlatStringReader(Vector<const char> input);
+ FlatStringReader(Isolate* isolate, Handle<String> str);
+ FlatStringReader(Isolate* isolate, Vector<const char> input);
void PostGarbageCollection();
inline uc32 Get(int index);
int length() { return length_; }
@@ -5889,6 +5943,9 @@ class Oddball: public HeapObject {
// [to_number]: Cached to_number computed at startup.
DECL_ACCESSORS(to_number, Object)
+ inline byte kind();
+ inline void set_kind(byte kind);
+
// Casting.
static inline Oddball* cast(Object* obj);
@@ -5899,12 +5956,23 @@ class Oddball: public HeapObject {
// Initialize the fields.
MUST_USE_RESULT MaybeObject* Initialize(const char* to_string,
- Object* to_number);
+ Object* to_number,
+ byte kind);
// Layout description.
static const int kToStringOffset = HeapObject::kHeaderSize;
static const int kToNumberOffset = kToStringOffset + kPointerSize;
- static const int kSize = kToNumberOffset + kPointerSize;
+ static const int kKindOffset = kToNumberOffset + kPointerSize;
+ static const int kSize = kKindOffset + kPointerSize;
+
+ static const byte kFalse = 0;
+ static const byte kTrue = 1;
+ static const byte kNotBooleanMask = ~1;
+ static const byte kTheHole = 2;
+ static const byte kNull = 3;
+ static const byte kArgumentMarker = 4;
+ static const byte kUndefined = 5;
+ static const byte kOther = 6;
typedef FixedBodyDescriptor<kToStringOffset,
kToNumberOffset + kPointerSize,
@@ -6537,6 +6605,9 @@ class ObjectVisitor BASE_EMBEDDED {
VisitExternalReferences(p, p + 1);
}
+ // Visits a handle that has an embedder-assigned class ID.
+ virtual void VisitEmbedderReference(Object** p, uint16_t class_id) {}
+
#ifdef DEBUG
// Intended for serialization/deserialization checking: insert, or
// check for the presence of, a tag at this position in the stream.
diff --git a/src/parser.cc b/src/parser.cc
index 3c361a7e..13e0c33c 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -246,93 +246,6 @@ void RegExpBuilder::AddQuantifierToAtom(int min,
}
-// A temporary scope stores information during parsing, just like
-// a plain scope. However, temporary scopes are not kept around
-// after parsing or referenced by syntax trees so they can be stack-
-// allocated and hence used by the pre-parser.
-class TemporaryScope BASE_EMBEDDED {
- public:
- explicit TemporaryScope(TemporaryScope** variable);
- ~TemporaryScope();
-
- int NextMaterializedLiteralIndex() {
- int next_index =
- materialized_literal_count_ + JSFunction::kLiteralsPrefixSize;
- materialized_literal_count_++;
- return next_index;
- }
- int materialized_literal_count() { return materialized_literal_count_; }
-
- void SetThisPropertyAssignmentInfo(
- bool only_simple_this_property_assignments,
- Handle<FixedArray> this_property_assignments) {
- only_simple_this_property_assignments_ =
- only_simple_this_property_assignments;
- this_property_assignments_ = this_property_assignments;
- }
- bool only_simple_this_property_assignments() {
- return only_simple_this_property_assignments_;
- }
- Handle<FixedArray> this_property_assignments() {
- return this_property_assignments_;
- }
-
- void AddProperty() { expected_property_count_++; }
- int expected_property_count() { return expected_property_count_; }
-
- void AddLoop() { loop_count_++; }
- bool ContainsLoops() const { return loop_count_ > 0; }
-
- bool StrictMode() { return strict_mode_; }
- void EnableStrictMode() {
- strict_mode_ = FLAG_strict_mode;
- }
-
- private:
- // Captures the number of literals that need materialization in the
- // function. Includes regexp literals, and boilerplate for object
- // and array literals.
- int materialized_literal_count_;
-
- // Properties count estimation.
- int expected_property_count_;
-
- // Keeps track of assignments to properties of this. Used for
- // optimizing constructors.
- bool only_simple_this_property_assignments_;
- Handle<FixedArray> this_property_assignments_;
-
- // Captures the number of loops inside the scope.
- int loop_count_;
-
- // Parsing strict mode code.
- bool strict_mode_;
-
- // Bookkeeping
- TemporaryScope** variable_;
- TemporaryScope* parent_;
-};
-
-
-TemporaryScope::TemporaryScope(TemporaryScope** variable)
- : materialized_literal_count_(0),
- expected_property_count_(0),
- only_simple_this_property_assignments_(false),
- this_property_assignments_(Factory::empty_fixed_array()),
- loop_count_(0),
- variable_(variable),
- parent_(*variable) {
- // Inherit the strict mode from the parent scope.
- strict_mode_ = (parent_ != NULL) && parent_->strict_mode_;
- *variable = this;
-}
-
-
-TemporaryScope::~TemporaryScope() {
- *variable_ = parent_;
-}
-
-
Handle<String> Parser::LookupSymbol(int symbol_id) {
// Length of symbol cache is the number of identified symbols.
// If we are larger than that, or negative, it's not a cached symbol.
@@ -341,9 +254,11 @@ Handle<String> Parser::LookupSymbol(int symbol_id) {
if (static_cast<unsigned>(symbol_id)
>= static_cast<unsigned>(symbol_cache_.length())) {
if (scanner().is_literal_ascii()) {
- return Factory::LookupAsciiSymbol(scanner().literal_ascii_string());
+ return isolate()->factory()->LookupAsciiSymbol(
+ scanner().literal_ascii_string());
} else {
- return Factory::LookupTwoByteSymbol(scanner().literal_uc16_string());
+ return isolate()->factory()->LookupTwoByteSymbol(
+ scanner().literal_uc16_string());
}
}
return LookupCachedSymbol(symbol_id);
@@ -360,14 +275,16 @@ Handle<String> Parser::LookupCachedSymbol(int symbol_id) {
Handle<String> result = symbol_cache_.at(symbol_id);
if (result.is_null()) {
if (scanner().is_literal_ascii()) {
- result = Factory::LookupAsciiSymbol(scanner().literal_ascii_string());
+ result = isolate()->factory()->LookupAsciiSymbol(
+ scanner().literal_ascii_string());
} else {
- result = Factory::LookupTwoByteSymbol(scanner().literal_uc16_string());
+ result = isolate()->factory()->LookupTwoByteSymbol(
+ scanner().literal_uc16_string());
}
symbol_cache_.at(symbol_id) = result;
return result;
}
- Counters::total_preparse_symbols_skipped.Increment();
+ isolate()->counters()->total_preparse_symbols_skipped()->Increment();
return result;
}
@@ -544,33 +461,94 @@ class TargetScope BASE_EMBEDDED {
// LexicalScope is a support class to facilitate manipulation of the
// Parser's scope stack. The constructor sets the parser's top scope
// to the incoming scope, and the destructor resets it.
+//
+// Additionlaly, it stores transient information used during parsing.
+// These scopes are not kept around after parsing or referenced by syntax
+// trees so they can be stack-allocated and hence used by the pre-parser.
class LexicalScope BASE_EMBEDDED {
public:
- LexicalScope(Scope** scope_variable,
- int* with_nesting_level_variable,
- Scope* scope)
- : scope_variable_(scope_variable),
- with_nesting_level_variable_(with_nesting_level_variable),
- prev_scope_(*scope_variable),
- prev_level_(*with_nesting_level_variable) {
- *scope_variable = scope;
- *with_nesting_level_variable = 0;
+ LexicalScope(Parser* parser, Scope* scope, Isolate* isolate);
+ ~LexicalScope();
+
+ int NextMaterializedLiteralIndex() {
+ int next_index =
+ materialized_literal_count_ + JSFunction::kLiteralsPrefixSize;
+ materialized_literal_count_++;
+ return next_index;
}
+ int materialized_literal_count() { return materialized_literal_count_; }
- ~LexicalScope() {
- (*scope_variable_)->Leave();
- *scope_variable_ = prev_scope_;
- *with_nesting_level_variable_ = prev_level_;
+ void SetThisPropertyAssignmentInfo(
+ bool only_simple_this_property_assignments,
+ Handle<FixedArray> this_property_assignments) {
+ only_simple_this_property_assignments_ =
+ only_simple_this_property_assignments;
+ this_property_assignments_ = this_property_assignments;
}
+ bool only_simple_this_property_assignments() {
+ return only_simple_this_property_assignments_;
+ }
+ Handle<FixedArray> this_property_assignments() {
+ return this_property_assignments_;
+ }
+
+ void AddProperty() { expected_property_count_++; }
+ int expected_property_count() { return expected_property_count_; }
+
+ void AddLoop() { loop_count_++; }
+ bool ContainsLoops() const { return loop_count_ > 0; }
private:
- Scope** scope_variable_;
- int* with_nesting_level_variable_;
- Scope* prev_scope_;
- int prev_level_;
+ // Captures the number of literals that need materialization in the
+ // function. Includes regexp literals, and boilerplate for object
+ // and array literals.
+ int materialized_literal_count_;
+
+ // Properties count estimation.
+ int expected_property_count_;
+
+ // Keeps track of assignments to properties of this. Used for
+ // optimizing constructors.
+ bool only_simple_this_property_assignments_;
+ Handle<FixedArray> this_property_assignments_;
+
+ // Captures the number of loops inside the scope.
+ int loop_count_;
+
+ // Bookkeeping
+ Parser* parser_;
+ // Previous values
+ LexicalScope* lexical_scope_parent_;
+ Scope* previous_scope_;
+ int previous_with_nesting_level_;
};
+
+LexicalScope::LexicalScope(Parser* parser, Scope* scope, Isolate* isolate)
+ : materialized_literal_count_(0),
+ expected_property_count_(0),
+ only_simple_this_property_assignments_(false),
+ this_property_assignments_(isolate->factory()->empty_fixed_array()),
+ loop_count_(0),
+ parser_(parser),
+ lexical_scope_parent_(parser->lexical_scope_),
+ previous_scope_(parser->top_scope_),
+ previous_with_nesting_level_(parser->with_nesting_level_) {
+ parser->top_scope_ = scope;
+ parser->lexical_scope_ = this;
+ parser->with_nesting_level_ = 0;
+}
+
+
+LexicalScope::~LexicalScope() {
+ parser_->top_scope_->Leave();
+ parser_->top_scope_ = previous_scope_;
+ parser_->lexical_scope_ = lexical_scope_parent_;
+ parser_->with_nesting_level_ = previous_with_nesting_level_;
+}
+
+
// ----------------------------------------------------------------------------
// The CHECK_OK macro is a convenient macro to enforce error
// handling for functions that may fail (by returning !*ok).
@@ -598,12 +576,13 @@ Parser::Parser(Handle<Script> script,
bool allow_natives_syntax,
v8::Extension* extension,
ScriptDataImpl* pre_data)
- : symbol_cache_(pre_data ? pre_data->symbol_count() : 0),
+ : isolate_(script->GetIsolate()),
+ symbol_cache_(pre_data ? pre_data->symbol_count() : 0),
script_(script),
- scanner_(),
+ scanner_(isolate_->scanner_constants()),
top_scope_(NULL),
with_nesting_level_(0),
- temp_scope_(NULL),
+ lexical_scope_(NULL),
target_stack_(NULL),
allow_natives_syntax_(allow_natives_syntax),
extension_(extension),
@@ -620,8 +599,8 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
StrictModeFlag strict_mode) {
CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
- HistogramTimerScope timer(&Counters::parse);
- Counters::total_parse_size.Increment(source->length());
+ HistogramTimerScope timer(isolate()->counters()->parse());
+ isolate()->counters()->total_parse_size()->Increment(source->length());
fni_ = new FuncNameInferrer();
// Initialize parser state.
@@ -657,21 +636,19 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
in_global_context
? Scope::GLOBAL_SCOPE
: Scope::EVAL_SCOPE;
- Handle<String> no_name = Factory::empty_symbol();
+ Handle<String> no_name = isolate()->factory()->empty_symbol();
FunctionLiteral* result = NULL;
{ Scope* scope = NewScope(top_scope_, type, inside_with());
- LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
- scope);
- TemporaryScope temp_scope(&this->temp_scope_);
+ LexicalScope lexical_scope(this, scope, isolate());
if (strict_mode == kStrictMode) {
- temp_scope.EnableStrictMode();
+ top_scope_->EnableStrictMode();
}
ZoneList<Statement*>* body = new ZoneList<Statement*>(16);
bool ok = true;
int beg_loc = scanner().location().beg_pos;
ParseSourceElements(body, Token::EOS, &ok);
- if (ok && temp_scope_->StrictMode()) {
+ if (ok && top_scope_->is_strict_mode()) {
CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
}
if (ok) {
@@ -679,18 +656,17 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
no_name,
top_scope_,
body,
- temp_scope.materialized_literal_count(),
- temp_scope.expected_property_count(),
- temp_scope.only_simple_this_property_assignments(),
- temp_scope.this_property_assignments(),
+ lexical_scope.materialized_literal_count(),
+ lexical_scope.expected_property_count(),
+ lexical_scope.only_simple_this_property_assignments(),
+ lexical_scope.this_property_assignments(),
0,
0,
source->length(),
false,
- temp_scope.ContainsLoops(),
- temp_scope.StrictMode());
+ lexical_scope.ContainsLoops());
} else if (stack_overflow_) {
- Top::StackOverflow();
+ isolate()->StackOverflow();
}
}
@@ -703,38 +679,40 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
return result;
}
-FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
+FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
- HistogramTimerScope timer(&Counters::parse_lazy);
+ HistogramTimerScope timer(isolate()->counters()->parse_lazy());
Handle<String> source(String::cast(script_->source()));
- Counters::total_parse_size.Increment(source->length());
+ isolate()->counters()->total_parse_size()->Increment(source->length());
+ Handle<SharedFunctionInfo> shared_info = info->shared_info();
// Initialize parser state.
source->TryFlatten();
if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source),
- info->start_position(),
- info->end_position());
+ shared_info->start_position(),
+ shared_info->end_position());
FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
return result;
} else {
GenericStringUC16CharacterStream stream(source,
- info->start_position(),
- info->end_position());
+ shared_info->start_position(),
+ shared_info->end_position());
FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
return result;
}
}
-FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info,
+FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
UC16CharacterStream* source,
ZoneScope* zone_scope) {
+ Handle<SharedFunctionInfo> shared_info = info->shared_info();
scanner_.Initialize(source);
ASSERT(target_stack_ == NULL);
- Handle<String> name(String::cast(info->name()));
+ Handle<String> name(String::cast(shared_info->name()));
fni_ = new FuncNameInferrer();
fni_->PushEnclosingName(name);
@@ -745,19 +723,19 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info,
{
// Parse the function literal.
- Handle<String> no_name = Factory::empty_symbol();
- Scope* scope =
- NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
- LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
- scope);
- TemporaryScope temp_scope(&this->temp_scope_);
-
- if (info->strict_mode()) {
- temp_scope.EnableStrictMode();
+ Handle<String> no_name = isolate()->factory()->empty_symbol();
+ Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
+ if (!info->closure().is_null()) {
+ scope = Scope::DeserializeScopeChain(info, scope);
+ }
+ LexicalScope lexical_scope(this, scope, isolate());
+
+ if (shared_info->strict_mode()) {
+ top_scope_->EnableStrictMode();
}
FunctionLiteralType type =
- info->is_expression() ? EXPRESSION : DECLARATION;
+ shared_info->is_expression() ? EXPRESSION : DECLARATION;
bool ok = true;
result = ParseFunctionLiteral(name,
false, // Strict mode name already checked.
@@ -773,9 +751,9 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info,
// not safe to do before scope has been deleted.
if (result == NULL) {
zone_scope->DeleteOnExit();
- if (stack_overflow_) Top::StackOverflow();
+ if (stack_overflow_) isolate()->StackOverflow();
} else {
- Handle<String> inferred_name(info->inferred_name());
+ Handle<String> inferred_name(shared_info->inferred_name());
result->set_inferred_name(inferred_name);
}
return result;
@@ -803,14 +781,15 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
MessageLocation location(script_,
source_location.beg_pos,
source_location.end_pos);
- Handle<FixedArray> elements = Factory::NewFixedArray(args.length());
+ Factory* factory = isolate()->factory();
+ Handle<FixedArray> elements = factory->NewFixedArray(args.length());
for (int i = 0; i < args.length(); i++) {
- Handle<String> arg_string = Factory::NewStringFromUtf8(CStrVector(args[i]));
+ Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
elements->set(i, *arg_string);
}
- Handle<JSArray> array = Factory::NewJSArrayWithElements(elements);
- Handle<Object> result = Factory::NewSyntaxError(type, array);
- Top::Throw(*result, &location);
+ Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
+ Handle<Object> result = factory->NewSyntaxError(type, array);
+ isolate()->Throw(*result, &location);
}
@@ -820,13 +799,14 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
MessageLocation location(script_,
source_location.beg_pos,
source_location.end_pos);
- Handle<FixedArray> elements = Factory::NewFixedArray(args.length());
+ Factory* factory = isolate()->factory();
+ Handle<FixedArray> elements = factory->NewFixedArray(args.length());
for (int i = 0; i < args.length(); i++) {
elements->set(i, *args[i]);
}
- Handle<JSArray> array = Factory::NewJSArrayWithElements(elements);
- Handle<Object> result = Factory::NewSyntaxError(type, array);
- Top::Throw(*result, &location);
+ Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
+ Handle<Object> result = factory->NewSyntaxError(type, array);
+ isolate()->Throw(*result, &location);
}
@@ -951,8 +931,9 @@ class InitializationBlockFinder : public ParserFinder {
// function contains only assignments of this type.
class ThisNamedPropertyAssigmentFinder : public ParserFinder {
public:
- ThisNamedPropertyAssigmentFinder()
- : only_simple_this_property_assignments_(true),
+ explicit ThisNamedPropertyAssigmentFinder(Isolate* isolate)
+ : isolate_(isolate),
+ only_simple_this_property_assignments_(true),
names_(NULL),
assigned_arguments_(NULL),
assigned_constants_(NULL) {}
@@ -983,14 +964,14 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder {
// form this.x = y;
Handle<FixedArray> GetThisPropertyAssignments() {
if (names_ == NULL) {
- return Factory::empty_fixed_array();
+ return isolate_->factory()->empty_fixed_array();
}
ASSERT(names_ != NULL);
ASSERT(assigned_arguments_ != NULL);
ASSERT_EQ(names_->length(), assigned_arguments_->length());
ASSERT_EQ(names_->length(), assigned_constants_->length());
Handle<FixedArray> assignments =
- Factory::NewFixedArray(names_->length() * 3);
+ isolate_->factory()->NewFixedArray(names_->length() * 3);
for (int i = 0; i < names_->length(); i++) {
assignments->set(i * 3, *names_->at(i));
assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_->at(i)));
@@ -1020,7 +1001,8 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder {
uint32_t dummy;
if (literal != NULL &&
literal->handle()->IsString() &&
- !String::cast(*(literal->handle()))->Equals(Heap::Proto_symbol()) &&
+ !String::cast(*(literal->handle()))->Equals(
+ isolate_->heap()->Proto_symbol()) &&
!String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
Handle<String> key = Handle<String>::cast(literal->handle());
@@ -1054,7 +1036,7 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder {
EnsureAllocation();
names_->Add(name);
assigned_arguments_->Add(index);
- assigned_constants_->Add(Factory::undefined_value());
+ assigned_constants_->Add(isolate_->factory()->undefined_value());
}
void AssignmentFromConstant(Handle<String> name, Handle<Object> value) {
@@ -1079,6 +1061,7 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder {
}
}
+ Isolate* isolate_;
bool only_simple_this_property_assignments_;
ZoneStringList* names_;
ZoneList<int>* assigned_arguments_;
@@ -1100,7 +1083,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
ASSERT(processor != NULL);
InitializationBlockFinder block_finder;
- ThisNamedPropertyAssigmentFinder this_property_assignment_finder;
+ ThisNamedPropertyAssigmentFinder this_property_assignment_finder(isolate());
bool directive_prologue = true; // Parsing directive prologue.
while (peek() != end_token) {
@@ -1140,11 +1123,11 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
Handle<String> directive = Handle<String>::cast(literal->handle());
// Check "use strict" directive (ES5 14.1).
- if (!temp_scope_->StrictMode() &&
- directive->Equals(Heap::use_strict()) &&
+ if (!top_scope_->is_strict_mode() &&
+ directive->Equals(isolate()->heap()->use_strict()) &&
token_loc.end_pos - token_loc.beg_pos ==
- Heap::use_strict()->length() + 2) {
- temp_scope_->EnableStrictMode();
+ isolate()->heap()->use_strict()->length() + 2) {
+ top_scope_->EnableStrictMode();
// "use strict" is the only directive for now.
directive_prologue = false;
}
@@ -1173,7 +1156,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
this_property_assignment_finder.only_simple_this_property_assignments()
&& top_scope_->declarations()->length() == 0;
if (only_simple_this_property_assignments) {
- temp_scope_->SetThisPropertyAssignmentInfo(
+ lexical_scope_->SetThisPropertyAssignmentInfo(
only_simple_this_property_assignments,
this_property_assignment_finder.GetThisPropertyAssignments());
}
@@ -1282,7 +1265,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
case Token::FUNCTION: {
// In strict mode, FunctionDeclaration is only allowed in the context
// of SourceElements.
- if (temp_scope_->StrictMode()) {
+ if (top_scope_->is_strict_mode()) {
ReportMessageAt(scanner().peek_location(), "strict_function",
Vector<const char*>::empty());
*ok = false;
@@ -1341,9 +1324,9 @@ VariableProxy* Parser::Declare(Handle<String> name,
var->mode() == Variable::CONST);
const char* type = (var->mode() == Variable::VAR) ? "var" : "const";
Handle<String> type_string =
- Factory::NewStringFromUtf8(CStrVector(type), TENURED);
+ isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
Expression* expression =
- NewThrowTypeError(Factory::redeclaration_symbol(),
+ NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
type_string, name);
top_scope_->SetIllegalRedeclaration(expression);
}
@@ -1449,7 +1432,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
Handle<Code> code = Handle<Code>(fun->shared()->code());
Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
Handle<SharedFunctionInfo> shared =
- Factory::NewSharedFunctionInfo(name, literals, code,
+ isolate()->factory()->NewSharedFunctionInfo(name, literals, code,
Handle<SerializedScopeInfo>(fun->shared()->scope_info()));
shared->set_construct_stub(*construct_stub);
@@ -1518,11 +1501,13 @@ Block* Parser::ParseVariableStatement(bool* ok) {
return result;
}
-static bool IsEvalOrArguments(Handle<String> string) {
- return string.is_identical_to(Factory::eval_symbol()) ||
- string.is_identical_to(Factory::arguments_symbol());
+
+bool Parser::IsEvalOrArguments(Handle<String> string) {
+ return string.is_identical_to(isolate()->factory()->eval_symbol()) ||
+ string.is_identical_to(isolate()->factory()->arguments_symbol());
}
+
// If the variable declaration declares exactly one non-const
// variable, then *var is set to that variable. In all other cases,
// *var is untouched; in particular, it is the caller's responsibility
@@ -1540,7 +1525,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
Consume(Token::CONST);
- if (temp_scope_->StrictMode()) {
+ if (top_scope_->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false;
return NULL;
@@ -1576,7 +1561,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
if (fni_ != NULL) fni_->PushVariableName(name);
// Strict mode variables may not be named eval or arguments
- if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) {
+ if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
ReportMessage("strict_var_name", Vector<const char*>::empty());
*ok = false;
return NULL;
@@ -1678,14 +1663,14 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// the number of arguments (1 or 2).
initialize =
new CallRuntime(
- Factory::InitializeConstGlobal_symbol(),
+ isolate()->factory()->InitializeConstGlobal_symbol(),
Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
arguments);
} else {
// Add strict mode.
// We may want to pass singleton to avoid Literal allocations.
arguments->Add(NewNumberLiteral(
- temp_scope_->StrictMode() ? kStrictMode : kNonStrictMode));
+ top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode));
// Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not
@@ -1702,7 +1687,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// the number of arguments (2 or 3).
initialize =
new CallRuntime(
- Factory::InitializeVarGlobal_symbol(),
+ isolate()->factory()->InitializeVarGlobal_symbol(),
Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
arguments);
}
@@ -1893,7 +1878,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
//
// To be consistent with KJS we report the syntax error at runtime.
if (!top_scope_->is_function_scope()) {
- Handle<String> type = Factory::illegal_return_symbol();
+ Handle<String> type = isolate()->factory()->illegal_return_symbol();
Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
return new ExpressionStatement(throw_error);
}
@@ -1958,7 +1943,7 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
Expect(Token::WITH, CHECK_OK);
- if (temp_scope_->StrictMode()) {
+ if (top_scope_->is_strict_mode()) {
ReportMessage("strict_mode_with", Vector<const char*>::empty());
*ok = false;
return NULL;
@@ -2097,7 +2082,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::LPAREN, CHECK_OK);
Handle<String> name = ParseIdentifier(CHECK_OK);
- if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) {
+ if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
ReportMessage("strict_catch_variable", Vector<const char*>::empty());
*ok = false;
return NULL;
@@ -2108,7 +2093,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
if (peek() == Token::LBRACE) {
// Allocate a temporary for holding the finally state while
// executing the finally block.
- catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol());
+ catch_var =
+ top_scope_->NewTemporary(isolate()->factory()->catch_var_symbol());
Literal* name_literal = new Literal(name);
VariableProxy* catch_var_use = new VariableProxy(catch_var);
Expression* obj = new CatchExtensionObject(name_literal, catch_var_use);
@@ -2169,7 +2155,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
// DoStatement ::
// 'do' Statement 'while' '(' Expression ')' ';'
- temp_scope_->AddLoop();
+ lexical_scope_->AddLoop();
DoWhileStatement* loop = new DoWhileStatement(labels);
Target target(&this->target_stack_, loop);
@@ -2202,7 +2188,7 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
// WhileStatement ::
// 'while' '(' Expression ')' Statement
- temp_scope_->AddLoop();
+ lexical_scope_->AddLoop();
WhileStatement* loop = new WhileStatement(labels);
Target target(&this->target_stack_, loop);
@@ -2222,7 +2208,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
// ForStatement ::
// 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
- temp_scope_->AddLoop();
+ lexical_scope_->AddLoop();
Statement* init = NULL;
Expect(Token::FOR, CHECK_OK);
@@ -2259,7 +2245,8 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
// error here but for compatibility with JSC we choose to report
// the error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
- Handle<String> type = Factory::invalid_lhs_in_for_in_symbol();
+ Handle<String> type =
+ isolate()->factory()->invalid_lhs_in_for_in_symbol();
expression = NewThrowReferenceError(type);
}
ForInStatement* loop = new ForInStatement(labels);
@@ -2344,11 +2331,12 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
// for compatibility with JSC we choose to report the error at
// runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
- Handle<String> type = Factory::invalid_lhs_in_assignment_symbol();
+ Handle<String> type =
+ isolate()->factory()->invalid_lhs_in_assignment_symbol();
expression = NewThrowReferenceError(type);
}
- if (temp_scope_->StrictMode()) {
+ if (top_scope_->is_strict_mode()) {
// Assignment to eval or arguments is disallowed in strict mode.
CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK);
}
@@ -2367,7 +2355,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
property != NULL &&
property->obj()->AsVariableProxy() != NULL &&
property->obj()->AsVariableProxy()->is_this()) {
- temp_scope_->AddProperty();
+ lexical_scope_->AddProperty();
}
// If we assign a function literal to a property we pretenure the
@@ -2567,7 +2555,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
}
// "delete identifier" is a syntax error in strict mode.
- if (op == Token::DELETE && temp_scope_->StrictMode()) {
+ if (op == Token::DELETE && top_scope_->is_strict_mode()) {
VariableProxy* operand = expression->AsVariableProxy();
if (operand != NULL && !operand->is_this()) {
ReportMessage("strict_delete", Vector<const char*>::empty());
@@ -2586,11 +2574,12 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
// error here but for compatibility with JSC we choose to report the
// error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
- Handle<String> type = Factory::invalid_lhs_in_prefix_op_symbol();
+ Handle<String> type =
+ isolate()->factory()->invalid_lhs_in_prefix_op_symbol();
expression = NewThrowReferenceError(type);
}
- if (temp_scope_->StrictMode()) {
+ if (top_scope_->is_strict_mode()) {
// Prefix expression operand in strict mode may not be eval or arguments.
CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
}
@@ -2617,11 +2606,12 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
// error here but for compatibility with JSC we choose to report the
// error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
- Handle<String> type = Factory::invalid_lhs_in_postfix_op_symbol();
+ Handle<String> type =
+ isolate()->factory()->invalid_lhs_in_postfix_op_symbol();
expression = NewThrowReferenceError(type);
}
- if (temp_scope_->StrictMode()) {
+ if (top_scope_->is_strict_mode()) {
// Postfix expression operand in strict mode may not be eval or arguments.
CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
}
@@ -2674,7 +2664,8 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
// is called without a receiver and it refers to the original eval
// function.
VariableProxy* callee = result->AsVariableProxy();
- if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) {
+ if (callee != NULL &&
+ callee->IsVariable(isolate()->factory()->eval_symbol())) {
Handle<String> name = callee->name();
Variable* var = top_scope_->Lookup(name);
if (var == NULL) {
@@ -2829,7 +2820,7 @@ void Parser::ReportUnexpectedToken(Token::Value token) {
return ReportMessage("unexpected_token_identifier",
Vector<const char*>::empty());
case Token::FUTURE_RESERVED_WORD:
- return ReportMessage(temp_scope_->StrictMode() ?
+ return ReportMessage(top_scope_->is_strict_mode() ?
"unexpected_strict_reserved" :
"unexpected_token_identifier",
Vector<const char*>::empty());
@@ -2875,17 +2866,17 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
case Token::NULL_LITERAL:
Consume(Token::NULL_LITERAL);
- result = new Literal(Factory::null_value());
+ result = new Literal(isolate()->factory()->null_value());
break;
case Token::TRUE_LITERAL:
Consume(Token::TRUE_LITERAL);
- result = new Literal(Factory::true_value());
+ result = new Literal(isolate()->factory()->true_value());
break;
case Token::FALSE_LITERAL:
Consume(Token::FALSE_LITERAL);
- result = new Literal(Factory::false_value());
+ result = new Literal(isolate()->factory()->false_value());
break;
case Token::IDENTIFIER:
@@ -3006,11 +2997,11 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
Expect(Token::RBRACK, CHECK_OK);
// Update the scope information before the pre-parsing bailout.
- int literal_index = temp_scope_->NextMaterializedLiteralIndex();
+ int literal_index = lexical_scope_->NextMaterializedLiteralIndex();
// Allocate a fixed array with all the literals.
Handle<FixedArray> literals =
- Factory::NewFixedArray(values->length(), TENURED);
+ isolate()->factory()->NewFixedArray(values->length(), TENURED);
// Fill in the literals.
bool is_simple = true;
@@ -3032,7 +3023,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
// Simple and shallow arrays can be lazily copied, we transform the
// elements array to a copy-on-write array.
if (is_simple && depth == 1 && values->length() > 0) {
- literals->set_map(Heap::fixed_cow_array_map());
+ literals->set_map(isolate()->heap()->fixed_cow_array_map());
}
return new ArrayLiteral(literals, values,
@@ -3067,7 +3058,7 @@ bool CompileTimeValue::ArrayLiteralElementNeedsInitialization(
Handle<FixedArray> CompileTimeValue::GetValue(Expression* expression) {
ASSERT(IsCompileTimeValue(expression));
- Handle<FixedArray> result = Factory::NewFixedArray(2, TENURED);
+ Handle<FixedArray> result = FACTORY->NewFixedArray(2, TENURED);
ObjectLiteral* object_literal = expression->AsObjectLiteral();
if (object_literal != NULL) {
ASSERT(object_literal->is_simple());
@@ -3105,7 +3096,7 @@ Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
if (CompileTimeValue::IsCompileTimeValue(expression)) {
return CompileTimeValue::GetValue(expression);
}
- return Factory::undefined_value();
+ return isolate()->factory()->undefined_value();
}
// Defined in ast.cc
@@ -3171,7 +3162,7 @@ void ObjectLiteralPropertyChecker::CheckProperty(
if (handle->IsSymbol()) {
Handle<String> name(String::cast(*handle));
if (name->AsArrayIndex(&hash)) {
- Handle<Object> key_handle = Factory::NewNumberFromUint(hash);
+ Handle<Object> key_handle = FACTORY->NewNumberFromUint(hash);
key = key_handle.location();
map = &elems;
} else {
@@ -3188,7 +3179,7 @@ void ObjectLiteralPropertyChecker::CheckProperty(
char arr[100];
Vector<char> buffer(arr, ARRAY_SIZE(arr));
const char* str = DoubleToCString(num, buffer);
- Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
+ Handle<String> name = FACTORY->NewStringFromAscii(CStrVector(str));
key = name.location();
hash = name->Hash();
map = &props;
@@ -3300,7 +3291,7 @@ ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter,
next == Token::STRING || is_keyword) {
Handle<String> name;
if (is_keyword) {
- name = Factory::LookupAsciiSymbol(Token::String(next));
+ name = isolate_->factory()->LookupAsciiSymbol(Token::String(next));
} else {
name = GetSymbol(CHECK_OK);
}
@@ -3333,8 +3324,9 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
ZoneList<ObjectLiteral::Property*>* properties =
new ZoneList<ObjectLiteral::Property*>(4);
int number_of_boilerplate_properties = 0;
+ bool has_function = false;
- ObjectLiteralPropertyChecker checker(this, temp_scope_->StrictMode());
+ ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode());
Expect(Token::LBRACE, CHECK_OK);
Scanner::Location loc = scanner().location();
@@ -3421,6 +3413,13 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
ObjectLiteral::Property* property =
new ObjectLiteral::Property(key, value);
+ // Mark object literals that contain function literals and pretenure the
+ // literal so it can be added as a constant function property.
+ if (value->AsFunctionLiteral() != NULL) {
+ has_function = true;
+ value->AsFunctionLiteral()->set_pretenure(true);
+ }
+
// Count CONSTANT or COMPUTED properties to maintain the enumeration order.
if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
// Validate the property
@@ -3438,10 +3437,10 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
Expect(Token::RBRACE, CHECK_OK);
// Computation of literal_index must happen before pre parse bailout.
- int literal_index = temp_scope_->NextMaterializedLiteralIndex();
+ int literal_index = lexical_scope_->NextMaterializedLiteralIndex();
- Handle<FixedArray> constant_properties =
- Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED);
+ Handle<FixedArray> constant_properties = isolate()->factory()->NewFixedArray(
+ number_of_boilerplate_properties * 2, TENURED);
bool is_simple = true;
bool fast_elements = true;
@@ -3456,7 +3455,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
literal_index,
is_simple,
fast_elements,
- depth);
+ depth,
+ has_function);
}
@@ -3468,7 +3468,7 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
return NULL;
}
- int literal_index = temp_scope_->NextMaterializedLiteralIndex();
+ int literal_index = lexical_scope_->NextMaterializedLiteralIndex();
Handle<String> js_pattern = NextLiteralString(TENURED);
scanner().ScanRegExpFlags();
@@ -3510,9 +3510,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
// this is the actual function name, otherwise this is the name of the
// variable declared and initialized with the function (expression). In
// that case, we don't have a function name (it's empty).
- Handle<String> name = is_named ? var_name : Factory::empty_symbol();
+ Handle<String> name =
+ is_named ? var_name : isolate()->factory()->empty_symbol();
// The function name, if any.
- Handle<String> function_name = Factory::empty_symbol();
+ Handle<String> function_name = isolate()->factory()->empty_symbol();
if (is_named && (type == EXPRESSION || type == NESTED)) {
function_name = name;
}
@@ -3521,9 +3522,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
// Parse function body.
{ Scope* scope =
NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
- LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
- scope);
- TemporaryScope temp_scope(&this->temp_scope_);
+ LexicalScope lexical_scope(this, scope, isolate());
top_scope_->SetScopeName(name);
// FormalParameterList ::
@@ -3609,29 +3608,30 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
// End position greater than end of stream is safe, and hard to check.
ReportInvalidPreparseData(name, CHECK_OK);
}
- Counters::total_preparse_skipped.Increment(end_pos - function_block_pos);
+ isolate()->counters()->total_preparse_skipped()->Increment(
+ end_pos - function_block_pos);
// Seek to position just before terminal '}'.
scanner().SeekForward(end_pos - 1);
materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count();
only_simple_this_property_assignments = false;
- this_property_assignments = Factory::empty_fixed_array();
+ this_property_assignments = isolate()->factory()->empty_fixed_array();
Expect(Token::RBRACE, CHECK_OK);
} else {
ParseSourceElements(body, Token::RBRACE, CHECK_OK);
- materialized_literal_count = temp_scope.materialized_literal_count();
- expected_property_count = temp_scope.expected_property_count();
+ materialized_literal_count = lexical_scope.materialized_literal_count();
+ expected_property_count = lexical_scope.expected_property_count();
only_simple_this_property_assignments =
- temp_scope.only_simple_this_property_assignments();
- this_property_assignments = temp_scope.this_property_assignments();
+ lexical_scope.only_simple_this_property_assignments();
+ this_property_assignments = lexical_scope.this_property_assignments();
Expect(Token::RBRACE, CHECK_OK);
end_pos = scanner().location().end_pos;
}
// Validate strict mode.
- if (temp_scope_->StrictMode()) {
+ if (top_scope_->is_strict_mode()) {
if (IsEvalOrArguments(name)) {
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
@@ -3685,8 +3685,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
start_pos,
end_pos,
function_name->length() > 0,
- temp_scope.ContainsLoops(),
- temp_scope.StrictMode());
+ lexical_scope.ContainsLoops());
function_literal->set_function_token_position(function_token_position);
if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
@@ -3709,7 +3708,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
top_scope_->ForceEagerCompilation();
}
- Runtime::Function* function = Runtime::FunctionForSymbol(name);
+ const Runtime::Function* function = Runtime::FunctionForSymbol(name);
// Check for built-in IS_VAR macro.
if (function != NULL &&
@@ -3792,12 +3791,12 @@ void Parser::ExpectSemicolon(bool* ok) {
Literal* Parser::GetLiteralUndefined() {
- return new Literal(Factory::undefined_value());
+ return new Literal(isolate()->factory()->undefined_value());
}
Literal* Parser::GetLiteralTheHole() {
- return new Literal(Factory::the_hole_value());
+ return new Literal(isolate()->factory()->the_hole_value());
}
@@ -3815,7 +3814,7 @@ Handle<String> Parser::ParseIdentifier(bool* ok) {
Handle<String> Parser::ParseIdentifierOrReservedWord(bool* is_reserved,
bool* ok) {
*is_reserved = false;
- if (temp_scope_->StrictMode()) {
+ if (top_scope_->is_strict_mode()) {
Expect(Token::IDENTIFIER, ok);
} else {
if (!Check(Token::IDENTIFIER)) {
@@ -3846,7 +3845,7 @@ Handle<String> Parser::ParseIdentifierName(bool* ok) {
void Parser::CheckStrictModeLValue(Expression* expression,
const char* error,
bool* ok) {
- ASSERT(temp_scope_->StrictMode());
+ ASSERT(top_scope_->is_strict_mode());
VariableProxy* lhs = expression != NULL
? expression->AsVariableProxy()
: NULL;
@@ -3945,12 +3944,12 @@ void Parser::RegisterTargetUse(BreakTarget* target, Target* stop) {
Literal* Parser::NewNumberLiteral(double number) {
- return new Literal(Factory::NewNumber(number, TENURED));
+ return new Literal(isolate()->factory()->NewNumber(number, TENURED));
}
Expression* Parser::NewThrowReferenceError(Handle<String> type) {
- return NewThrowError(Factory::MakeReferenceError_symbol(),
+ return NewThrowError(isolate()->factory()->MakeReferenceError_symbol(),
type, HandleVector<Object>(NULL, 0));
}
@@ -3959,7 +3958,8 @@ Expression* Parser::NewThrowSyntaxError(Handle<String> type,
Handle<Object> first) {
int argc = first.is_null() ? 0 : 1;
Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
- return NewThrowError(Factory::MakeSyntaxError_symbol(), type, arguments);
+ return NewThrowError(
+ isolate()->factory()->MakeSyntaxError_symbol(), type, arguments);
}
@@ -3970,7 +3970,8 @@ Expression* Parser::NewThrowTypeError(Handle<String> type,
Handle<Object> elements[] = { first, second };
Vector< Handle<Object> > arguments =
HandleVector<Object>(elements, ARRAY_SIZE(elements));
- return NewThrowError(Factory::MakeTypeError_symbol(), type, arguments);
+ return NewThrowError(
+ isolate()->factory()->MakeTypeError_symbol(), type, arguments);
}
@@ -3978,14 +3979,16 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
Handle<String> type,
Vector< Handle<Object> > arguments) {
int argc = arguments.length();
- Handle<FixedArray> elements = Factory::NewFixedArray(argc, TENURED);
+ Handle<FixedArray> elements = isolate()->factory()->NewFixedArray(argc,
+ TENURED);
for (int i = 0; i < argc; i++) {
Handle<Object> element = arguments[i];
if (!element.is_null()) {
elements->set(i, *element);
}
}
- Handle<JSArray> array = Factory::NewJSArrayWithElements(elements, TENURED);
+ Handle<JSArray> array = isolate()->factory()->NewJSArrayWithElements(elements,
+ TENURED);
ZoneList<Expression*>* args = new ZoneList<Expression*>(2);
args->Add(new Literal(type));
@@ -4005,7 +4008,7 @@ Handle<Object> JsonParser::ParseJson(Handle<String> script,
if (result.is_null() || scanner_.Next() != Token::EOS) {
if (stack_overflow_) {
// Scanner failed.
- Top::StackOverflow();
+ isolate()->StackOverflow();
} else {
// Parse failed. Scanner's current token is the unexpected token.
Token::Value token = scanner_.current_token();
@@ -4035,20 +4038,21 @@ Handle<Object> JsonParser::ParseJson(Handle<String> script,
}
Scanner::Location source_location = scanner_.location();
- MessageLocation location(Factory::NewScript(script),
+ Factory* factory = isolate()->factory();
+ MessageLocation location(factory->NewScript(script),
source_location.beg_pos,
source_location.end_pos);
Handle<JSArray> array;
if (name_opt == NULL) {
- array = Factory::NewJSArray(0);
+ array = factory->NewJSArray(0);
} else {
- Handle<String> name = Factory::NewStringFromUtf8(CStrVector(name_opt));
- Handle<FixedArray> element = Factory::NewFixedArray(1);
+ Handle<String> name = factory->NewStringFromUtf8(CStrVector(name_opt));
+ Handle<FixedArray> element = factory->NewFixedArray(1);
element->set(0, *name);
- array = Factory::NewJSArrayWithElements(element);
+ array = factory->NewJSArrayWithElements(element);
}
- Handle<Object> result = Factory::NewSyntaxError(message, array);
- Top::Throw(*result, &location);
+ Handle<Object> result = factory->NewSyntaxError(message, array);
+ isolate()->Throw(*result, &location);
return Handle<Object>::null();
}
}
@@ -4059,12 +4063,14 @@ Handle<Object> JsonParser::ParseJson(Handle<String> script,
Handle<String> JsonParser::GetString() {
int literal_length = scanner_.literal_length();
if (literal_length == 0) {
- return Factory::empty_string();
+ return isolate()->factory()->empty_string();
}
if (scanner_.is_literal_ascii()) {
- return Factory::NewStringFromAscii(scanner_.literal_ascii_string());
+ return isolate()->factory()->NewStringFromAscii(
+ scanner_.literal_ascii_string());
} else {
- return Factory::NewStringFromTwoByte(scanner_.literal_uc16_string());
+ return isolate()->factory()->NewStringFromTwoByte(
+ scanner_.literal_uc16_string());
}
}
@@ -4076,13 +4082,13 @@ Handle<Object> JsonParser::ParseJsonValue() {
case Token::STRING:
return GetString();
case Token::NUMBER:
- return Factory::NewNumber(scanner_.number());
+ return isolate()->factory()->NewNumber(scanner_.number());
case Token::FALSE_LITERAL:
- return Factory::false_value();
+ return isolate()->factory()->false_value();
case Token::TRUE_LITERAL:
- return Factory::true_value();
+ return isolate()->factory()->true_value();
case Token::NULL_LITERAL:
- return Factory::null_value();
+ return isolate()->factory()->null_value();
case Token::LBRACE:
return ParseJsonObject();
case Token::LBRACK:
@@ -4096,12 +4102,13 @@ Handle<Object> JsonParser::ParseJsonValue() {
// Parse a JSON object. Scanner must be right after '{' token.
Handle<Object> JsonParser::ParseJsonObject() {
Handle<JSFunction> object_constructor(
- Top::global_context()->object_function());
- Handle<JSObject> json_object = Factory::NewJSObject(object_constructor);
+ isolate()->global_context()->object_function());
+ Handle<JSObject> json_object =
+ isolate()->factory()->NewJSObject(object_constructor);
if (scanner_.peek() == Token::RBRACE) {
scanner_.Next();
} else {
- if (StackLimitCheck().HasOverflowed()) {
+ if (StackLimitCheck(isolate()).HasOverflowed()) {
stack_overflow_ = true;
return Handle<Object>::null();
}
@@ -4118,7 +4125,7 @@ Handle<Object> JsonParser::ParseJsonObject() {
uint32_t index;
if (key->AsArrayIndex(&index)) {
SetOwnElement(json_object, index, value, kNonStrictMode);
- } else if (key->Equals(Heap::Proto_symbol())) {
+ } else if (key->Equals(isolate()->heap()->Proto_symbol())) {
// We can't remove the __proto__ accessor since it's hardcoded
// in several places. Instead go along and add the value as
// the prototype of the created object if possible.
@@ -4144,7 +4151,7 @@ Handle<Object> JsonParser::ParseJsonArray() {
if (token == Token::RBRACK) {
scanner_.Next();
} else {
- if (StackLimitCheck().HasOverflowed()) {
+ if (StackLimitCheck(isolate()).HasOverflowed()) {
stack_overflow_ = true;
return Handle<Object>::null();
}
@@ -4161,13 +4168,13 @@ Handle<Object> JsonParser::ParseJsonArray() {
// Allocate a fixed array with all the elements.
Handle<FixedArray> fast_elements =
- Factory::NewFixedArray(elements.length());
+ isolate()->factory()->NewFixedArray(elements.length());
for (int i = 0, n = elements.length(); i < n; i++) {
fast_elements->set(i, *elements[i]);
}
- return Factory::NewJSArrayWithElements(fast_elements);
+ return isolate()->factory()->NewJSArrayWithElements(fast_elements);
}
// ----------------------------------------------------------------------------
@@ -4177,18 +4184,19 @@ Handle<Object> JsonParser::ParseJsonArray() {
RegExpParser::RegExpParser(FlatStringReader* in,
Handle<String>* error,
bool multiline)
- : error_(error),
- captures_(NULL),
- in_(in),
- current_(kEndMarker),
- next_pos_(0),
- capture_count_(0),
- has_more_(true),
- multiline_(multiline),
- simple_(false),
- contains_anchor_(false),
- is_scanned_for_captures_(false),
- failed_(false) {
+ : isolate_(Isolate::Current()),
+ error_(error),
+ captures_(NULL),
+ in_(in),
+ current_(kEndMarker),
+ next_pos_(0),
+ capture_count_(0),
+ has_more_(true),
+ multiline_(multiline),
+ simple_(false),
+ contains_anchor_(false),
+ is_scanned_for_captures_(false),
+ failed_(false) {
Advance();
}
@@ -4204,10 +4212,10 @@ uc32 RegExpParser::Next() {
void RegExpParser::Advance() {
if (next_pos_ < in()->length()) {
- StackLimitCheck check;
+ StackLimitCheck check(isolate());
if (check.HasOverflowed()) {
- ReportError(CStrVector(Top::kStackOverflowMessage));
- } else if (Zone::excess_allocation()) {
+ ReportError(CStrVector(Isolate::kStackOverflowMessage));
+ } else if (isolate()->zone()->excess_allocation()) {
ReportError(CStrVector("Regular expression too large"));
} else {
current_ = in()->Get(next_pos_);
@@ -4238,7 +4246,7 @@ bool RegExpParser::simple() {
RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
failed_ = true;
- *error_ = Factory::NewStringFromAscii(message, NOT_TENURED);
+ *error_ = isolate()->factory()->NewStringFromAscii(message, NOT_TENURED);
// Zip to the end to make sure the no more input is read.
current_ = kEndMarker;
next_pos_ = in()->length();
@@ -4592,30 +4600,6 @@ RegExpTree* RegExpParser::ParseDisjunction() {
}
}
-class SourceCharacter {
- public:
- static bool Is(uc32 c) {
- switch (c) {
- // case ']': case '}':
- // In spidermonkey and jsc these are treated as source characters
- // so we do too.
- case '^': case '$': case '\\': case '.': case '*': case '+':
- case '?': case '(': case ')': case '[': case '{': case '|':
- case RegExpParser::kEndMarker:
- return false;
- default:
- return true;
- }
- }
-};
-
-
-static unibrow::Predicate<SourceCharacter> source_character;
-
-
-static inline bool IsSourceCharacter(uc32 c) {
- return source_character.get(c);
-}
#ifdef DEBUG
// Currently only used in an ASSERT.
@@ -5068,14 +5052,15 @@ int ScriptDataImpl::ReadNumber(byte** source) {
static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
bool allow_lazy,
ParserRecorder* recorder) {
- V8JavaScriptScanner scanner;
+ Isolate* isolate = Isolate::Current();
+ V8JavaScriptScanner scanner(isolate->scanner_constants());
scanner.Initialize(source);
- intptr_t stack_limit = StackGuard::real_climit();
+ intptr_t stack_limit = isolate->stack_guard()->real_climit();
if (!preparser::PreParser::PreParseProgram(&scanner,
recorder,
allow_lazy,
stack_limit)) {
- Top::StackOverflow();
+ isolate->StackOverflow();
return NULL;
}
@@ -5138,10 +5123,10 @@ bool ParserApi::Parse(CompilationInfo* info) {
Handle<Script> script = info->script();
if (info->is_lazy()) {
Parser parser(script, true, NULL, NULL);
- result = parser.ParseLazy(info->shared_info());
+ result = parser.ParseLazy(info);
} else {
bool allow_natives_syntax =
- FLAG_allow_natives_syntax || Bootstrapper::IsActive();
+ info->allows_natives_syntax() || FLAG_allow_natives_syntax;
ScriptDataImpl* pre_data = info->pre_parse_data();
Parser parser(script, allow_natives_syntax, info->extension(), pre_data);
if (pre_data != NULL && pre_data->has_error()) {
@@ -5154,7 +5139,7 @@ bool ParserApi::Parse(CompilationInfo* info) {
DeleteArray(args[i]);
}
DeleteArray(args.start());
- ASSERT(Top::has_pending_exception());
+ ASSERT(info->isolate()->has_pending_exception());
} else {
Handle<String> source = Handle<String>(String::cast(script->source()));
result = parser.ParseProgram(source,
diff --git a/src/parser.h b/src/parser.h
index dfd909a0..74cb0493 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -42,7 +42,7 @@ class FuncNameInferrer;
class ParserLog;
class PositionStack;
class Target;
-class TemporaryScope;
+class LexicalScope;
template <typename T> class ZoneListWrapper;
@@ -388,6 +388,8 @@ class RegExpParser {
int disjunction_capture_index_;
};
+ Isolate* isolate() { return isolate_; }
+
uc32 current() { return current_; }
bool has_more() { return has_more_; }
bool has_next() { return next_pos_ < in()->length(); }
@@ -395,6 +397,7 @@ class RegExpParser {
FlatStringReader* in() { return in_; }
void ScanForCaptures();
+ Isolate* isolate_;
Handle<String>* error_;
ZoneList<RegExpCapture*>* captures_;
FlatStringReader* in_;
@@ -426,7 +429,7 @@ class Parser {
bool in_global_context,
StrictModeFlag strict_mode);
- FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info);
+ FunctionLiteral* ParseLazy(CompilationInfo* info);
void ReportMessageAt(Scanner::Location loc,
const char* message,
@@ -441,7 +444,7 @@ class Parser {
// construct a hashable id, so if more than 2^17 are allowed, this
// should be checked.
static const int kMaxNumFunctionParameters = 32766;
- FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info,
+ FunctionLiteral* ParseLazy(CompilationInfo* info,
UC16CharacterStream* source,
ZoneScope* zone_scope);
enum Mode {
@@ -449,6 +452,8 @@ class Parser {
PARSE_EAGERLY
};
+ Isolate* isolate() { return isolate_; }
+
// Called by ParseProgram after setting up the scanner.
FunctionLiteral* DoParseProgram(Handle<String> source,
bool in_global_context,
@@ -465,6 +470,9 @@ class Parser {
Mode mode() const { return mode_; }
ScriptDataImpl* pre_data() const { return pre_data_; }
+ // Check if the given string is 'eval' or 'arguments'.
+ bool IsEvalOrArguments(Handle<String> string);
+
// All ParseXXX functions take as the last argument an *ok parameter
// which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check
@@ -574,7 +582,7 @@ class Parser {
if (stack_overflow_) {
return Token::ILLEGAL;
}
- if (StackLimitCheck().HasOverflowed()) {
+ if (StackLimitCheck(isolate()).HasOverflowed()) {
// Any further calls to Next or peek will return the illegal token.
// The current call must return the next token, which might already
// have been peek'ed.
@@ -592,21 +600,21 @@ class Parser {
Handle<String> LiteralString(PretenureFlag tenured) {
if (scanner().is_literal_ascii()) {
- return Factory::NewStringFromAscii(scanner().literal_ascii_string(),
- tenured);
+ return isolate_->factory()->NewStringFromAscii(
+ scanner().literal_ascii_string(), tenured);
} else {
- return Factory::NewStringFromTwoByte(scanner().literal_uc16_string(),
- tenured);
+ return isolate_->factory()->NewStringFromTwoByte(
+ scanner().literal_uc16_string(), tenured);
}
}
Handle<String> NextLiteralString(PretenureFlag tenured) {
if (scanner().is_next_literal_ascii()) {
- return Factory::NewStringFromAscii(scanner().next_literal_ascii_string(),
- tenured);
+ return isolate_->factory()->NewStringFromAscii(
+ scanner().next_literal_ascii_string(), tenured);
} else {
- return Factory::NewStringFromTwoByte(scanner().next_literal_uc16_string(),
- tenured);
+ return isolate_->factory()->NewStringFromTwoByte(
+ scanner().next_literal_uc16_string(), tenured);
}
}
@@ -686,6 +694,7 @@ class Parser {
Handle<String> type,
Vector< Handle<Object> > arguments);
+ Isolate* isolate_;
ZoneList<Handle<String> > symbol_cache_;
Handle<Script> script_;
@@ -694,7 +703,7 @@ class Parser {
Scope* top_scope_;
int with_nesting_level_;
- TemporaryScope* temp_scope_;
+ LexicalScope* lexical_scope_;
Mode mode_;
Target* target_stack_; // for break, continue statements
@@ -709,6 +718,8 @@ class Parser {
// Heuristically that means that the function will be called immediately,
// so never lazily compile it.
bool parenthesized_function_;
+
+ friend class LexicalScope;
};
@@ -765,9 +776,13 @@ class JsonParser BASE_EMBEDDED {
}
private:
- JsonParser() { }
+ JsonParser()
+ : isolate_(Isolate::Current()),
+ scanner_(isolate_->scanner_constants()) { }
~JsonParser() { }
+ Isolate* isolate() { return isolate_; }
+
// Parse a string containing a single JSON value.
Handle<Object> ParseJson(Handle<String> script, UC16CharacterStream* source);
// Parse a single JSON value from input (grammar production JSONValue).
@@ -794,6 +809,7 @@ class JsonParser BASE_EMBEDDED {
// Converts the currently parsed literal to a JavaScript String.
Handle<String> GetString();
+ Isolate* isolate_;
JsonScanner scanner_;
bool stack_overflow_;
};
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index a7cc5256..4b450c18 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -143,7 +143,7 @@ void* OS::Allocate(const size_t requested,
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mbase == MAP_FAILED) {
- LOG(StringEvent("OS::Allocate", "mmap failed"));
+ LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
@@ -400,12 +400,18 @@ bool ThreadHandle::IsValid() const {
}
-Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
- set_name("v8:<unknown>");
+Thread::Thread(Isolate* isolate, const Options& options)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(options.stack_size) {
+ set_name(options.name);
}
-Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(Isolate* isolate, const char* name)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(0) {
set_name(name);
}
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 21763b5d..2a73b6e9 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -42,6 +42,7 @@
#include <sys/stat.h> // open
#include <sys/fcntl.h> // open
#include <unistd.h> // getpagesize
+// If you don't have execinfo.h then you need devel/libexecinfo from ports.
#include <execinfo.h> // backtrace, backtrace_symbols
#include <strings.h> // index
#include <errno.h>
@@ -74,6 +75,9 @@ double ceiling(double x) {
}
+static Mutex* limit_mutex = NULL;
+
+
void OS::Setup() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
@@ -82,6 +86,7 @@ void OS::Setup() {
// call this setup code within the same millisecond.
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed));
+ limit_mutex = CreateMutex();
}
@@ -130,6 +135,9 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
static void UpdateAllocatedSpaceLimits(void* address, int size) {
+ ASSERT(limit_mutex != NULL);
+ ScopedLock lock(limit_mutex);
+
lowest_ever_allocated = Min(lowest_ever_allocated, address);
highest_ever_allocated =
Max(highest_ever_allocated,
@@ -155,7 +163,7 @@ void* OS::Allocate(const size_t requested,
void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
if (mbase == MAP_FAILED) {
- LOG(StringEvent("OS::Allocate", "mmap failed"));
+ LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
@@ -299,7 +307,7 @@ void OS::LogSharedLibraryAddresses() {
// There may be no filename in this line. Skip to next.
if (start_of_path == NULL) continue;
buffer[bytes_read] = 0;
- LOG(SharedLibraryEvent(start_of_path, start, end));
+ LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end));
}
close(fd);
#endif
@@ -424,12 +432,18 @@ bool ThreadHandle::IsValid() const {
}
-Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
- set_name("v8:<unknown>");
+Thread::Thread(Isolate* isolate, const Options& options)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(options.stack_size) {
+ set_name(options.name);
}
-Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(Isolate* isolate, const char* name)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(0) {
set_name(name);
}
@@ -445,6 +459,7 @@ static void* ThreadEntry(void* arg) {
// one) so we initialize it here too.
thread->thread_handle_data()->thread_ = pthread_self();
ASSERT(thread->IsValid());
+ Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
thread->Run();
return NULL;
}
@@ -457,7 +472,14 @@ void Thread::set_name(const char* name) {
void Thread::Start() {
- pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
+ pthread_attr_t* attr_ptr = NULL;
+ pthread_attr_t attr;
+ if (stack_size_ > 0) {
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
+ attr_ptr = &attr;
+ }
+ pthread_create(&thread_handle_data()->thread_, attr_ptr, ThreadEntry, this);
ASSERT(IsValid());
}
@@ -526,6 +548,16 @@ class FreeBSDMutex : public Mutex {
return result;
}
+ virtual bool TryLock() {
+ int result = pthread_mutex_trylock(&mutex_);
+ // Return false if the lock is busy and locking failed.
+ if (result == EBUSY) {
+ return false;
+ }
+ ASSERT(result == 0); // Verify no other errors.
+ return true;
+ }
+
private:
pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
};
@@ -594,107 +626,227 @@ Semaphore* OS::CreateSemaphore(int count) {
#ifdef ENABLE_LOGGING_AND_PROFILING
-static Sampler* active_sampler_ = NULL;
+static pthread_t GetThreadID() {
+ pthread_t thread_id = pthread_self();
+ return thread_id;
+}
+
+
+class Sampler::PlatformData : public Malloced {
+ public:
+ PlatformData() : vm_tid_(GetThreadID()) {}
+
+ pthread_t vm_tid() const { return vm_tid_; }
+
+ private:
+ pthread_t vm_tid_;
+};
+
static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
USE(info);
if (signal != SIGPROF) return;
- if (active_sampler_ == NULL) return;
-
- TickSample sample;
+ Isolate* isolate = Isolate::UncheckedCurrent();
+ if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
+ // We require a fully initialized and entered isolate.
+ return;
+ }
+ Sampler* sampler = isolate->logger()->sampler();
+ if (sampler == NULL || !sampler->IsActive()) return;
- // We always sample the VM state.
- sample.state = VMState::current_state();
+ TickSample sample_obj;
+ TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
+ if (sample == NULL) sample = &sample_obj;
- // If profiling, we extract the current pc and sp.
- if (active_sampler_->IsProfiling()) {
- // Extracting the sample from the context is extremely machine dependent.
- ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
- mcontext_t& mcontext = ucontext->uc_mcontext;
+ // Extracting the sample from the context is extremely machine dependent.
+ ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+ mcontext_t& mcontext = ucontext->uc_mcontext;
+ sample->state = isolate->current_vm_state();
#if V8_HOST_ARCH_IA32
- sample.pc = reinterpret_cast<Address>(mcontext.mc_eip);
- sample.sp = reinterpret_cast<Address>(mcontext.mc_esp);
- sample.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
+ sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
+ sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
+ sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
#elif V8_HOST_ARCH_X64
- sample.pc = reinterpret_cast<Address>(mcontext.mc_rip);
- sample.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
- sample.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
+ sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
+ sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
+ sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
#elif V8_HOST_ARCH_ARM
- sample.pc = reinterpret_cast<Address>(mcontext.mc_r15);
- sample.sp = reinterpret_cast<Address>(mcontext.mc_r13);
- sample.fp = reinterpret_cast<Address>(mcontext.mc_r11);
+ sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
+ sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
+ sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
#endif
- active_sampler_->SampleStack(&sample);
- }
-
- active_sampler_->Tick(&sample);
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
}
-class Sampler::PlatformData : public Malloced {
+class SignalSender : public Thread {
public:
- PlatformData() {
- signal_handler_installed_ = false;
+ enum SleepInterval {
+ HALF_INTERVAL,
+ FULL_INTERVAL
+ };
+
+ explicit SignalSender(int interval)
+ : Thread(NULL, "SignalSender"),
+ interval_(interval) {}
+
+ static void AddActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::AddActiveSampler(sampler);
+ if (instance_ == NULL) {
+ // Install a signal handler.
+ struct sigaction sa;
+ sa.sa_sigaction = ProfilerSignalHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ signal_handler_installed_ =
+ (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
+
+ // Start a thread that sends SIGPROF signal to VM threads.
+ instance_ = new SignalSender(sampler->interval());
+ instance_->Start();
+ } else {
+ ASSERT(instance_->interval_ == sampler->interval());
+ }
}
- bool signal_handler_installed_;
- struct sigaction old_signal_handler_;
- struct itimerval old_timer_value_;
+ static void RemoveActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::RemoveActiveSampler(sampler);
+ if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
+ RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown();
+ instance_->Join();
+ delete instance_;
+ instance_ = NULL;
+
+ // Restore the old signal handler.
+ if (signal_handler_installed_) {
+ sigaction(SIGPROF, &old_signal_handler_, 0);
+ signal_handler_installed_ = false;
+ }
+ }
+ }
+
+ // Implement Thread::Run().
+ virtual void Run() {
+ SamplerRegistry::State state;
+ while ((state = SamplerRegistry::GetState()) !=
+ SamplerRegistry::HAS_NO_SAMPLERS) {
+ bool cpu_profiling_enabled =
+ (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
+ bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
+ // When CPU profiling is enabled both JavaScript and C++ code is
+ // profiled. We must not suspend.
+ if (!cpu_profiling_enabled) {
+ if (rate_limiter_.SuspendIfNecessary()) continue;
+ }
+ if (cpu_profiling_enabled && runtime_profiler_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
+ return;
+ }
+ Sleep(HALF_INTERVAL);
+ if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
+ return;
+ }
+ Sleep(HALF_INTERVAL);
+ } else {
+ if (cpu_profiling_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
+ this)) {
+ return;
+ }
+ }
+ if (runtime_profiler_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
+ NULL)) {
+ return;
+ }
+ }
+ Sleep(FULL_INTERVAL);
+ }
+ }
+ }
+
+ static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
+ if (!sampler->IsProfiling()) return;
+ SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
+ sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
+ }
+
+ static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
+ if (!sampler->isolate()->IsInitialized()) return;
+ sampler->isolate()->runtime_profiler()->NotifyTick();
+ }
+
+ void SendProfilingSignal(pthread_t tid) {
+ if (!signal_handler_installed_) return;
+ pthread_kill(tid, SIGPROF);
+ }
+
+ void Sleep(SleepInterval full_or_half) {
+ // Convert ms to us and subtract 100 us to compensate delays
+ // occuring during signal delivery.
+ useconds_t interval = interval_ * 1000 - 100;
+ if (full_or_half == HALF_INTERVAL) interval /= 2;
+ int result = usleep(interval);
+#ifdef DEBUG
+ if (result != 0 && errno != EINTR) {
+ fprintf(stderr,
+ "SignalSender usleep error; interval = %u, errno = %d\n",
+ interval,
+ errno);
+ ASSERT(result == 0 || errno == EINTR);
+ }
+#endif
+ USE(result);
+ }
+
+ const int interval_;
+ RuntimeProfilerRateLimiter rate_limiter_;
+
+ // Protects the process wide state below.
+ static Mutex* mutex_;
+ static SignalSender* instance_;
+ static bool signal_handler_installed_;
+ static struct sigaction old_signal_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(SignalSender);
};
+Mutex* SignalSender::mutex_ = OS::CreateMutex();
+SignalSender* SignalSender::instance_ = NULL;
+struct sigaction SignalSender::old_signal_handler_;
+bool SignalSender::signal_handler_installed_ = false;
-Sampler::Sampler(int interval)
- : interval_(interval),
+
+Sampler::Sampler(Isolate* isolate, int interval)
+ : isolate_(isolate),
+ interval_(interval),
profiling_(false),
active_(false),
samples_taken_(0) {
- data_ = new PlatformData();
+ data_ = new PlatformData;
}
Sampler::~Sampler() {
+ ASSERT(!IsActive());
delete data_;
}
void Sampler::Start() {
- // There can only be one active sampler at the time on POSIX
- // platforms.
- if (active_sampler_ != NULL) return;
-
- // Request profiling signals.
- struct sigaction sa;
- sa.sa_sigaction = ProfilerSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_SIGINFO;
- if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
- data_->signal_handler_installed_ = true;
-
- // Set the itimer to generate a tick for each interval.
- itimerval itimer;
- itimer.it_interval.tv_sec = interval_ / 1000;
- itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
- itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
- itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
- setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
-
- // Set this sampler as the active sampler.
- active_sampler_ = this;
- active_ = true;
+ ASSERT(!IsActive());
+ SetActive(true);
+ SignalSender::AddActiveSampler(this);
}
void Sampler::Stop() {
- // Restore old signal handler
- if (data_->signal_handler_installed_) {
- setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
- sigaction(SIGPROF, &data_->old_signal_handler_, 0);
- data_->signal_handler_installed_ = false;
- }
-
- // This sampler is no longer the active sampler.
- active_sampler_ = NULL;
- active_ = false;
+ ASSERT(IsActive());
+ SignalSender::RemoveActiveSampler(this);
+ SetActive(false);
}
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 16aa7c81..73a6ccbd 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -58,7 +58,6 @@
#include "v8.h"
#include "platform.h"
-#include "top.h"
#include "v8threads.h"
#include "vm-state-inl.h"
@@ -76,6 +75,9 @@ double ceiling(double x) {
}
+static Mutex* limit_mutex = NULL;
+
+
void OS::Setup() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
@@ -84,6 +86,7 @@ void OS::Setup() {
// call this setup code within the same millisecond.
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed));
+ limit_mutex = CreateMutex();
}
@@ -94,6 +97,10 @@ uint64_t OS::CpuFeaturesImpliedByPlatform() {
return 1u << VFP3;
#elif CAN_USE_ARMV7_INSTRUCTIONS
return 1u << ARMv7;
+#elif(defined(__mips_hard_float) && __mips_hard_float != 0)
+ // Here gcc is telling us that we are on an MIPS and gcc is assuming that we
+ // have FPU instructions. If gcc can assume it then so can we.
+ return 1u << FPU;
#else
return 0; // Linux runs on anything.
#endif
@@ -172,6 +179,58 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) {
#endif // def __arm__
+#ifdef __mips__
+bool OS::MipsCpuHasFeature(CpuFeature feature) {
+ const char* search_string = NULL;
+ const char* file_name = "/proc/cpuinfo";
+ // Simple detection of FPU at runtime for Linux.
+ // It is based on /proc/cpuinfo, which reveals hardware configuration
+ // to user-space applications. According to MIPS (early 2010), no similar
+ // facility is universally available on the MIPS architectures,
+ // so it's up to individual OSes to provide such.
+ //
+ // This is written as a straight shot one pass parser
+ // and not using STL string and ifstream because,
+ // on Linux, it's reading from a (non-mmap-able)
+ // character special device.
+
+ switch (feature) {
+ case FPU:
+ search_string = "FPU";
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ FILE* f = NULL;
+ const char* what = search_string;
+
+ if (NULL == (f = fopen(file_name, "r")))
+ return false;
+
+ int k;
+ while (EOF != (k = fgetc(f))) {
+ if (k == *what) {
+ ++what;
+ while ((*what != '\0') && (*what == fgetc(f))) {
+ ++what;
+ }
+ if (*what == '\0') {
+ fclose(f);
+ return true;
+ } else {
+ what = search_string;
+ }
+ }
+ }
+ fclose(f);
+
+ // Did not find string in the proc file.
+ return false;
+}
+#endif // def __mips__
+
+
int OS::ActivationFrameAlignment() {
#ifdef V8_TARGET_ARCH_ARM
// On EABI ARM targets this is required for fp correctness in the
@@ -187,8 +246,9 @@ int OS::ActivationFrameAlignment() {
void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
-#if defined(V8_TARGET_ARCH_ARM) && defined(__arm__)
- // Only use on ARM hardware.
+#if (defined(V8_TARGET_ARCH_ARM) && defined(__arm__)) || \
+ (defined(V8_TARGET_ARCH_MIPS) && defined(__mips__))
+ // Only use on ARM or MIPS hardware.
MemoryBarrier();
#else
__asm__ __volatile__("" : : : "memory");
@@ -226,6 +286,9 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
static void UpdateAllocatedSpaceLimits(void* address, int size) {
+ ASSERT(limit_mutex != NULL);
+ ScopedLock lock(limit_mutex);
+
lowest_ever_allocated = Min(lowest_ever_allocated, address);
highest_ever_allocated =
Max(highest_ever_allocated,
@@ -251,7 +314,8 @@ void* OS::Allocate(const size_t requested,
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mbase == MAP_FAILED) {
- LOG(StringEvent("OS::Allocate", "mmap failed"));
+ LOG(i::Isolate::Current(),
+ StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
@@ -372,6 +436,7 @@ void OS::LogSharedLibraryAddresses() {
const int kLibNameLen = FILENAME_MAX + 1;
char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
+ i::Isolate* isolate = ISOLATE;
// This loop will terminate once the scanning hits an EOF.
while (true) {
uintptr_t start, end;
@@ -405,7 +470,7 @@ void OS::LogSharedLibraryAddresses() {
snprintf(lib_name, kLibNameLen,
"%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
}
- LOG(SharedLibraryEvent(lib_name, start, end));
+ LOG(isolate, SharedLibraryEvent(lib_name, start, end));
} else {
// Entry not describing executable data. Skip to end of line to setup
// reading the next entry.
@@ -565,12 +630,18 @@ bool ThreadHandle::IsValid() const {
}
-Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
- set_name("v8:<unknown>");
+Thread::Thread(Isolate* isolate, const Options& options)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(options.stack_size) {
+ set_name(options.name);
}
-Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(Isolate* isolate, const char* name)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(0) {
set_name(name);
}
@@ -589,6 +660,7 @@ static void* ThreadEntry(void* arg) {
0, 0, 0);
thread->thread_handle_data()->thread_ = pthread_self();
ASSERT(thread->IsValid());
+ Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
thread->Run();
return NULL;
}
@@ -601,7 +673,14 @@ void Thread::set_name(const char* name) {
void Thread::Start() {
- pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
+ pthread_attr_t* attr_ptr = NULL;
+ pthread_attr_t attr;
+ if (stack_size_ > 0) {
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
+ attr_ptr = &attr;
+ }
+ pthread_create(&thread_handle_data()->thread_, attr_ptr, ThreadEntry, this);
ASSERT(IsValid());
}
@@ -762,10 +841,6 @@ Semaphore* OS::CreateSemaphore(int count) {
#ifdef ENABLE_LOGGING_AND_PROFILING
-static Sampler* active_sampler_ = NULL;
-static int vm_tid_ = 0;
-
-
#if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
// Android runs a fairly new Linux kernel, so signal info is there,
// but the C library doesn't have the structs defined.
@@ -794,7 +869,11 @@ enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11};
static int GetThreadID() {
// Glibc doesn't provide a wrapper for gettid(2).
+#if defined(ANDROID)
+ return syscall(__NR_gettid);
+#else
return syscall(SYS_gettid);
+#endif
}
@@ -802,17 +881,22 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
#ifndef V8_HOST_ARCH_MIPS
USE(info);
if (signal != SIGPROF) return;
- if (active_sampler_ == NULL || !active_sampler_->IsActive()) return;
- if (vm_tid_ != GetThreadID()) return;
+ Isolate* isolate = Isolate::UncheckedCurrent();
+ if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
+ // We require a fully initialized and entered isolate.
+ return;
+ }
+ Sampler* sampler = isolate->logger()->sampler();
+ if (sampler == NULL || !sampler->IsActive()) return;
TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent();
+ TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
if (sample == NULL) sample = &sample_obj;
// Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
mcontext_t& mcontext = ucontext->uc_mcontext;
- sample->state = Top::current_vm_state();
+ sample->state = isolate->current_vm_state();
#if V8_HOST_ARCH_IA32
sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
@@ -833,55 +917,141 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
#endif
#elif V8_HOST_ARCH_MIPS
- // Implement this on MIPS.
- UNIMPLEMENTED();
+ sample.pc = reinterpret_cast<Address>(mcontext.pc);
+ sample.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
+ sample.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
#endif
- active_sampler_->SampleStack(sample);
- active_sampler_->Tick(sample);
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
#endif
}
class Sampler::PlatformData : public Malloced {
public:
+ PlatformData() : vm_tid_(GetThreadID()) {}
+
+ int vm_tid() const { return vm_tid_; }
+
+ private:
+ const int vm_tid_;
+};
+
+
+class SignalSender : public Thread {
+ public:
enum SleepInterval {
- FULL_INTERVAL,
- HALF_INTERVAL
+ HALF_INTERVAL,
+ FULL_INTERVAL
};
- explicit PlatformData(Sampler* sampler)
- : sampler_(sampler),
- signal_handler_installed_(false),
+ explicit SignalSender(int interval)
+ : Thread(NULL, "SignalSender"),
vm_tgid_(getpid()),
- signal_sender_launched_(false) {
+ interval_(interval) {}
+
+ static void AddActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::AddActiveSampler(sampler);
+ if (instance_ == NULL) {
+ // Install a signal handler.
+ struct sigaction sa;
+ sa.sa_sigaction = ProfilerSignalHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ signal_handler_installed_ =
+ (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
+
+ // Start a thread that sends SIGPROF signal to VM threads.
+ instance_ = new SignalSender(sampler->interval());
+ instance_->Start();
+ } else {
+ ASSERT(instance_->interval_ == sampler->interval());
+ }
}
- void SignalSender() {
- while (sampler_->IsActive()) {
- if (rate_limiter_.SuspendIfNecessary()) continue;
- if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) {
- SendProfilingSignal();
+ static void RemoveActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::RemoveActiveSampler(sampler);
+ if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
+ RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown();
+ instance_->Join();
+ delete instance_;
+ instance_ = NULL;
+
+ // Restore the old signal handler.
+ if (signal_handler_installed_) {
+ sigaction(SIGPROF, &old_signal_handler_, 0);
+ signal_handler_installed_ = false;
+ }
+ }
+ }
+
+ // Implement Thread::Run().
+ virtual void Run() {
+ SamplerRegistry::State state;
+ while ((state = SamplerRegistry::GetState()) !=
+ SamplerRegistry::HAS_NO_SAMPLERS) {
+ bool cpu_profiling_enabled =
+ (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
+ bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
+ // When CPU profiling is enabled both JavaScript and C++ code is
+ // profiled. We must not suspend.
+ if (!cpu_profiling_enabled) {
+ if (rate_limiter_.SuspendIfNecessary()) continue;
+ }
+ if (cpu_profiling_enabled && runtime_profiler_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
+ return;
+ }
Sleep(HALF_INTERVAL);
- RuntimeProfiler::NotifyTick();
+ if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
+ return;
+ }
Sleep(HALF_INTERVAL);
} else {
- if (sampler_->IsProfiling()) SendProfilingSignal();
- if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick();
+ if (cpu_profiling_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
+ this)) {
+ return;
+ }
+ }
+ if (runtime_profiler_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
+ NULL)) {
+ return;
+ }
+ }
Sleep(FULL_INTERVAL);
}
}
}
- void SendProfilingSignal() {
+ static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
+ if (!sampler->IsProfiling()) return;
+ SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
+ sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
+ }
+
+ static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
+ if (!sampler->isolate()->IsInitialized()) return;
+ sampler->isolate()->runtime_profiler()->NotifyTick();
+ }
+
+ void SendProfilingSignal(int tid) {
if (!signal_handler_installed_) return;
// Glibc doesn't provide a wrapper for tgkill(2).
- syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF);
+#if defined(ANDROID)
+ syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
+#else
+ syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
+#endif
}
void Sleep(SleepInterval full_or_half) {
// Convert ms to us and subtract 100 us to compensate delays
// occuring during signal delivery.
- useconds_t interval = sampler_->interval_ * 1000 - 100;
+ useconds_t interval = interval_ * 1000 - 100;
if (full_or_half == HALF_INTERVAL) interval /= 2;
int result = usleep(interval);
#ifdef DEBUG
@@ -896,89 +1066,55 @@ class Sampler::PlatformData : public Malloced {
USE(result);
}
- Sampler* sampler_;
- bool signal_handler_installed_;
- struct sigaction old_signal_handler_;
- int vm_tgid_;
- bool signal_sender_launched_;
- pthread_t signal_sender_thread_;
+ const int vm_tgid_;
+ const int interval_;
RuntimeProfilerRateLimiter rate_limiter_;
+
+ // Protects the process wide state below.
+ static Mutex* mutex_;
+ static SignalSender* instance_;
+ static bool signal_handler_installed_;
+ static struct sigaction old_signal_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(SignalSender);
};
-static void* SenderEntry(void* arg) {
- Sampler::PlatformData* data =
- reinterpret_cast<Sampler::PlatformData*>(arg);
- data->SignalSender();
- return 0;
-}
+Mutex* SignalSender::mutex_ = OS::CreateMutex();
+SignalSender* SignalSender::instance_ = NULL;
+struct sigaction SignalSender::old_signal_handler_;
+bool SignalSender::signal_handler_installed_ = false;
-Sampler::Sampler(int interval)
- : interval_(interval),
+Sampler::Sampler(Isolate* isolate, int interval)
+ : isolate_(isolate),
+ interval_(interval),
profiling_(false),
active_(false),
samples_taken_(0) {
- data_ = new PlatformData(this);
+ data_ = new PlatformData;
}
Sampler::~Sampler() {
- ASSERT(!data_->signal_sender_launched_);
+ ASSERT(!IsActive());
delete data_;
}
void Sampler::Start() {
- // There can only be one active sampler at the time on POSIX
- // platforms.
ASSERT(!IsActive());
- vm_tid_ = GetThreadID();
-
- // Request profiling signals.
- struct sigaction sa;
- sa.sa_sigaction = ProfilerSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- data_->signal_handler_installed_ =
- sigaction(SIGPROF, &sa, &data_->old_signal_handler_) == 0;
-
- // Start a thread that sends SIGPROF signal to VM thread.
- // Sending the signal ourselves instead of relying on itimer provides
- // much better accuracy.
SetActive(true);
- if (pthread_create(
- &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
- data_->signal_sender_launched_ = true;
- }
-
- // Set this sampler as the active sampler.
- active_sampler_ = this;
+ SignalSender::AddActiveSampler(this);
}
void Sampler::Stop() {
+ ASSERT(IsActive());
+ SignalSender::RemoveActiveSampler(this);
SetActive(false);
-
- // Wait for signal sender termination (it will exit after setting
- // active_ to false).
- if (data_->signal_sender_launched_) {
- Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
- pthread_join(data_->signal_sender_thread_, NULL);
- data_->signal_sender_launched_ = false;
- }
-
- // Restore old signal handler
- if (data_->signal_handler_installed_) {
- sigaction(SIGPROF, &data_->old_signal_handler_, 0);
- data_->signal_handler_installed_ = false;
- }
-
- // This sampler is no longer the active sampler.
- active_sampler_ = NULL;
}
-
#endif // ENABLE_LOGGING_AND_PROFILING
} } // namespace v8::internal
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index 35724c35..17e30428 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -88,6 +88,9 @@ double ceiling(double x) {
}
+static Mutex* limit_mutex = NULL;
+
+
void OS::Setup() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
@@ -96,6 +99,7 @@ void OS::Setup() {
// call this setup code within the same millisecond.
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed));
+ limit_mutex = CreateMutex();
}
@@ -109,6 +113,9 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
static void UpdateAllocatedSpaceLimits(void* address, int size) {
+ ASSERT(limit_mutex != NULL);
+ ScopedLock lock(limit_mutex);
+
lowest_ever_allocated = Min(lowest_ever_allocated, address);
highest_ever_allocated =
Max(highest_ever_allocated,
@@ -143,7 +150,7 @@ void* OS::Allocate(const size_t requested,
MAP_PRIVATE | MAP_ANON,
kMmapFd, kMmapFdOffset);
if (mbase == MAP_FAILED) {
- LOG(StringEvent("OS::Allocate", "mmap failed"));
+ LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
@@ -258,7 +265,8 @@ void OS::LogSharedLibraryAddresses() {
if (code_ptr == NULL) continue;
const uintptr_t slide = _dyld_get_image_vmaddr_slide(i);
const uintptr_t start = reinterpret_cast<uintptr_t>(code_ptr) + slide;
- LOG(SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
+ LOG(Isolate::Current(),
+ SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
}
#endif // ENABLE_LOGGING_AND_PROFILING
}
@@ -424,12 +432,18 @@ bool ThreadHandle::IsValid() const {
}
-Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
- set_name("v8:<unknown>");
+Thread::Thread(Isolate* isolate, const Options& options)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(options.stack_size) {
+ set_name(options.name);
}
-Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(Isolate* isolate, const char* name)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(0) {
set_name(name);
}
@@ -438,7 +452,6 @@ Thread::~Thread() {
}
-
static void SetThreadName(const char* name) {
// pthread_setname_np is only available in 10.6 or later, so test
// for it at runtime.
@@ -464,6 +477,7 @@ static void* ThreadEntry(void* arg) {
thread->thread_handle_data()->thread_ = pthread_self();
SetThreadName(thread->name());
ASSERT(thread->IsValid());
+ Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
thread->Run();
return NULL;
}
@@ -476,7 +490,15 @@ void Thread::set_name(const char* name) {
void Thread::Start() {
- pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
+ pthread_attr_t* attr_ptr = NULL;
+ pthread_attr_t attr;
+ if (stack_size_ > 0) {
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
+ attr_ptr = &attr;
+ }
+ pthread_create(&thread_handle_data()->thread_, attr_ptr, ThreadEntry, this);
+ ASSERT(IsValid());
}
@@ -595,52 +617,111 @@ Semaphore* OS::CreateSemaphore(int count) {
class Sampler::PlatformData : public Malloced {
public:
- explicit PlatformData(Sampler* sampler)
- : sampler_(sampler),
- task_self_(mach_task_self()),
- profiled_thread_(0),
- sampler_thread_(0) {
+ PlatformData() : profiled_thread_(mach_thread_self()) {}
+
+ ~PlatformData() {
+ // Deallocate Mach port for thread.
+ mach_port_deallocate(mach_task_self(), profiled_thread_);
}
- Sampler* sampler_;
+ thread_act_t profiled_thread() { return profiled_thread_; }
+
+ private:
// Note: for profiled_thread_ Mach primitives are used instead of PThread's
// because the latter doesn't provide thread manipulation primitives required.
// For details, consult "Mac OS X Internals" book, Section 7.3.
- mach_port_t task_self_;
thread_act_t profiled_thread_;
- pthread_t sampler_thread_;
- RuntimeProfilerRateLimiter rate_limiter_;
+};
+
+class SamplerThread : public Thread {
+ public:
+ explicit SamplerThread(int interval)
+ : Thread(NULL, "SamplerThread"),
+ interval_(interval) {}
+
+ static void AddActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::AddActiveSampler(sampler);
+ if (instance_ == NULL) {
+ instance_ = new SamplerThread(sampler->interval());
+ instance_->Start();
+ } else {
+ ASSERT(instance_->interval_ == sampler->interval());
+ }
+ }
+
+ static void RemoveActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::RemoveActiveSampler(sampler);
+ if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
+ RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown();
+ instance_->Join();
+ delete instance_;
+ instance_ = NULL;
+ }
+ }
- // Sampler thread handler.
- void Runner() {
- while (sampler_->IsActive()) {
- if (rate_limiter_.SuspendIfNecessary()) continue;
- Sample();
- OS::Sleep(sampler_->interval_);
+ // Implement Thread::Run().
+ virtual void Run() {
+ SamplerRegistry::State state;
+ while ((state = SamplerRegistry::GetState()) !=
+ SamplerRegistry::HAS_NO_SAMPLERS) {
+ bool cpu_profiling_enabled =
+ (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
+ bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
+ // When CPU profiling is enabled both JavaScript and C++ code is
+ // profiled. We must not suspend.
+ if (!cpu_profiling_enabled) {
+ if (rate_limiter_.SuspendIfNecessary()) continue;
+ }
+ if (cpu_profiling_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
+ return;
+ }
+ }
+ if (runtime_profiler_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
+ return;
+ }
+ }
+ OS::Sleep(interval_);
}
}
- void Sample() {
- if (sampler_->IsProfiling()) {
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
+ static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
+ if (!sampler->isolate()->IsInitialized()) return;
+ if (!sampler->IsProfiling()) return;
+ SamplerThread* sampler_thread =
+ reinterpret_cast<SamplerThread*>(raw_sampler_thread);
+ sampler_thread->SampleContext(sampler);
+ }
- if (KERN_SUCCESS != thread_suspend(profiled_thread_)) return;
+ static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
+ if (!sampler->isolate()->IsInitialized()) return;
+ sampler->isolate()->runtime_profiler()->NotifyTick();
+ }
+
+ void SampleContext(Sampler* sampler) {
+ thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
+ TickSample sample_obj;
+ TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
+ if (sample == NULL) sample = &sample_obj;
+
+ if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
#if V8_HOST_ARCH_X64
- thread_state_flavor_t flavor = x86_THREAD_STATE64;
- x86_thread_state64_t state;
- mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = x86_THREAD_STATE64;
+ x86_thread_state64_t state;
+ mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
#if __DARWIN_UNIX03
#define REGISTER_FIELD(name) __r ## name
#else
#define REGISTER_FIELD(name) r ## name
#endif // __DARWIN_UNIX03
#elif V8_HOST_ARCH_IA32
- thread_state_flavor_t flavor = i386_THREAD_STATE;
- i386_thread_state_t state;
- mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+ thread_state_flavor_t flavor = i386_THREAD_STATE;
+ i386_thread_state_t state;
+ mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
#if __DARWIN_UNIX03
#define REGISTER_FIELD(name) __e ## name
#else
@@ -650,81 +731,64 @@ class Sampler::PlatformData : public Malloced {
#error Unsupported Mac OS X host architecture.
#endif // V8_HOST_ARCH
- if (thread_get_state(profiled_thread_,
- flavor,
- reinterpret_cast<natural_t*>(&state),
- &count) == KERN_SUCCESS) {
- sample->state = Top::current_vm_state();
- sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
- sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
- sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
- sampler_->SampleStack(sample);
- sampler_->Tick(sample);
- }
- thread_resume(profiled_thread_);
+ if (thread_get_state(profiled_thread,
+ flavor,
+ reinterpret_cast<natural_t*>(&state),
+ &count) == KERN_SUCCESS) {
+ sample->state = sampler->isolate()->current_vm_state();
+ sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
+ sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
+ sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
}
- if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick();
+ thread_resume(profiled_thread);
}
+
+ const int interval_;
+ RuntimeProfilerRateLimiter rate_limiter_;
+
+ // Protects the process wide state below.
+ static Mutex* mutex_;
+ static SamplerThread* instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(SamplerThread);
};
#undef REGISTER_FIELD
-// Entry point for sampler thread.
-static void* SamplerEntry(void* arg) {
- Sampler::PlatformData* data =
- reinterpret_cast<Sampler::PlatformData*>(arg);
- data->Runner();
- return 0;
-}
+Mutex* SamplerThread::mutex_ = OS::CreateMutex();
+SamplerThread* SamplerThread::instance_ = NULL;
-Sampler::Sampler(int interval)
- : interval_(interval),
+Sampler::Sampler(Isolate* isolate, int interval)
+ : isolate_(isolate),
+ interval_(interval),
profiling_(false),
active_(false),
samples_taken_(0) {
- data_ = new PlatformData(this);
+ data_ = new PlatformData;
}
Sampler::~Sampler() {
+ ASSERT(!IsActive());
delete data_;
}
void Sampler::Start() {
- // Do not start multiple threads for the same sampler.
ASSERT(!IsActive());
- data_->profiled_thread_ = mach_thread_self();
-
- // Create sampler thread with high priority.
- // According to POSIX spec, when SCHED_FIFO policy is used, a thread
- // runs until it exits or blocks.
- pthread_attr_t sched_attr;
- sched_param fifo_param;
- pthread_attr_init(&sched_attr);
- pthread_attr_setinheritsched(&sched_attr, PTHREAD_EXPLICIT_SCHED);
- pthread_attr_setschedpolicy(&sched_attr, SCHED_FIFO);
- fifo_param.sched_priority = sched_get_priority_max(SCHED_FIFO);
- pthread_attr_setschedparam(&sched_attr, &fifo_param);
-
SetActive(true);
- pthread_create(&data_->sampler_thread_, &sched_attr, SamplerEntry, data_);
+ SamplerThread::AddActiveSampler(this);
}
void Sampler::Stop() {
- // Seting active to false triggers termination of the sampler
- // thread.
+ ASSERT(IsActive());
+ SamplerThread::RemoveActiveSampler(this);
SetActive(false);
-
- // Wait for sampler thread to terminate.
- Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
- pthread_join(data_->sampler_thread_, NULL);
-
- // Deallocate Mach port for thread.
- mach_port_deallocate(data_->task_self_, data_->profiled_thread_);
}
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/src/platform-nullos.cc b/src/platform-nullos.cc
index 49d3dd98..5409936f 100644
--- a/src/platform-nullos.cc
+++ b/src/platform-nullos.cc
@@ -340,13 +340,19 @@ bool ThreadHandle::IsValid() const {
}
-Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
- set_name("v8:<unknown>");
+Thread::Thread(Isolate* isolate, const Options& options)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(options.stack_size) {
+ set_name(options.name);
UNIMPLEMENTED();
}
-Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(Isolate* isolate, const char* name)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(0) {
set_name(name);
UNIMPLEMENTED();
}
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index e2796294..fe1a62a0 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -154,7 +154,7 @@ void* OS::Allocate(const size_t requested,
void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
if (mbase == MAP_FAILED) {
- LOG(StringEvent("OS::Allocate", "mmap failed"));
+ LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
@@ -400,12 +400,18 @@ bool ThreadHandle::IsValid() const {
}
-Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
- set_name("v8:<unknown>");
+Thread::Thread(Isolate* isolate, const Options& options)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(options.stack_size) {
+ set_name(options.name);
}
-Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(Isolate* isolate, const char* name)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(0) {
set_name(name);
}
@@ -421,6 +427,7 @@ static void* ThreadEntry(void* arg) {
// one) so we initialize it here too.
thread->thread_handle_data()->thread_ = pthread_self();
ASSERT(thread->IsValid());
+ Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
thread->Run();
return NULL;
}
@@ -433,7 +440,14 @@ void Thread::set_name(const char* name) {
void Thread::Start() {
- pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
+ pthread_attr_t* attr_ptr = NULL;
+ pthread_attr_t attr;
+ if (stack_size_ > 0) {
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
+ attr_ptr = &attr;
+ }
+ pthread_create(&thread_handle_data()->thread_, attr_ptr, ThreadEntry, this);
ASSERT(IsValid());
}
@@ -598,8 +612,9 @@ class Sampler::PlatformData : public Malloced {
};
-Sampler::Sampler(int interval)
- : interval_(interval),
+Sampler::Sampler(Isolate* isolate, int interval)
+ : isolate_(isolate),
+ interval_(interval),
profiling_(false),
active_(false),
samples_taken_(0) {
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index 256dc75f..1dd486eb 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -127,7 +127,7 @@ bool OS::Remove(const char* path) {
}
-const char* OS::LogFileOpenMode = "w";
+const char* const OS::LogFileOpenMode = "w";
void OS::Print(const char* format, ...) {
@@ -139,7 +139,7 @@ void OS::Print(const char* format, ...) {
void OS::VPrint(const char* format, va_list args) {
-#if defined(ANDROID)
+#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, format, args);
#else
vprintf(format, args);
@@ -156,7 +156,7 @@ void OS::FPrint(FILE* out, const char* format, ...) {
void OS::VFPrint(FILE* out, const char* format, va_list args) {
-#if defined(ANDROID)
+#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, format, args);
#else
vfprintf(out, format, args);
@@ -173,7 +173,7 @@ void OS::PrintError(const char* format, ...) {
void OS::VPrintError(const char* format, va_list args) {
-#if defined(ANDROID)
+#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
LOG_PRI_VA(ANDROID_LOG_ERROR, LOG_TAG, format, args);
#else
vfprintf(stderr, format, args);
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index ebe0475f..da278f34 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -45,7 +45,7 @@
#include <errno.h>
#include <ieeefp.h> // finite()
#include <signal.h> // sigemptyset(), etc
-#include <sys/kdi_regs.h>
+#include <sys/regset.h>
#undef MAP_TYPE
@@ -169,7 +169,7 @@ void* OS::Allocate(const size_t requested,
void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
if (mbase == MAP_FAILED) {
- LOG(StringEvent("OS::Allocate", "mmap failed"));
+ LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
@@ -415,12 +415,18 @@ bool ThreadHandle::IsValid() const {
}
-Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
- set_name("v8:<unknown>");
+Thread::Thread(Isolate* isolate, const Options& options)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(options.stack_size) {
+ set_name(options.name);
}
-Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(Isolate* isolate, const char* name)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(0) {
set_name(name);
}
@@ -436,6 +442,7 @@ static void* ThreadEntry(void* arg) {
// one) so we initialize it here too.
thread->thread_handle_data()->thread_ = pthread_self();
ASSERT(thread->IsValid());
+ Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
thread->Run();
return NULL;
}
@@ -448,6 +455,13 @@ void Thread::set_name(const char* name) {
void Thread::Start() {
+ pthread_attr_t* attr_ptr = NULL;
+ pthread_attr_t attr;
+ if (stack_size_ > 0) {
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
+ attr_ptr = &attr;
+ }
pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
ASSERT(IsValid());
}
@@ -612,11 +626,16 @@ static Sampler* active_sampler_ = NULL;
static pthread_t vm_tid_ = 0;
+static pthread_t GetThreadID() {
+ return pthread_self();
+}
+
+
static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
USE(info);
if (signal != SIGPROF) return;
if (active_sampler_ == NULL || !active_sampler_->IsActive()) return;
- if (vm_tid_ != pthread_self()) return;
+ if (vm_tid_ != GetThreadID()) return;
TickSample sample_obj;
TickSample* sample = CpuProfiler::TickSampleEvent();
@@ -627,17 +646,10 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
mcontext_t& mcontext = ucontext->uc_mcontext;
sample->state = Top::current_vm_state();
-#if V8_HOST_ARCH_IA32
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[KDIREG_EIP]);
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_ESP]);
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_EBP]);
-#elif V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[KDIREG_RIP]);
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_RSP]);
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_RBP]);
-#else
- UNIMPLEMENTED();
-#endif
+ sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
+ sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
+ sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
+
active_sampler_->SampleStack(sample);
active_sampler_->Tick(sample);
}
@@ -645,26 +657,87 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
class Sampler::PlatformData : public Malloced {
public:
- PlatformData() {
- signal_handler_installed_ = false;
+ enum SleepInterval {
+ FULL_INTERVAL,
+ HALF_INTERVAL
+ };
+
+ explicit PlatformData(Sampler* sampler)
+ : sampler_(sampler),
+ signal_handler_installed_(false),
+ vm_tgid_(getpid()),
+ signal_sender_launched_(false) {
+ }
+
+ void SignalSender() {
+ while (sampler_->IsActive()) {
+ if (rate_limiter_.SuspendIfNecessary()) continue;
+ if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) {
+ SendProfilingSignal();
+ Sleep(HALF_INTERVAL);
+ RuntimeProfiler::NotifyTick();
+ Sleep(HALF_INTERVAL);
+ } else {
+ if (sampler_->IsProfiling()) SendProfilingSignal();
+ if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick();
+ Sleep(FULL_INTERVAL);
+ }
+ }
+ }
+
+ void SendProfilingSignal() {
+ if (!signal_handler_installed_) return;
+ pthread_kill(vm_tid_, SIGPROF);
}
+ void Sleep(SleepInterval full_or_half) {
+ // Convert ms to us and subtract 100 us to compensate delays
+ // occuring during signal delivery.
+ useconds_t interval = sampler_->interval_ * 1000 - 100;
+ if (full_or_half == HALF_INTERVAL) interval /= 2;
+ int result = usleep(interval);
+#ifdef DEBUG
+ if (result != 0 && errno != EINTR) {
+ fprintf(stderr,
+ "SignalSender usleep error; interval = %u, errno = %d\n",
+ interval,
+ errno);
+ ASSERT(result == 0 || errno == EINTR);
+ }
+#endif
+ USE(result);
+ }
+
+ Sampler* sampler_;
bool signal_handler_installed_;
struct sigaction old_signal_handler_;
- struct itimerval old_timer_value_;
+ int vm_tgid_;
+ bool signal_sender_launched_;
+ pthread_t signal_sender_thread_;
+ RuntimeProfilerRateLimiter rate_limiter_;
};
-Sampler::Sampler(int interval)
- : interval_(interval),
+static void* SenderEntry(void* arg) {
+ Sampler::PlatformData* data =
+ reinterpret_cast<Sampler::PlatformData*>(arg);
+ data->SignalSender();
+ return 0;
+}
+
+
+Sampler::Sampler(Isolate* isolate, int interval)
+ : isolate_(isolate),
+ interval_(interval),
profiling_(false),
active_(false),
samples_taken_(0) {
- data_ = new PlatformData();
+ data_ = new PlatformData(this);
}
Sampler::~Sampler() {
+ ASSERT(!data_->signal_sender_launched_);
delete data_;
}
@@ -672,41 +745,50 @@ Sampler::~Sampler() {
void Sampler::Start() {
// There can only be one active sampler at the time on POSIX
// platforms.
- if (active_sampler_ != NULL) return;
+ ASSERT(!IsActive());
+ vm_tid_ = GetThreadID();
// Request profiling signals.
struct sigaction sa;
sa.sa_sigaction = ProfilerSignalHandler;
sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_SIGINFO;
- if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
- data_->signal_handler_installed_ = true;
-
- // Set the itimer to generate a tick for each interval.
- itimerval itimer;
- itimer.it_interval.tv_sec = interval_ / 1000;
- itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
- itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
- itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
- setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ data_->signal_handler_installed_ =
+ sigaction(SIGPROF, &sa, &data_->old_signal_handler_) == 0;
+
+ // Start a thread that sends SIGPROF signal to VM thread.
+ // Sending the signal ourselves instead of relying on itimer provides
+ // much better accuracy.
+ SetActive(true);
+ if (pthread_create(
+ &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
+ data_->signal_sender_launched_ = true;
+ }
// Set this sampler as the active sampler.
active_sampler_ = this;
- active_ = true;
}
void Sampler::Stop() {
+ SetActive(false);
+
+ // Wait for signal sender termination (it will exit after setting
+ // active_ to false).
+ if (data_->signal_sender_launched_) {
+ Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
+ pthread_join(data_->signal_sender_thread_, NULL);
+ data_->signal_sender_launched_ = false;
+ }
+
// Restore old signal handler
if (data_->signal_handler_installed_) {
- setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
sigaction(SIGPROF, &data_->old_signal_handler_, 0);
data_->signal_handler_installed_ = false;
}
// This sampler is no longer the active sampler.
active_sampler_ = NULL;
- active_ = false;
}
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/src/platform-tls-mac.h b/src/platform-tls-mac.h
new file mode 100644
index 00000000..86a3347d
--- /dev/null
+++ b/src/platform-tls-mac.h
@@ -0,0 +1,62 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PLATFORM_TLS_MAC_H_
+#define V8_PLATFORM_TLS_MAC_H_
+
+#include "globals.h"
+
+namespace v8 {
+namespace internal {
+
+#if defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64)
+
+#define V8_FAST_TLS_SUPPORTED 1
+
+INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
+
+inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
+ // The constants below are taken from pthreads.s from the XNU kernel
+ // sources archive at www.opensource.apple.com.
+ intptr_t result;
+#if defined(V8_HOST_ARCH_IA32)
+ asm("movl %%gs:0x48(,%1,4), %0;"
+ :"=r"(result) // Output must be a writable register.
+ :"0"(index)); // Input is the same as output.
+#else
+ asm("movq %%gs:0x60(,%1,8), %0;"
+ :"=r"(result)
+ :"0"(index));
+#endif
+ return result;
+}
+
+#endif
+
+} } // namespace v8::internal
+
+#endif // V8_PLATFORM_TLS_MAC_H_
diff --git a/src/platform-tls-win32.h b/src/platform-tls-win32.h
new file mode 100644
index 00000000..4056e8cc
--- /dev/null
+++ b/src/platform-tls-win32.h
@@ -0,0 +1,62 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PLATFORM_TLS_WIN32_H_
+#define V8_PLATFORM_TLS_WIN32_H_
+
+#include "checks.h"
+#include "globals.h"
+#include "win32-headers.h"
+
+namespace v8 {
+namespace internal {
+
+#if defined(_WIN32) && !defined(_WIN64)
+
+#define V8_FAST_TLS_SUPPORTED 1
+
+inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
+ const intptr_t kTibInlineTlsOffset = 0xE10;
+ const intptr_t kTibExtraTlsOffset = 0xF94;
+ const intptr_t kMaxInlineSlots = 64;
+ const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
+ ASSERT(0 <= index && index < kMaxSlots);
+ if (index < kMaxInlineSlots) {
+ return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
+ kPointerSize * index));
+ }
+ intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
+ ASSERT(extra != 0);
+ return *reinterpret_cast<intptr_t*>(extra +
+ kPointerSize * (index - kMaxInlineSlots));
+}
+
+#endif
+
+} } // namespace v8::internal
+
+#endif // V8_PLATFORM_TLS_WIN32_H_
diff --git a/src/platform-tls.h b/src/platform-tls.h
new file mode 100644
index 00000000..56491754
--- /dev/null
+++ b/src/platform-tls.h
@@ -0,0 +1,50 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Platform and architecture specific thread local store functions.
+
+#ifndef V8_PLATFORM_TLS_H_
+#define V8_PLATFORM_TLS_H_
+
+#ifdef V8_FAST_TLS
+
+// When fast TLS is requested we include the appropriate
+// implementation header.
+//
+// The implementation header defines V8_FAST_TLS_SUPPORTED if it
+// provides fast TLS support for the current platform and architecture
+// combination.
+
+#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
+#include "platform-tls-win32.h"
+#elif defined(__APPLE__)
+#include "platform-tls-mac.h"
+#endif
+
+#endif
+
+#endif // V8_PLATFORM_TLS_H_
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index f24994b5..50a9e5b1 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -173,6 +173,10 @@ double ceiling(double x) {
return ceil(x);
}
+
+static Mutex* limit_mutex = NULL;
+
+
#ifdef _WIN64
typedef double (*ModuloFunction)(double, double);
@@ -540,6 +544,7 @@ void OS::Setup() {
// call this setup code within the same millisecond.
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srand(static_cast<unsigned int>(seed));
+ limit_mutex = CreateMutex();
}
@@ -676,7 +681,7 @@ bool OS::Remove(const char* path) {
// Open log file in binary mode to avoid /n -> /r/n conversion.
-const char* OS::LogFileOpenMode = "wb";
+const char* const OS::LogFileOpenMode = "wb";
// Print (debug) message to console.
@@ -749,9 +754,13 @@ char* OS::StrChr(char* str, int c) {
void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
+ // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small.
+ size_t buffer_size = static_cast<size_t>(dest.length());
+ if (n + 1 > buffer_size) // count for trailing '\0'
+ n = _TRUNCATE;
int result = strncpy_s(dest.start(), dest.length(), src, n);
USE(result);
- ASSERT(result == 0);
+ ASSERT(result == 0 || (n == _TRUNCATE && result == STRUNCATE));
}
@@ -765,6 +774,9 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
static void UpdateAllocatedSpaceLimits(void* address, int size) {
+ ASSERT(limit_mutex != NULL);
+ ScopedLock lock(limit_mutex);
+
lowest_ever_allocated = Min(lowest_ever_allocated, address);
highest_ever_allocated =
Max(highest_ever_allocated,
@@ -835,7 +847,7 @@ void* OS::Allocate(const size_t requested,
// For exectutable pages try and randomize the allocation address
if (prot == PAGE_EXECUTE_READWRITE &&
msize >= static_cast<size_t>(Page::kPageSize)) {
- address = (V8::RandomPrivate() << kPageSizeBits)
+ address = (V8::RandomPrivate(Isolate::Current()) << kPageSizeBits)
| kAllocationRandomAddressMin;
address &= kAllocationRandomAddressMax;
}
@@ -848,7 +860,7 @@ void* OS::Allocate(const size_t requested,
mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot);
if (mbase == NULL) {
- LOG(StringEvent("OS::Allocate", "VirtualAlloc failed"));
+ LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed"));
return NULL;
}
@@ -1191,7 +1203,8 @@ static bool LoadSymbols(HANDLE process_handle) {
if (err != ERROR_MOD_NOT_FOUND &&
err != ERROR_INVALID_HANDLE) return false;
}
- LOG(SharedLibraryEvent(
+ LOG(i::Isolate::Current(),
+ SharedLibraryEvent(
module_entry.szExePath,
reinterpret_cast<unsigned int>(module_entry.modBaseAddr),
reinterpret_cast<unsigned int>(module_entry.modBaseAddr +
@@ -1450,6 +1463,7 @@ static unsigned int __stdcall ThreadEntry(void* arg) {
// don't know which thread will run first (the original thread or the new
// one) so we initialize it here too.
thread->thread_handle_data()->tid_ = GetCurrentThreadId();
+ Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
thread->Run();
return 0;
}
@@ -1493,13 +1507,19 @@ class Thread::PlatformData : public Malloced {
// Initialize a Win32 thread object. The thread has an invalid thread
// handle until it is started.
-Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(Isolate* isolate, const Options& options)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(options.stack_size) {
data_ = new PlatformData(kNoThread);
- set_name("v8:<unknown>");
+ set_name(options.name);
}
-Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(Isolate* isolate, const char* name)
+ : ThreadHandle(ThreadHandle::INVALID),
+ isolate_(isolate),
+ stack_size_(0) {
data_ = new PlatformData(kNoThread);
set_name(name);
}
@@ -1524,7 +1544,7 @@ Thread::~Thread() {
void Thread::Start() {
data_->thread_ = reinterpret_cast<HANDLE>(
_beginthreadex(NULL,
- 0,
+ static_cast<unsigned>(stack_size_),
ThreadEntry,
this,
0,
@@ -1840,135 +1860,179 @@ Socket* OS::CreateSocket() {
// ----------------------------------------------------------------------------
// Win32 profiler support.
-//
-// On win32 we use a sampler thread with high priority to sample the program
-// counter for the profiled thread.
class Sampler::PlatformData : public Malloced {
public:
- explicit PlatformData(Sampler* sampler) {
- sampler_ = sampler;
- sampler_thread_ = INVALID_HANDLE_VALUE;
- profiled_thread_ = INVALID_HANDLE_VALUE;
+ // Get a handle to the calling thread. This is the thread that we are
+ // going to profile. We need to make a copy of the handle because we are
+ // going to use it in the sampler thread. Using GetThreadHandle() will
+ // not work in this case. We're using OpenThread because DuplicateHandle
+ // for some reason doesn't work in Chrome's sandbox.
+ PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
+ THREAD_SUSPEND_RESUME |
+ THREAD_QUERY_INFORMATION,
+ false,
+ GetCurrentThreadId())) {}
+
+ ~PlatformData() {
+ if (profiled_thread_ != NULL) {
+ CloseHandle(profiled_thread_);
+ profiled_thread_ = NULL;
+ }
}
- Sampler* sampler_;
- HANDLE sampler_thread_;
+ HANDLE profiled_thread() { return profiled_thread_; }
+
+ private:
HANDLE profiled_thread_;
- RuntimeProfilerRateLimiter rate_limiter_;
+};
+
+
+class SamplerThread : public Thread {
+ public:
+ explicit SamplerThread(int interval)
+ : Thread(NULL, "SamplerThread"),
+ interval_(interval) {}
+
+ static void AddActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::AddActiveSampler(sampler);
+ if (instance_ == NULL) {
+ instance_ = new SamplerThread(sampler->interval());
+ instance_->Start();
+ } else {
+ ASSERT(instance_->interval_ == sampler->interval());
+ }
+ }
+
+ static void RemoveActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::RemoveActiveSampler(sampler);
+ if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
+ RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown();
+ instance_->Join();
+ delete instance_;
+ instance_ = NULL;
+ }
+ }
- // Sampler thread handler.
- void Runner() {
- while (sampler_->IsActive()) {
- if (rate_limiter_.SuspendIfNecessary()) continue;
- Sample();
- Sleep(sampler_->interval_);
+ // Implement Thread::Run().
+ virtual void Run() {
+ SamplerRegistry::State state;
+ while ((state = SamplerRegistry::GetState()) !=
+ SamplerRegistry::HAS_NO_SAMPLERS) {
+ bool cpu_profiling_enabled =
+ (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
+ bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
+ // When CPU profiling is enabled both JavaScript and C++ code is
+ // profiled. We must not suspend.
+ if (!cpu_profiling_enabled) {
+ if (rate_limiter_.SuspendIfNecessary()) continue;
+ }
+ if (cpu_profiling_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
+ return;
+ }
+ }
+ if (runtime_profiler_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
+ return;
+ }
+ }
+ OS::Sleep(interval_);
}
}
- void Sample() {
- if (sampler_->IsProfiling()) {
- // Context used for sampling the register state of the profiled thread.
- CONTEXT context;
- memset(&context, 0, sizeof(context));
+ static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
+ if (!sampler->isolate()->IsInitialized()) return;
+ if (!sampler->IsProfiling()) return;
+ SamplerThread* sampler_thread =
+ reinterpret_cast<SamplerThread*>(raw_sampler_thread);
+ sampler_thread->SampleContext(sampler);
+ }
+
+ static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
+ if (!sampler->isolate()->IsInitialized()) return;
+ sampler->isolate()->runtime_profiler()->NotifyTick();
+ }
+
+ void SampleContext(Sampler* sampler) {
+ HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
+ if (profiled_thread == NULL) return;
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
+ // Context used for sampling the register state of the profiled thread.
+ CONTEXT context;
+ memset(&context, 0, sizeof(context));
- static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
- if (SuspendThread(profiled_thread_) == kSuspendFailed) return;
- sample->state = Top::current_vm_state();
+ TickSample sample_obj;
+ TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
+ if (sample == NULL) sample = &sample_obj;
- context.ContextFlags = CONTEXT_FULL;
- if (GetThreadContext(profiled_thread_, &context) != 0) {
+ static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
+ if (SuspendThread(profiled_thread) == kSuspendFailed) return;
+ sample->state = sampler->isolate()->current_vm_state();
+
+ context.ContextFlags = CONTEXT_FULL;
+ if (GetThreadContext(profiled_thread, &context) != 0) {
#if V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(context.Rip);
- sample->sp = reinterpret_cast<Address>(context.Rsp);
- sample->fp = reinterpret_cast<Address>(context.Rbp);
+ sample->pc = reinterpret_cast<Address>(context.Rip);
+ sample->sp = reinterpret_cast<Address>(context.Rsp);
+ sample->fp = reinterpret_cast<Address>(context.Rbp);
#else
- sample->pc = reinterpret_cast<Address>(context.Eip);
- sample->sp = reinterpret_cast<Address>(context.Esp);
- sample->fp = reinterpret_cast<Address>(context.Ebp);
+ sample->pc = reinterpret_cast<Address>(context.Eip);
+ sample->sp = reinterpret_cast<Address>(context.Esp);
+ sample->fp = reinterpret_cast<Address>(context.Ebp);
#endif
- sampler_->SampleStack(sample);
- sampler_->Tick(sample);
- }
- ResumeThread(profiled_thread_);
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
}
- if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick();
+ ResumeThread(profiled_thread);
}
+
+ const int interval_;
+ RuntimeProfilerRateLimiter rate_limiter_;
+
+ // Protects the process wide state below.
+ static Mutex* mutex_;
+ static SamplerThread* instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(SamplerThread);
};
-// Entry point for sampler thread.
-static unsigned int __stdcall SamplerEntry(void* arg) {
- Sampler::PlatformData* data =
- reinterpret_cast<Sampler::PlatformData*>(arg);
- data->Runner();
- return 0;
-}
+Mutex* SamplerThread::mutex_ = OS::CreateMutex();
+SamplerThread* SamplerThread::instance_ = NULL;
-// Initialize a profile sampler.
-Sampler::Sampler(int interval)
- : interval_(interval),
+Sampler::Sampler(Isolate* isolate, int interval)
+ : isolate_(isolate),
+ interval_(interval),
profiling_(false),
active_(false),
samples_taken_(0) {
- data_ = new PlatformData(this);
+ data_ = new PlatformData;
}
Sampler::~Sampler() {
+ ASSERT(!IsActive());
delete data_;
}
-// Start profiling.
void Sampler::Start() {
- // Do not start multiple threads for the same sampler.
ASSERT(!IsActive());
-
- // Get a handle to the calling thread. This is the thread that we are
- // going to profile. We need to make a copy of the handle because we are
- // going to use it in the sampler thread. Using GetThreadHandle() will
- // not work in this case. We're using OpenThread because DuplicateHandle
- // for some reason doesn't work in Chrome's sandbox.
- data_->profiled_thread_ = OpenThread(THREAD_GET_CONTEXT |
- THREAD_SUSPEND_RESUME |
- THREAD_QUERY_INFORMATION,
- false,
- GetCurrentThreadId());
- BOOL ok = data_->profiled_thread_ != NULL;
- if (!ok) return;
-
- // Start sampler thread.
- unsigned int tid;
SetActive(true);
- data_->sampler_thread_ = reinterpret_cast<HANDLE>(
- _beginthreadex(NULL, 0, SamplerEntry, data_, 0, &tid));
- // Set thread to high priority to increase sampling accuracy.
- SetThreadPriority(data_->sampler_thread_, THREAD_PRIORITY_TIME_CRITICAL);
+ SamplerThread::AddActiveSampler(this);
}
-// Stop profiling.
void Sampler::Stop() {
- // Seting active to false triggers termination of the sampler
- // thread.
+ ASSERT(IsActive());
+ SamplerThread::RemoveActiveSampler(this);
SetActive(false);
-
- // Wait for sampler thread to terminate.
- Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
- WaitForSingleObject(data_->sampler_thread_, INFINITE);
-
- // Release the thread handles
- CloseHandle(data_->sampler_thread_);
- CloseHandle(data_->profiled_thread_);
}
-
#endif // ENABLE_LOGGING_AND_PROFILING
} } // namespace v8::internal
diff --git a/src/platform.h b/src/platform.h
index 88825e64..b2e0c48c 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -114,6 +114,7 @@ int signbit(double x);
#endif // __GNUC__
#include "atomicops.h"
+#include "platform-tls.h"
#include "utils.h"
#include "v8globals.h"
@@ -177,7 +178,7 @@ class OS {
static bool Remove(const char* path);
// Log file open mode is platform-dependent due to line ends issues.
- static const char* LogFileOpenMode;
+ static const char* const LogFileOpenMode;
// Print output to console. This is mostly used for debugging output.
// On platforms that has standard terminal output, the output
@@ -293,6 +294,9 @@ class OS {
// Support runtime detection of VFP3 on ARM CPUs.
static bool ArmCpuHasFeature(CpuFeature feature);
+ // Support runtime detection of FPU on MIPS CPUs.
+ static bool MipsCpuHasFeature(CpuFeature feature);
+
// Returns the activation frame alignment constraint or zero if
// the platform doesn't care. Guaranteed to be a power of two.
static int ActivationFrameAlignment();
@@ -388,9 +392,16 @@ class Thread: public ThreadHandle {
LOCAL_STORAGE_KEY_MAX_VALUE = kMaxInt
};
- // Create new thread.
- Thread();
- explicit Thread(const char* name);
+ struct Options {
+ Options() : name("v8:<unknown>"), stack_size(0) {}
+
+ const char* name;
+ int stack_size;
+ };
+
+ // Create new thread (with a value for storing in the TLS isolate field).
+ Thread(Isolate* isolate, const Options& options);
+ Thread(Isolate* isolate, const char* name);
virtual ~Thread();
// Start new thread by calling the Run() method in the new thread.
@@ -421,9 +432,24 @@ class Thread: public ThreadHandle {
return GetThreadLocal(key) != NULL;
}
+#ifdef V8_FAST_TLS_SUPPORTED
+ static inline void* GetExistingThreadLocal(LocalStorageKey key) {
+ void* result = reinterpret_cast<void*>(
+ InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
+ ASSERT(result == GetThreadLocal(key));
+ return result;
+ }
+#else
+ static inline void* GetExistingThreadLocal(LocalStorageKey key) {
+ return GetThreadLocal(key);
+ }
+#endif
+
// A hint to the scheduler to let another thread run.
static void YieldCPU();
+ Isolate* isolate() const { return isolate_; }
+
// The thread name length is limited to 16 based on Linux's implementation of
// prctl().
static const int kMaxThreadNameLength = 16;
@@ -432,8 +458,9 @@ class Thread: public ThreadHandle {
class PlatformData;
PlatformData* data_;
-
+ Isolate* isolate_;
char name_[kMaxThreadNameLength];
+ int stack_size_;
DISALLOW_COPY_AND_ASSIGN(Thread);
};
@@ -466,13 +493,14 @@ class Mutex {
// ----------------------------------------------------------------------------
-// ScopedLock
+// ScopedLock/ScopedUnlock
//
-// Stack-allocated ScopedLocks provide block-scoped locking and unlocking
-// of a mutex.
+// Stack-allocated ScopedLocks/ScopedUnlocks provide block-scoped
+// locking and unlocking of a mutex.
class ScopedLock {
public:
explicit ScopedLock(Mutex* mutex): mutex_(mutex) {
+ ASSERT(mutex_ != NULL);
mutex_->Lock();
}
~ScopedLock() {
@@ -570,22 +598,28 @@ class TickSample {
tos(NULL),
frames_count(0) {}
StateTag state; // The state of the VM.
- Address pc; // Instruction pointer.
- Address sp; // Stack pointer.
- Address fp; // Frame pointer.
- Address tos; // Top stack value (*sp).
+ Address pc; // Instruction pointer.
+ Address sp; // Stack pointer.
+ Address fp; // Frame pointer.
+ union {
+ Address tos; // Top stack value (*sp).
+ Address external_callback;
+ };
static const int kMaxFramesCount = 64;
Address stack[kMaxFramesCount]; // Call stack.
- int frames_count; // Number of captured frames.
+ int frames_count : 8; // Number of captured frames.
+ bool has_external_callback : 1;
};
#ifdef ENABLE_LOGGING_AND_PROFILING
class Sampler {
public:
// Initialize sampler.
- explicit Sampler(int interval);
+ Sampler(Isolate* isolate, int interval);
virtual ~Sampler();
+ int interval() const { return interval_; }
+
// Performs stack sampling.
void SampleStack(TickSample* sample) {
DoSampleStack(sample);
@@ -608,11 +642,16 @@ class Sampler {
// Whether the sampler is running (that is, consumes resources).
bool IsActive() const { return NoBarrier_Load(&active_); }
+ Isolate* isolate() { return isolate_; }
+
// Used in tests to make sure that stack sampling is performed.
int samples_taken() const { return samples_taken_; }
void ResetSamplesTaken() { samples_taken_ = 0; }
class PlatformData;
+ PlatformData* data() { return data_; }
+
+ PlatformData* platform_data() { return data_; }
protected:
virtual void DoSampleStack(TickSample* sample) = 0;
@@ -621,6 +660,7 @@ class Sampler {
void SetActive(bool value) { NoBarrier_Store(&active_, value); }
void IncSamplesTaken() { if (++samples_taken_ < 0) samples_taken_ = 0; }
+ Isolate* isolate_;
const int interval_;
Atomic32 profiling_;
Atomic32 active_;
@@ -629,6 +669,7 @@ class Sampler {
DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler);
};
+
#endif // ENABLE_LOGGING_AND_PROFILING
} } // namespace v8::internal
diff --git a/src/preparse-data.cc b/src/preparse-data.cc
index 7c9d8a61..92a0338a 100644
--- a/src/preparse-data.cc
+++ b/src/preparse-data.cc
@@ -32,8 +32,10 @@
#include "utils.h"
#include "list-inl.h"
#include "hashmap.h"
+
#include "preparse-data.h"
+
namespace v8 {
namespace internal {
diff --git a/src/preparser-api.cc b/src/preparser-api.cc
index 3817935f..61e9e7e0 100644
--- a/src/preparser-api.cc
+++ b/src/preparser-api.cc
@@ -26,6 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/v8-preparser.h"
+
#include "globals.h"
#include "checks.h"
#include "allocation.h"
@@ -158,6 +159,9 @@ class InputStreamUTF16Buffer : public UC16CharacterStream {
class StandAloneJavaScriptScanner : public JavaScriptScanner {
public:
+ explicit StandAloneJavaScriptScanner(ScannerConstants* scanner_constants)
+ : JavaScriptScanner(scanner_constants) { }
+
void Initialize(UC16CharacterStream* source) {
source_ = source;
Init();
@@ -170,7 +174,8 @@ class StandAloneJavaScriptScanner : public JavaScriptScanner {
};
-// Functions declared by allocation.h
+// Functions declared by allocation.h and implemented in both api.cc (for v8)
+// or here (for a stand-alone preparser).
void FatalProcessOutOfMemory(const char* reason) {
V8_Fatal(__FILE__, __LINE__, reason);
@@ -187,7 +192,8 @@ UnicodeInputStream::~UnicodeInputStream() { }
PreParserData Preparse(UnicodeInputStream* input, size_t max_stack) {
internal::InputStreamUTF16Buffer buffer(input);
uintptr_t stack_limit = reinterpret_cast<uintptr_t>(&buffer) - max_stack;
- internal::StandAloneJavaScriptScanner scanner;
+ internal::ScannerConstants scanner_constants;
+ internal::StandAloneJavaScriptScanner scanner(&scanner_constants);
scanner.Initialize(&buffer);
internal::CompleteParserRecorder recorder;
preparser::PreParser::PreParseResult result =
diff --git a/src/preparser.cc b/src/preparser.cc
index 252e88f4..fec1567c 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -1,4 +1,3 @@
-
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -33,6 +32,7 @@
#include "allocation.h"
#include "utils.h"
#include "list.h"
+
#include "scanner-base.h"
#include "preparse-data.h"
#include "preparser.h"
diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
index dda7abbb..043ad1ca 100644
--- a/src/prettyprinter.cc
+++ b/src/prettyprinter.cc
@@ -526,13 +526,13 @@ void PrettyPrinter::PrintLiteral(Handle<Object> value, bool quote) {
Print("%c", string->Get(i));
}
if (quote) Print("\"");
- } else if (object == Heap::null_value()) {
+ } else if (object->IsNull()) {
Print("null");
- } else if (object == Heap::true_value()) {
+ } else if (object->IsTrue()) {
Print("true");
- } else if (object == Heap::false_value()) {
+ } else if (object->IsFalse()) {
Print("false");
- } else if (object == Heap::undefined_value()) {
+ } else if (object->IsUndefined()) {
Print("undefined");
} else if (object->IsNumber()) {
Print("%g", object->Number());
@@ -602,11 +602,12 @@ void PrettyPrinter::PrintCaseClause(CaseClause* clause) {
class IndentedScope BASE_EMBEDDED {
public:
- IndentedScope() {
+ explicit IndentedScope(AstPrinter* printer) : ast_printer_(printer) {
ast_printer_->inc_indent();
}
- explicit IndentedScope(const char* txt, AstNode* node = NULL) {
+ IndentedScope(AstPrinter* printer, const char* txt, AstNode* node = NULL)
+ : ast_printer_(printer) {
ast_printer_->PrintIndented(txt);
if (node != NULL && node->AsExpression() != NULL) {
Expression* expr = node->AsExpression();
@@ -626,30 +627,20 @@ class IndentedScope BASE_EMBEDDED {
ast_printer_->dec_indent();
}
- static void SetAstPrinter(AstPrinter* a) { ast_printer_ = a; }
-
private:
- static AstPrinter* ast_printer_;
+ AstPrinter* ast_printer_;
};
-AstPrinter* IndentedScope::ast_printer_ = NULL;
-
-
//-----------------------------------------------------------------------------
-int AstPrinter::indent_ = 0;
-
-AstPrinter::AstPrinter() {
- ASSERT(indent_ == 0);
- IndentedScope::SetAstPrinter(this);
+AstPrinter::AstPrinter() : indent_(0) {
}
AstPrinter::~AstPrinter() {
ASSERT(indent_ == 0);
- IndentedScope::SetAstPrinter(NULL);
}
@@ -708,14 +699,14 @@ void AstPrinter::PrintLabelsIndented(const char* info, ZoneStringList* labels) {
void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) {
- IndentedScope indent(s, node);
+ IndentedScope indent(this, s, node);
Visit(node);
}
const char* AstPrinter::PrintProgram(FunctionLiteral* program) {
Init();
- { IndentedScope indent("FUNC");
+ { IndentedScope indent(this, "FUNC");
PrintLiteralIndented("NAME", program->name(), true);
PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true);
PrintParameters(program->scope());
@@ -728,7 +719,7 @@ const char* AstPrinter::PrintProgram(FunctionLiteral* program) {
void AstPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) {
if (declarations->length() > 0) {
- IndentedScope indent("DECLS");
+ IndentedScope indent(this, "DECLS");
for (int i = 0; i < declarations->length(); i++) {
Visit(declarations->at(i));
}
@@ -738,7 +729,7 @@ void AstPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) {
void AstPrinter::PrintParameters(Scope* scope) {
if (scope->num_parameters() > 0) {
- IndentedScope indent("PARAMS");
+ IndentedScope indent(this, "PARAMS");
for (int i = 0; i < scope->num_parameters(); i++) {
PrintLiteralWithModeIndented("VAR", scope->parameter(i),
scope->parameter(i)->name(),
@@ -764,10 +755,10 @@ void AstPrinter::PrintArguments(ZoneList<Expression*>* arguments) {
void AstPrinter::PrintCaseClause(CaseClause* clause) {
if (clause->is_default()) {
- IndentedScope indent("DEFAULT");
+ IndentedScope indent(this, "DEFAULT");
PrintStatements(clause->statements());
} else {
- IndentedScope indent("CASE");
+ IndentedScope indent(this, "CASE");
Visit(clause->label());
PrintStatements(clause->statements());
}
@@ -776,7 +767,7 @@ void AstPrinter::PrintCaseClause(CaseClause* clause) {
void AstPrinter::VisitBlock(Block* node) {
const char* block_txt = node->is_initializer_block() ? "BLOCK INIT" : "BLOCK";
- IndentedScope indent(block_txt);
+ IndentedScope indent(this, block_txt);
PrintStatements(node->statements());
}
@@ -844,7 +835,7 @@ void AstPrinter::VisitWithExitStatement(WithExitStatement* node) {
void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
- IndentedScope indent("SWITCH");
+ IndentedScope indent(this, "SWITCH");
PrintLabelsIndented(NULL, node->labels());
PrintIndentedVisit("TAG", node->tag());
for (int i = 0; i < node->cases()->length(); i++) {
@@ -854,7 +845,7 @@ void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
- IndentedScope indent("DO");
+ IndentedScope indent(this, "DO");
PrintLabelsIndented(NULL, node->labels());
PrintIndentedVisit("BODY", node->body());
PrintIndentedVisit("COND", node->cond());
@@ -862,7 +853,7 @@ void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
void AstPrinter::VisitWhileStatement(WhileStatement* node) {
- IndentedScope indent("WHILE");
+ IndentedScope indent(this, "WHILE");
PrintLabelsIndented(NULL, node->labels());
PrintIndentedVisit("COND", node->cond());
PrintIndentedVisit("BODY", node->body());
@@ -870,7 +861,7 @@ void AstPrinter::VisitWhileStatement(WhileStatement* node) {
void AstPrinter::VisitForStatement(ForStatement* node) {
- IndentedScope indent("FOR");
+ IndentedScope indent(this, "FOR");
PrintLabelsIndented(NULL, node->labels());
if (node->init()) PrintIndentedVisit("INIT", node->init());
if (node->cond()) PrintIndentedVisit("COND", node->cond());
@@ -880,7 +871,7 @@ void AstPrinter::VisitForStatement(ForStatement* node) {
void AstPrinter::VisitForInStatement(ForInStatement* node) {
- IndentedScope indent("FOR IN");
+ IndentedScope indent(this, "FOR IN");
PrintIndentedVisit("FOR", node->each());
PrintIndentedVisit("IN", node->enumerable());
PrintIndentedVisit("BODY", node->body());
@@ -888,7 +879,7 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) {
void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
- IndentedScope indent("TRY CATCH");
+ IndentedScope indent(this, "TRY CATCH");
PrintIndentedVisit("TRY", node->try_block());
PrintIndentedVisit("CATCHVAR", node->catch_var());
PrintIndentedVisit("CATCH", node->catch_block());
@@ -896,19 +887,19 @@ void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
- IndentedScope indent("TRY FINALLY");
+ IndentedScope indent(this, "TRY FINALLY");
PrintIndentedVisit("TRY", node->try_block());
PrintIndentedVisit("FINALLY", node->finally_block());
}
void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
- IndentedScope indent("DEBUGGER");
+ IndentedScope indent(this, "DEBUGGER");
}
void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
- IndentedScope indent("FUNC LITERAL");
+ IndentedScope indent(this, "FUNC LITERAL");
PrintLiteralIndented("NAME", node->name(), false);
PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false);
PrintParameters(node->scope());
@@ -921,13 +912,13 @@ void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
void AstPrinter::VisitSharedFunctionInfoLiteral(
SharedFunctionInfoLiteral* node) {
- IndentedScope indent("FUNC LITERAL");
+ IndentedScope indent(this, "FUNC LITERAL");
PrintLiteralIndented("SHARED INFO", node->shared_function_info(), true);
}
void AstPrinter::VisitConditional(Conditional* node) {
- IndentedScope indent("CONDITIONAL");
+ IndentedScope indent(this, "CONDITIONAL");
PrintIndentedVisit("?", node->condition());
PrintIndentedVisit("THEN", node->then_expression());
PrintIndentedVisit("ELSE", node->else_expression());
@@ -940,14 +931,14 @@ void AstPrinter::VisitLiteral(Literal* node) {
void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
- IndentedScope indent("REGEXP LITERAL");
+ IndentedScope indent(this, "REGEXP LITERAL");
PrintLiteralIndented("PATTERN", node->pattern(), false);
PrintLiteralIndented("FLAGS", node->flags(), false);
}
void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
- IndentedScope indent("OBJ LITERAL");
+ IndentedScope indent(this, "OBJ LITERAL");
for (int i = 0; i < node->properties()->length(); i++) {
const char* prop_kind = NULL;
switch (node->properties()->at(i)->kind()) {
@@ -972,7 +963,7 @@ void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
default:
UNREACHABLE();
}
- IndentedScope prop(prop_kind);
+ IndentedScope prop(this, prop_kind);
PrintIndentedVisit("KEY", node->properties()->at(i)->key());
PrintIndentedVisit("VALUE", node->properties()->at(i)->value());
}
@@ -980,9 +971,9 @@ void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
- IndentedScope indent("ARRAY LITERAL");
+ IndentedScope indent(this, "ARRAY LITERAL");
if (node->values()->length() > 0) {
- IndentedScope indent("VALUES");
+ IndentedScope indent(this, "VALUES");
for (int i = 0; i < node->values()->length(); i++) {
Visit(node->values()->at(i));
}
@@ -991,7 +982,7 @@ void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
void AstPrinter::VisitCatchExtensionObject(CatchExtensionObject* node) {
- IndentedScope indent("CatchExtensionObject");
+ IndentedScope indent(this, "CatchExtensionObject");
PrintIndentedVisit("KEY", node->key());
PrintIndentedVisit("VALUE", node->value());
}
@@ -1009,14 +1000,14 @@ void AstPrinter::VisitVariableProxy(VariableProxy* node) {
node->type());
Variable* var = node->var();
if (var != NULL && var->rewrite() != NULL) {
- IndentedScope indent;
+ IndentedScope indent(this);
Visit(var->rewrite());
}
}
void AstPrinter::VisitAssignment(Assignment* node) {
- IndentedScope indent(Token::Name(node->op()), node);
+ IndentedScope indent(this, Token::Name(node->op()), node);
Visit(node->target());
Visit(node->value());
}
@@ -1028,7 +1019,7 @@ void AstPrinter::VisitThrow(Throw* node) {
void AstPrinter::VisitProperty(Property* node) {
- IndentedScope indent("PROPERTY", node);
+ IndentedScope indent(this, "PROPERTY", node);
Visit(node->obj());
Literal* literal = node->key()->AsLiteral();
if (literal != NULL && literal->handle()->IsSymbol()) {
@@ -1040,14 +1031,14 @@ void AstPrinter::VisitProperty(Property* node) {
void AstPrinter::VisitCall(Call* node) {
- IndentedScope indent("CALL");
+ IndentedScope indent(this, "CALL");
Visit(node->expression());
PrintArguments(node->arguments());
}
void AstPrinter::VisitCallNew(CallNew* node) {
- IndentedScope indent("CALL NEW");
+ IndentedScope indent(this, "CALL NEW");
Visit(node->expression());
PrintArguments(node->arguments());
}
@@ -1055,7 +1046,7 @@ void AstPrinter::VisitCallNew(CallNew* node) {
void AstPrinter::VisitCallRuntime(CallRuntime* node) {
PrintLiteralIndented("CALL RUNTIME ", node->name(), false);
- IndentedScope indent;
+ IndentedScope indent(this);
PrintArguments(node->arguments());
}
@@ -1086,14 +1077,14 @@ void AstPrinter::VisitCountOperation(CountOperation* node) {
void AstPrinter::VisitBinaryOperation(BinaryOperation* node) {
- IndentedScope indent(Token::Name(node->op()), node);
+ IndentedScope indent(this, Token::Name(node->op()), node);
Visit(node->left());
Visit(node->right());
}
void AstPrinter::VisitCompareOperation(CompareOperation* node) {
- IndentedScope indent(Token::Name(node->op()), node);
+ IndentedScope indent(this, Token::Name(node->op()), node);
Visit(node->left());
Visit(node->right());
}
@@ -1103,13 +1094,13 @@ void AstPrinter::VisitCompareToNull(CompareToNull* node) {
const char* name = node->is_strict()
? "COMPARE-TO-NULL-STRICT"
: "COMPARE-TO-NULL";
- IndentedScope indent(name, node);
+ IndentedScope indent(this, name, node);
Visit(node->expression());
}
void AstPrinter::VisitThisFunction(ThisFunction* node) {
- IndentedScope indent("THIS-FUNCTION");
+ IndentedScope indent(this, "THIS-FUNCTION");
}
diff --git a/src/prettyprinter.h b/src/prettyprinter.h
index c83de345..284a93f3 100644
--- a/src/prettyprinter.h
+++ b/src/prettyprinter.h
@@ -111,7 +111,7 @@ class AstPrinter: public PrettyPrinter {
void inc_indent() { indent_++; }
void dec_indent() { indent_--; }
- static int indent_;
+ int indent_;
};
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 7612eab9..c9db94f7 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -29,8 +29,8 @@
#include "v8.h"
#include "global-handles.h"
+#include "heap-profiler.h"
#include "scopeinfo.h"
-#include "top.h"
#include "unicode.h"
#include "zone-inl.h"
@@ -47,24 +47,27 @@ TokenEnumerator::TokenEnumerator()
TokenEnumerator::~TokenEnumerator() {
+ Isolate* isolate = Isolate::Current();
for (int i = 0; i < token_locations_.length(); ++i) {
if (!token_removed_[i]) {
- GlobalHandles::ClearWeakness(token_locations_[i]);
- GlobalHandles::Destroy(token_locations_[i]);
+ isolate->global_handles()->ClearWeakness(token_locations_[i]);
+ isolate->global_handles()->Destroy(token_locations_[i]);
}
}
}
int TokenEnumerator::GetTokenId(Object* token) {
+ Isolate* isolate = Isolate::Current();
if (token == NULL) return TokenEnumerator::kNoSecurityToken;
for (int i = 0; i < token_locations_.length(); ++i) {
if (*token_locations_[i] == token && !token_removed_[i]) return i;
}
- Handle<Object> handle = GlobalHandles::Create(token);
+ Handle<Object> handle = isolate->global_handles()->Create(token);
// handle.location() points to a memory cell holding a pointer
// to a token object in the V8's heap.
- GlobalHandles::MakeWeak(handle.location(), this, TokenRemovedCallback);
+ isolate->global_handles()->MakeWeak(handle.location(), this,
+ TokenRemovedCallback);
token_locations_.Add(handle.location());
token_removed_.Add(false);
return token_locations_.length() - 1;
@@ -94,55 +97,74 @@ StringsStorage::StringsStorage()
}
-static void DeleteIndexName(char** name_ptr) {
- DeleteArray(*name_ptr);
-}
-
-
StringsStorage::~StringsStorage() {
for (HashMap::Entry* p = names_.Start();
p != NULL;
p = names_.Next(p)) {
DeleteArray(reinterpret_cast<const char*>(p->value));
}
- index_names_.Iterate(DeleteIndexName);
+}
+
+
+const char* StringsStorage::GetCopy(const char* src) {
+ int len = static_cast<int>(strlen(src));
+ Vector<char> dst = Vector<char>::New(len + 1);
+ OS::StrNCpy(dst, src, len);
+ dst[len] = '\0';
+ uint32_t hash = HashSequentialString(dst.start(), len);
+ return AddOrDisposeString(dst.start(), hash);
+}
+
+
+const char* StringsStorage::GetFormatted(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ const char* result = GetVFormatted(format, args);
+ va_end(args);
+ return result;
+}
+
+
+const char* StringsStorage::AddOrDisposeString(char* str, uint32_t hash) {
+ HashMap::Entry* cache_entry = names_.Lookup(str, hash, true);
+ if (cache_entry->value == NULL) {
+ // New entry added.
+ cache_entry->value = str;
+ } else {
+ DeleteArray(str);
+ }
+ return reinterpret_cast<const char*>(cache_entry->value);
+}
+
+
+const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
+ Vector<char> str = Vector<char>::New(1024);
+ int len = OS::VSNPrintF(str, format, args);
+ if (len == -1) {
+ DeleteArray(str.start());
+ return format;
+ }
+ uint32_t hash = HashSequentialString(str.start(), len);
+ return AddOrDisposeString(str.start(), hash);
}
const char* StringsStorage::GetName(String* name) {
if (name->IsString()) {
- char* c_name =
- name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach();
- HashMap::Entry* cache_entry = names_.Lookup(c_name, name->Hash(), true);
- if (cache_entry->value == NULL) {
- // New entry added.
- cache_entry->value = c_name;
- } else {
- DeleteArray(c_name);
- }
- return reinterpret_cast<const char*>(cache_entry->value);
+ return AddOrDisposeString(
+ name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(),
+ name->Hash());
}
return "";
}
const char* StringsStorage::GetName(int index) {
- ASSERT(index >= 0);
- if (index_names_.length() <= index) {
- index_names_.AddBlock(
- NULL, index - index_names_.length() + 1);
- }
- if (index_names_[index] == NULL) {
- const int kMaximumNameLength = 32;
- char* name = NewArray<char>(kMaximumNameLength);
- OS::SNPrintF(Vector<char>(name, kMaximumNameLength), "%d", index);
- index_names_[index] = name;
- }
- return index_names_[index];
+ return GetFormatted("%d", index);
}
-const char* CodeEntry::kEmptyNamePrefix = "";
+const char* const CodeEntry::kEmptyNamePrefix = "";
void CodeEntry::CopyData(const CodeEntry& source) {
@@ -298,7 +320,7 @@ struct NodesPair {
class FilteredCloneCallback {
public:
- explicit FilteredCloneCallback(ProfileNode* dst_root, int security_token_id)
+ FilteredCloneCallback(ProfileNode* dst_root, int security_token_id)
: stack_(10),
security_token_id_(security_token_id) {
stack_.Add(NodesPair(NULL, dst_root));
@@ -465,7 +487,7 @@ void CpuProfile::Print() {
}
-CodeEntry* const CodeMap::kSfiCodeEntry = NULL;
+CodeEntry* const CodeMap::kSharedFunctionCodeEntry = NULL;
const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL;
const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue =
CodeMap::CodeEntryInfo(NULL, 0);
@@ -483,18 +505,18 @@ CodeEntry* CodeMap::FindEntry(Address addr) {
}
-int CodeMap::GetSFITag(Address addr) {
+int CodeMap::GetSharedId(Address addr) {
CodeTree::Locator locator;
- // For SFI entries, 'size' field is used to store their IDs.
+ // For shared function entries, 'size' field is used to store their IDs.
if (tree_.Find(addr, &locator)) {
const CodeEntryInfo& entry = locator.value();
- ASSERT(entry.entry == kSfiCodeEntry);
+ ASSERT(entry.entry == kSharedFunctionCodeEntry);
return entry.size;
} else {
tree_.Insert(addr, &locator);
- int tag = next_sfi_tag_++;
- locator.set_value(CodeEntryInfo(kSfiCodeEntry, tag));
- return tag;
+ int id = next_shared_id_++;
+ locator.set_value(CodeEntryInfo(kSharedFunctionCodeEntry, id));
+ return id;
}
}
@@ -528,13 +550,16 @@ static void DeleteCpuProfile(CpuProfile** profile_ptr) {
}
static void DeleteProfilesList(List<CpuProfile*>** list_ptr) {
- (*list_ptr)->Iterate(DeleteCpuProfile);
- delete *list_ptr;
+ if (*list_ptr != NULL) {
+ (*list_ptr)->Iterate(DeleteCpuProfile);
+ delete *list_ptr;
+ }
}
CpuProfilesCollection::~CpuProfilesCollection() {
delete current_profiles_semaphore_;
current_profiles_.Iterate(DeleteCpuProfile);
+ detached_profiles_.Iterate(DeleteCpuProfile);
profiles_by_token_.Iterate(DeleteProfilesList);
code_entries_.Iterate(DeleteCodeEntry);
}
@@ -599,15 +624,8 @@ CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id,
unsigned uid) {
- HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid),
- static_cast<uint32_t>(uid),
- false);
- int index;
- if (entry != NULL) {
- index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
- } else {
- return NULL;
- }
+ int index = GetProfileIndex(uid);
+ if (index < 0) return NULL;
List<CpuProfile*>* unabridged_list =
profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
if (security_token_id == TokenEnumerator::kNoSecurityToken) {
@@ -622,6 +640,15 @@ CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id,
}
+int CpuProfilesCollection::GetProfileIndex(unsigned uid) {
+ HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid),
+ static_cast<uint32_t>(uid),
+ false);
+ return entry != NULL ?
+ static_cast<int>(reinterpret_cast<intptr_t>(entry->value)) : -1;
+}
+
+
bool CpuProfilesCollection::IsLastProfile(const char* title) {
// Called from VM thread, and only it can mutate the list,
// so no locking is needed here.
@@ -631,6 +658,39 @@ bool CpuProfilesCollection::IsLastProfile(const char* title) {
}
+void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) {
+ // Called from VM thread for a completed profile.
+ unsigned uid = profile->uid();
+ int index = GetProfileIndex(uid);
+ if (index < 0) {
+ detached_profiles_.RemoveElement(profile);
+ return;
+ }
+ profiles_uids_.Remove(reinterpret_cast<void*>(uid),
+ static_cast<uint32_t>(uid));
+ // Decrement all indexes above the deleted one.
+ for (HashMap::Entry* p = profiles_uids_.Start();
+ p != NULL;
+ p = profiles_uids_.Next(p)) {
+ intptr_t p_index = reinterpret_cast<intptr_t>(p->value);
+ if (p_index > index) {
+ p->value = reinterpret_cast<void*>(p_index - 1);
+ }
+ }
+ for (int i = 0; i < profiles_by_token_.length(); ++i) {
+ List<CpuProfile*>* list = profiles_by_token_[i];
+ if (list != NULL && index < list->length()) {
+ // Move all filtered clones into detached_profiles_,
+ // so we can know that they are still in use.
+ CpuProfile* cloned_profile = list->Remove(index);
+ if (cloned_profile != NULL && cloned_profile != profile) {
+ detached_profiles_.Add(cloned_profile);
+ }
+ }
+ }
+}
+
+
int CpuProfilesCollection::TokenToIndex(int security_token_id) {
ASSERT(TokenEnumerator::kNoSecurityToken == -1);
return security_token_id + 1; // kNoSecurityToken -> 0, 0 -> 1, ...
@@ -763,10 +823,12 @@ void SampleRateCalculator::UpdateMeasurements(double current_time) {
}
-const char* ProfileGenerator::kAnonymousFunctionName = "(anonymous function)";
-const char* ProfileGenerator::kProgramEntryName = "(program)";
-const char* ProfileGenerator::kGarbageCollectorEntryName =
- "(garbage collector)";
+const char* const ProfileGenerator::kAnonymousFunctionName =
+ "(anonymous function)";
+const char* const ProfileGenerator::kProgramEntryName =
+ "(program)";
+const char* const ProfileGenerator::kGarbageCollectorEntryName =
+ "(garbage collector)";
ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
@@ -789,7 +851,15 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
if (sample.pc != NULL) {
*entry++ = code_map_.FindEntry(sample.pc);
- if (sample.tos != NULL) {
+ if (sample.has_external_callback) {
+ // Don't use PC when in external callback code, as it can point
+ // inside callback's code, and we will erroneously report
+ // that a callback calls itself.
+ *(entries.start()) = NULL;
+ *entry++ = code_map_.FindEntry(sample.external_callback);
+ } else if (sample.tos != NULL) {
+ // Find out, if top of stack was pointing inside a JS function
+ // meaning that we have encountered a frameless invocation.
*entry = code_map_.FindEntry(sample.tos);
if (*entry != NULL && !(*entry)->is_js_function()) {
*entry = NULL;
@@ -914,11 +984,6 @@ int HeapEntry::RetainedSize(bool exact) {
}
-List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() {
- return snapshot_->GetRetainingPaths(this);
-}
-
-
template<class Visitor>
void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) {
List<HeapEntry*> list(10);
@@ -1009,6 +1074,7 @@ const char* HeapEntry::TypeAsString() {
case kArray: return "/array/";
case kRegExp: return "/regexp/";
case kHeapNumber: return "/number/";
+ case kNative: return "/native/";
default: return "???";
}
}
@@ -1076,107 +1142,6 @@ void HeapEntry::CalculateExactRetainedSize() {
}
-class CachedHeapGraphPath {
- public:
- CachedHeapGraphPath()
- : nodes_(NodesMatch) { }
- CachedHeapGraphPath(const CachedHeapGraphPath& src)
- : nodes_(NodesMatch, &HashMap::DefaultAllocator, src.nodes_.capacity()),
- path_(src.path_.length() + 1) {
- for (HashMap::Entry* p = src.nodes_.Start();
- p != NULL;
- p = src.nodes_.Next(p)) {
- nodes_.Lookup(p->key, p->hash, true);
- }
- path_.AddAll(src.path_);
- }
- void Add(HeapGraphEdge* edge) {
- nodes_.Lookup(edge->to(), Hash(edge->to()), true);
- path_.Add(edge);
- }
- bool ContainsNode(HeapEntry* node) {
- return nodes_.Lookup(node, Hash(node), false) != NULL;
- }
- const List<HeapGraphEdge*>* path() const { return &path_; }
-
- private:
- static uint32_t Hash(HeapEntry* entry) {
- return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry));
- }
- static bool NodesMatch(void* key1, void* key2) { return key1 == key2; }
-
- HashMap nodes_;
- List<HeapGraphEdge*> path_;
-};
-
-
-List<HeapGraphPath*>* HeapEntry::CalculateRetainingPaths() {
- List<HeapGraphPath*>* retaining_paths = new List<HeapGraphPath*>(4);
- CachedHeapGraphPath path;
- FindRetainingPaths(&path, retaining_paths);
- return retaining_paths;
-}
-
-
-void HeapEntry::FindRetainingPaths(CachedHeapGraphPath* prev_path,
- List<HeapGraphPath*>* retaining_paths) {
- Vector<HeapGraphEdge*> rets = retainers();
- for (int i = 0; i < rets.length(); ++i) {
- HeapGraphEdge* ret_edge = rets[i];
- if (prev_path->ContainsNode(ret_edge->From())) continue;
- if (ret_edge->From() != snapshot()->root()) {
- CachedHeapGraphPath path(*prev_path);
- path.Add(ret_edge);
- ret_edge->From()->FindRetainingPaths(&path, retaining_paths);
- } else {
- HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path());
- ret_path->Set(0, ret_edge);
- retaining_paths->Add(ret_path);
- }
- }
-}
-
-
-HeapGraphPath::HeapGraphPath(const List<HeapGraphEdge*>& path)
- : path_(path.length() + 1) {
- Add(NULL);
- for (int i = path.length() - 1; i >= 0; --i) {
- Add(path[i]);
- }
-}
-
-
-void HeapGraphPath::Print() {
- path_[0]->From()->Print(1, 0);
- for (int i = 0; i < path_.length(); ++i) {
- OS::Print(" -> ");
- HeapGraphEdge* edge = path_[i];
- switch (edge->type()) {
- case HeapGraphEdge::kContextVariable:
- OS::Print("[#%s] ", edge->name());
- break;
- case HeapGraphEdge::kElement:
- case HeapGraphEdge::kHidden:
- OS::Print("[%d] ", edge->index());
- break;
- case HeapGraphEdge::kInternal:
- OS::Print("[$%s] ", edge->name());
- break;
- case HeapGraphEdge::kProperty:
- OS::Print("[%s] ", edge->name());
- break;
- case HeapGraphEdge::kShortcut:
- OS::Print("[^%s] ", edge->name());
- break;
- default:
- OS::Print("!!! unknown edge type: %d ", edge->type());
- }
- edge->to()->Print(1, 0);
- }
- OS::Print("\n");
-}
-
-
// It is very important to keep objects that form a heap snapshot
// as small as possible.
namespace { // Avoid littering the global namespace.
@@ -1205,9 +1170,9 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
uid_(uid),
root_entry_(NULL),
gc_roots_entry_(NULL),
+ natives_root_entry_(NULL),
raw_entries_(NULL),
- entries_sorted_(false),
- retaining_paths_(HeapEntry::Match) {
+ entries_sorted_(false) {
STATIC_ASSERT(
sizeof(HeapGraphEdge) ==
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize); // NOLINT
@@ -1216,21 +1181,14 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT
}
-
-static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) {
- delete *path_ptr;
-}
-
HeapSnapshot::~HeapSnapshot() {
DeleteArray(raw_entries_);
- for (HashMap::Entry* p = retaining_paths_.Start();
- p != NULL;
- p = retaining_paths_.Next(p)) {
- List<HeapGraphPath*>* list =
- reinterpret_cast<List<HeapGraphPath*>*>(p->value);
- list->Iterate(DeleteHeapGraphPath);
- delete list;
- }
+}
+
+
+void HeapSnapshot::Delete() {
+ collection_->RemoveSnapshot(this);
+ delete this;
}
@@ -1279,6 +1237,19 @@ HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count,
}
+HeapEntry* HeapSnapshot::AddNativesRootEntry(int children_count,
+ int retainers_count) {
+ ASSERT(natives_root_entry_ == NULL);
+ return (natives_root_entry_ = AddEntry(
+ HeapEntry::kObject,
+ "(Native objects)",
+ HeapObjectsMap::kNativesRootObjectId,
+ 0,
+ children_count,
+ retainers_count));
+}
+
+
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
const char* name,
uint64_t id,
@@ -1313,14 +1284,7 @@ HeapEntry* HeapSnapshot::GetNextEntryToInit() {
}
-HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) {
- return collection_->CompareSnapshots(this, snapshot);
-}
-
-
HeapEntry* HeapSnapshot::GetEntryById(uint64_t id) {
- // GetSortedEntriesList is used in diff algorithm and sorts
- // entries by their id.
List<HeapEntry*>* entries_by_id = GetSortedEntriesList();
// Perform a binary search by id.
@@ -1341,16 +1305,6 @@ HeapEntry* HeapSnapshot::GetEntryById(uint64_t id) {
}
-List<HeapGraphPath*>* HeapSnapshot::GetRetainingPaths(HeapEntry* entry) {
- HashMap::Entry* p =
- retaining_paths_.Lookup(entry, HeapEntry::Hash(entry), true);
- if (p->value == NULL) {
- p->value = entry->CalculateRetainingPaths();
- }
- return reinterpret_cast<List<HeapGraphPath*>*>(p->value);
-}
-
-
template<class T>
static int SortByIds(const T* entry1_ptr,
const T* entry2_ptr) {
@@ -1372,10 +1326,13 @@ void HeapSnapshot::Print(int max_depth) {
}
-const uint64_t HeapObjectsMap::kInternalRootObjectId = 0;
-const uint64_t HeapObjectsMap::kGcRootsObjectId = 1;
+// We split IDs on evens for embedder objects (see
+// HeapObjectsMap::GenerateId) and odds for native objects.
+const uint64_t HeapObjectsMap::kInternalRootObjectId = 1;
+const uint64_t HeapObjectsMap::kGcRootsObjectId = 3;
+const uint64_t HeapObjectsMap::kNativesRootObjectId = 5;
// Increase kFirstAvailableObjectId if new 'special' objects appear.
-const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 2;
+const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 7;
HeapObjectsMap::HeapObjectsMap()
: initial_fill_mode_(true),
@@ -1400,7 +1357,8 @@ uint64_t HeapObjectsMap::FindObject(Address addr) {
uint64_t existing = FindEntry(addr);
if (existing != 0) return existing;
}
- uint64_t id = next_id_++;
+ uint64_t id = next_id_;
+ next_id_ += 2;
AddEntry(addr, id);
return id;
}
@@ -1468,6 +1426,17 @@ void HeapObjectsMap::RemoveDeadEntries() {
}
+uint64_t HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
+ uint64_t id = static_cast<uint64_t>(info->GetHash());
+ const char* label = info->GetLabel();
+ id ^= HashSequentialString(label, static_cast<int>(strlen(label)));
+ intptr_t element_count = info->GetElementCount();
+ if (element_count != -1)
+ id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count));
+ return id << 1;
+}
+
+
HeapSnapshotsCollection::HeapSnapshotsCollection()
: is_tracking_objects_(false),
snapshots_uids_(HeapSnapshotsMatch),
@@ -1517,10 +1486,11 @@ HeapSnapshot* HeapSnapshotsCollection::GetSnapshot(unsigned uid) {
}
-HeapSnapshotsDiff* HeapSnapshotsCollection::CompareSnapshots(
- HeapSnapshot* snapshot1,
- HeapSnapshot* snapshot2) {
- return comparator_.Compare(snapshot1, snapshot2);
+void HeapSnapshotsCollection::RemoveSnapshot(HeapSnapshot* snapshot) {
+ snapshots_.RemoveElement(snapshot);
+ unsigned uid = snapshot->uid();
+ snapshots_uids_.Remove(reinterpret_cast<void*>(uid),
+ static_cast<uint32_t>(uid));
}
@@ -1551,6 +1521,8 @@ void HeapEntriesMap::AllocateEntries() {
p->key,
entry_info->children_count,
entry_info->retainers_count);
+ ASSERT(entry_info->entry != NULL);
+ ASSERT(entry_info->entry != kHeapEntryPlaceholder);
entry_info->children_count = 0;
entry_info->retainers_count = 0;
}
@@ -1630,9 +1602,11 @@ void HeapObjectsSet::Insert(Object* obj) {
HeapObject *const V8HeapExplorer::kInternalRootObject =
- reinterpret_cast<HeapObject*>(1);
+ reinterpret_cast<HeapObject*>(
+ static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId));
HeapObject *const V8HeapExplorer::kGcRootsObject =
- reinterpret_cast<HeapObject*>(2);
+ reinterpret_cast<HeapObject*>(
+ static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId));
V8HeapExplorer::V8HeapExplorer(
@@ -1669,27 +1643,28 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
SharedFunctionInfo* shared = func->shared();
return AddEntry(object,
HeapEntry::kClosure,
- collection_->GetName(String::cast(shared->name())),
+ collection_->names()->GetName(String::cast(shared->name())),
children_count,
retainers_count);
} else if (object->IsJSRegExp()) {
JSRegExp* re = JSRegExp::cast(object);
return AddEntry(object,
HeapEntry::kRegExp,
- collection_->GetName(re->Pattern()),
+ collection_->names()->GetName(re->Pattern()),
children_count,
retainers_count);
} else if (object->IsJSObject()) {
return AddEntry(object,
HeapEntry::kObject,
- collection_->GetName(GetConstructorNameForHeapProfile(
- JSObject::cast(object))),
+ collection_->names()->GetName(
+ GetConstructorNameForHeapProfile(
+ JSObject::cast(object))),
children_count,
retainers_count);
} else if (object->IsString()) {
return AddEntry(object,
HeapEntry::kString,
- collection_->GetName(String::cast(object)),
+ collection_->names()->GetName(String::cast(object)),
children_count,
retainers_count);
} else if (object->IsCode()) {
@@ -1702,7 +1677,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
SharedFunctionInfo* shared = SharedFunctionInfo::cast(object);
return AddEntry(object,
HeapEntry::kCode,
- collection_->GetName(String::cast(shared->name())),
+ collection_->names()->GetName(String::cast(shared->name())),
children_count,
retainers_count);
} else if (object->IsScript()) {
@@ -1710,7 +1685,9 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
return AddEntry(object,
HeapEntry::kCode,
script->name()->IsString() ?
- collection_->GetName(String::cast(script->name())) : "",
+ collection_->names()->GetName(
+ String::cast(script->name()))
+ : "",
children_count,
retainers_count);
} else if (object->IsFixedArray()) {
@@ -1749,8 +1726,8 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
- filler->AddEntry(kInternalRootObject);
- filler->AddEntry(kGcRootsObject);
+ filler->AddEntry(kInternalRootObject, this);
+ filler->AddEntry(kGcRootsObject, this);
}
@@ -1769,25 +1746,40 @@ class IndexedReferencesExtractor : public ObjectVisitor {
IndexedReferencesExtractor(V8HeapExplorer* generator,
HeapObject* parent_obj,
HeapEntry* parent_entry,
- HeapObjectsSet* known_references = NULL)
+ bool process_field_marks = false)
: generator_(generator),
parent_obj_(parent_obj),
parent_(parent_entry),
- known_references_(known_references),
+ process_field_marks_(process_field_marks),
next_index_(1) {
}
void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) {
- if (!known_references_ || !known_references_->Contains(*p)) {
- generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p);
- }
+ if (CheckVisitedAndUnmark(p)) continue;
+ generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p);
}
}
+ static void MarkVisitedField(HeapObject* obj, int offset) {
+ if (offset < 0) return;
+ Address field = obj->address() + offset;
+ ASSERT(!Memory::Object_at(field)->IsFailure());
+ ASSERT(Memory::Object_at(field)->IsHeapObject());
+ *field |= kFailureTag;
+ }
private:
+ bool CheckVisitedAndUnmark(Object** field) {
+ if (process_field_marks_ && (*field)->IsFailure()) {
+ intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask;
+ *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag);
+ ASSERT((*field)->IsHeapObject());
+ return true;
+ }
+ return false;
+ }
V8HeapExplorer* generator_;
HeapObject* parent_obj_;
HeapEntry* parent_;
- HeapObjectsSet* known_references_;
+ bool process_field_marks_;
int next_index_;
};
@@ -1796,7 +1788,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
HeapEntry* entry = GetEntry(obj);
if (entry == NULL) return; // No interest in this object.
- known_references_.Clear();
if (obj->IsJSGlobalProxy()) {
// We need to reference JS global objects from snapshot's root.
// We use JSGlobalProxy because this is what embedder (e.g. browser)
@@ -1812,16 +1803,28 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
ExtractElementReferences(js_obj, entry);
ExtractInternalReferences(js_obj, entry);
SetPropertyReference(
- obj, entry, Heap::Proto_symbol(), js_obj->GetPrototype());
+ obj, entry, HEAP->Proto_symbol(), js_obj->GetPrototype());
if (obj->IsJSFunction()) {
- JSFunction* js_fun = JSFunction::cast(obj);
- if (js_fun->has_prototype()) {
- SetPropertyReference(
- obj, entry, Heap::prototype_symbol(), js_fun->prototype());
+ JSFunction* js_fun = JSFunction::cast(js_obj);
+ SetInternalReference(
+ js_fun, entry,
+ "code", js_fun->shared(),
+ JSFunction::kSharedFunctionInfoOffset);
+ Object* proto_or_map = js_fun->prototype_or_initial_map();
+ if (!proto_or_map->IsTheHole()) {
+ if (!proto_or_map->IsMap()) {
+ SetPropertyReference(
+ obj, entry,
+ HEAP->prototype_symbol(), proto_or_map,
+ JSFunction::kPrototypeOrInitialMapOffset);
+ } else {
+ SetPropertyReference(
+ obj, entry,
+ HEAP->prototype_symbol(), js_fun->prototype());
+ }
}
}
- IndexedReferencesExtractor refs_extractor(
- this, obj, entry, &known_references_);
+ IndexedReferencesExtractor refs_extractor(this, obj, entry, true);
obj->Iterate(&refs_extractor);
} else if (obj->IsString()) {
if (obj->IsConsString()) {
@@ -1854,7 +1857,6 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
SetClosureReference(js_obj, entry, local_name, context->get(idx));
}
}
- SetInternalReference(js_obj, entry, "code", func->shared());
}
}
@@ -1867,13 +1869,22 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
switch (descs->GetType(i)) {
case FIELD: {
int index = descs->GetFieldIndex(i);
- SetPropertyReference(
- js_obj, entry, descs->GetKey(i), js_obj->FastPropertyAt(index));
+ if (index < js_obj->map()->inobject_properties()) {
+ SetPropertyReference(
+ js_obj, entry,
+ descs->GetKey(i), js_obj->InObjectPropertyAt(index),
+ js_obj->GetInObjectPropertyOffset(index));
+ } else {
+ SetPropertyReference(
+ js_obj, entry,
+ descs->GetKey(i), js_obj->FastPropertyAt(index));
+ }
break;
}
case CONSTANT_FUNCTION:
SetPropertyReference(
- js_obj, entry, descs->GetKey(i), descs->GetConstantFunction(i));
+ js_obj, entry,
+ descs->GetKey(i), descs->GetConstantFunction(i));
break;
default: ;
}
@@ -1933,14 +1944,15 @@ void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
int length = js_obj->GetInternalFieldCount();
for (int i = 0; i < length; ++i) {
Object* o = js_obj->GetInternalField(i);
- SetInternalReference(js_obj, entry, i, o);
+ SetInternalReference(
+ js_obj, entry, i, o, js_obj->GetInternalFieldOffset(i));
}
}
HeapEntry* V8HeapExplorer::GetEntry(Object* obj) {
if (!obj->IsHeapObject()) return NULL;
- return filler_->FindOrAddEntry(obj);
+ return filler_->FindOrAddEntry(obj, this);
}
@@ -1977,7 +1989,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(
}
SetRootGcRootsReference();
RootsReferencesExtractor extractor(this);
- Heap::IterateRoots(&extractor, VISIT_ALL);
+ HEAP->IterateRoots(&extractor, VISIT_ALL);
filler_ = NULL;
return progress_->ProgressReport(false);
}
@@ -1992,10 +2004,9 @@ void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj,
filler_->SetNamedReference(HeapGraphEdge::kContextVariable,
parent_obj,
parent_entry,
- collection_->GetName(reference_name),
+ collection_->names()->GetName(reference_name),
child_obj,
child_entry);
- known_references_.Insert(child_obj);
}
}
@@ -2012,7 +2023,6 @@ void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
index,
child_obj,
child_entry);
- known_references_.Insert(child_obj);
}
}
@@ -2020,7 +2030,8 @@ void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
const char* reference_name,
- Object* child_obj) {
+ Object* child_obj,
+ int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kInternal,
@@ -2029,7 +2040,7 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
reference_name,
child_obj,
child_entry);
- known_references_.Insert(child_obj);
+ IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
}
@@ -2037,16 +2048,17 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int index,
- Object* child_obj) {
+ Object* child_obj,
+ int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kInternal,
parent_obj,
parent_entry,
- collection_->GetName(index),
+ collection_->names()->GetName(index),
child_obj,
child_entry);
- known_references_.Insert(child_obj);
+ IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
}
@@ -2070,7 +2082,8 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
String* reference_name,
- Object* child_obj) {
+ Object* child_obj,
+ int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
HeapGraphEdge::Type type = reference_name->length() > 0 ?
@@ -2078,25 +2091,24 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
filler_->SetNamedReference(type,
parent_obj,
parent_entry,
- collection_->GetName(reference_name),
+ collection_->names()->GetName(reference_name),
child_obj,
child_entry);
- known_references_.Insert(child_obj);
+ IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
}
-void V8HeapExplorer::SetPropertyShortcutReference(
- HeapObject* parent_obj,
- HeapEntry* parent_entry,
- String* reference_name,
- Object* child_obj) {
+void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj,
+ HeapEntry* parent_entry,
+ String* reference_name,
+ Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kShortcut,
parent_obj,
parent_entry,
- collection_->GetName(reference_name),
+ collection_->names()->GetName(reference_name),
child_obj,
child_entry);
}
@@ -2132,25 +2144,217 @@ void V8HeapExplorer::SetGcRootsReference(Object* child_obj) {
}
+class GlobalHandlesExtractor : public ObjectVisitor {
+ public:
+ explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer)
+ : explorer_(explorer) {}
+ virtual ~GlobalHandlesExtractor() {}
+ virtual void VisitPointers(Object** start, Object** end) {
+ UNREACHABLE();
+ }
+ virtual void VisitEmbedderReference(Object** p, uint16_t class_id) {
+ explorer_->VisitSubtreeWrapper(p, class_id);
+ }
+ private:
+ NativeObjectsExplorer* explorer_;
+};
+
+HeapThing const NativeObjectsExplorer::kNativesRootObject =
+ reinterpret_cast<HeapThing>(
+ static_cast<intptr_t>(HeapObjectsMap::kNativesRootObjectId));
+
+
+NativeObjectsExplorer::NativeObjectsExplorer(
+ HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress)
+ : snapshot_(snapshot),
+ collection_(snapshot_->collection()),
+ progress_(progress),
+ embedder_queried_(false),
+ objects_by_info_(RetainedInfosMatch),
+ filler_(NULL) {
+}
+
+
+NativeObjectsExplorer::~NativeObjectsExplorer() {
+ for (HashMap::Entry* p = objects_by_info_.Start();
+ p != NULL;
+ p = objects_by_info_.Next(p)) {
+ v8::RetainedObjectInfo* info =
+ reinterpret_cast<v8::RetainedObjectInfo*>(p->key);
+ info->Dispose();
+ List<HeapObject*>* objects =
+ reinterpret_cast<List<HeapObject*>* >(p->value);
+ delete objects;
+ }
+}
+
+
+HeapEntry* NativeObjectsExplorer::AllocateEntry(
+ HeapThing ptr, int children_count, int retainers_count) {
+ if (ptr == kNativesRootObject) {
+ return snapshot_->AddNativesRootEntry(children_count, retainers_count);
+ } else {
+ v8::RetainedObjectInfo* info =
+ reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
+ intptr_t elements = info->GetElementCount();
+ intptr_t size = info->GetSizeInBytes();
+ return snapshot_->AddEntry(
+ HeapEntry::kNative,
+ elements != -1 ?
+ collection_->names()->GetFormatted(
+ "%s / %" V8_PTR_PREFIX "d entries",
+ info->GetLabel(),
+ info->GetElementCount()) :
+ collection_->names()->GetCopy(info->GetLabel()),
+ HeapObjectsMap::GenerateId(info),
+ size != -1 ? static_cast<int>(size) : 0,
+ children_count,
+ retainers_count);
+ }
+}
+
+
+void NativeObjectsExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
+ if (EstimateObjectsCount() <= 0) return;
+ filler->AddEntry(kNativesRootObject, this);
+}
+
+
+int NativeObjectsExplorer::EstimateObjectsCount() {
+ FillRetainedObjects();
+ return objects_by_info_.occupancy();
+}
+
+
+void NativeObjectsExplorer::FillRetainedObjects() {
+ if (embedder_queried_) return;
+ Isolate* isolate = Isolate::Current();
+ // Record objects that are joined into ObjectGroups.
+ isolate->heap()->CallGlobalGCPrologueCallback();
+ List<ObjectGroup*>* groups = isolate->global_handles()->object_groups();
+ for (int i = 0; i < groups->length(); ++i) {
+ ObjectGroup* group = groups->at(i);
+ if (group->info_ == NULL) continue;
+ List<HeapObject*>* list = GetListMaybeDisposeInfo(group->info_);
+ for (int j = 0; j < group->objects_.length(); ++j) {
+ HeapObject* obj = HeapObject::cast(*group->objects_[j]);
+ list->Add(obj);
+ in_groups_.Insert(obj);
+ }
+ group->info_ = NULL; // Acquire info object ownership.
+ }
+ isolate->global_handles()->RemoveObjectGroups();
+ isolate->heap()->CallGlobalGCEpilogueCallback();
+ // Record objects that are not in ObjectGroups, but have class ID.
+ GlobalHandlesExtractor extractor(this);
+ isolate->global_handles()->IterateAllRootsWithClassIds(&extractor);
+ embedder_queried_ = true;
+}
+
+
+List<HeapObject*>* NativeObjectsExplorer::GetListMaybeDisposeInfo(
+ v8::RetainedObjectInfo* info) {
+ HashMap::Entry* entry =
+ objects_by_info_.Lookup(info, InfoHash(info), true);
+ if (entry->value != NULL) {
+ info->Dispose();
+ } else {
+ entry->value = new List<HeapObject*>(4);
+ }
+ return reinterpret_cast<List<HeapObject*>* >(entry->value);
+}
+
+
+bool NativeObjectsExplorer::IterateAndExtractReferences(
+ SnapshotFillerInterface* filler) {
+ if (EstimateObjectsCount() <= 0) return true;
+ filler_ = filler;
+ FillRetainedObjects();
+ for (HashMap::Entry* p = objects_by_info_.Start();
+ p != NULL;
+ p = objects_by_info_.Next(p)) {
+ v8::RetainedObjectInfo* info =
+ reinterpret_cast<v8::RetainedObjectInfo*>(p->key);
+ SetNativeRootReference(info);
+ List<HeapObject*>* objects =
+ reinterpret_cast<List<HeapObject*>* >(p->value);
+ for (int i = 0; i < objects->length(); ++i) {
+ SetWrapperNativeReferences(objects->at(i), info);
+ }
+ }
+ SetRootNativesRootReference();
+ filler_ = NULL;
+ return true;
+}
+
+
+void NativeObjectsExplorer::SetNativeRootReference(
+ v8::RetainedObjectInfo* info) {
+ HeapEntry* child_entry = filler_->FindOrAddEntry(info, this);
+ ASSERT(child_entry != NULL);
+ filler_->SetIndexedAutoIndexReference(
+ HeapGraphEdge::kElement,
+ kNativesRootObject, snapshot_->natives_root(),
+ info, child_entry);
+}
+
+
+void NativeObjectsExplorer::SetWrapperNativeReferences(
+ HeapObject* wrapper, v8::RetainedObjectInfo* info) {
+ HeapEntry* wrapper_entry = filler_->FindEntry(wrapper);
+ ASSERT(wrapper_entry != NULL);
+ HeapEntry* info_entry = filler_->FindOrAddEntry(info, this);
+ ASSERT(info_entry != NULL);
+ filler_->SetNamedReference(HeapGraphEdge::kInternal,
+ wrapper, wrapper_entry,
+ "Native",
+ info, info_entry);
+ filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
+ info, info_entry,
+ wrapper, wrapper_entry);
+}
+
+
+void NativeObjectsExplorer::SetRootNativesRootReference() {
+ filler_->SetIndexedAutoIndexReference(
+ HeapGraphEdge::kElement,
+ V8HeapExplorer::kInternalRootObject, snapshot_->root(),
+ kNativesRootObject, snapshot_->natives_root());
+}
+
+
+void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) {
+ if (in_groups_.Contains(*p)) return;
+ Isolate* isolate = Isolate::Current();
+ v8::RetainedObjectInfo* info =
+ isolate->heap_profiler()->ExecuteWrapperClassCallback(class_id, p);
+ if (info == NULL) return;
+ GetListMaybeDisposeInfo(info)->Add(HeapObject::cast(*p));
+}
+
+
HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot,
v8::ActivityControl* control)
: snapshot_(snapshot),
control_(control),
- v8_heap_explorer_(snapshot_, this) {
+ v8_heap_explorer_(snapshot_, this),
+ dom_explorer_(snapshot_, this) {
}
class SnapshotCounter : public SnapshotFillerInterface {
public:
- SnapshotCounter(HeapEntriesAllocator* allocator, HeapEntriesMap* entries)
- : allocator_(allocator), entries_(entries) { }
- HeapEntry* AddEntry(HeapThing ptr) {
- entries_->Pair(ptr, allocator_, HeapEntriesMap::kHeapEntryPlaceholder);
+ explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { }
+ HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
+ entries_->Pair(ptr, allocator, HeapEntriesMap::kHeapEntryPlaceholder);
return HeapEntriesMap::kHeapEntryPlaceholder;
}
- HeapEntry* FindOrAddEntry(HeapThing ptr) {
- HeapEntry* entry = entries_->Map(ptr);
- return entry != NULL ? entry : AddEntry(ptr);
+ HeapEntry* FindEntry(HeapThing ptr) {
+ return entries_->Map(ptr);
+ }
+ HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
+ HeapEntry* entry = FindEntry(ptr);
+ return entry != NULL ? entry : AddEntry(ptr, allocator);
}
void SetIndexedReference(HeapGraphEdge::Type,
HeapThing parent_ptr,
@@ -2183,7 +2387,6 @@ class SnapshotCounter : public SnapshotFillerInterface {
entries_->CountReference(parent_ptr, child_ptr);
}
private:
- HeapEntriesAllocator* allocator_;
HeapEntriesMap* entries_;
};
@@ -2194,13 +2397,16 @@ class SnapshotFiller : public SnapshotFillerInterface {
: snapshot_(snapshot),
collection_(snapshot->collection()),
entries_(entries) { }
- HeapEntry* AddEntry(HeapThing ptr) {
+ HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
UNREACHABLE();
return NULL;
}
- HeapEntry* FindOrAddEntry(HeapThing ptr) {
- HeapEntry* entry = entries_->Map(ptr);
- return entry != NULL ? entry : AddEntry(ptr);
+ HeapEntry* FindEntry(HeapThing ptr) {
+ return entries_->Map(ptr);
+ }
+ HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
+ HeapEntry* entry = FindEntry(ptr);
+ return entry != NULL ? entry : AddEntry(ptr, allocator);
}
void SetIndexedReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
@@ -2247,7 +2453,7 @@ class SnapshotFiller : public SnapshotFillerInterface {
parent_ptr, child_ptr, &child_index, &retainer_index);
parent_entry->SetNamedReference(type,
child_index,
- collection_->GetName(child_index + 1),
+ collection_->names()->GetName(child_index + 1),
child_entry,
retainer_index);
}
@@ -2303,21 +2509,28 @@ bool HeapSnapshotGenerator::ProgressReport(bool force) {
void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
if (control_ == NULL) return;
- progress_total_ = v8_heap_explorer_.EstimateObjectsCount() * iterations_count;
+ progress_total_ = (
+ v8_heap_explorer_.EstimateObjectsCount() +
+ dom_explorer_.EstimateObjectsCount()) * iterations_count;
progress_counter_ = 0;
}
bool HeapSnapshotGenerator::CountEntriesAndReferences() {
- SnapshotCounter counter(&v8_heap_explorer_, &entries_);
+ SnapshotCounter counter(&entries_);
v8_heap_explorer_.AddRootEntries(&counter);
- return v8_heap_explorer_.IterateAndExtractReferences(&counter);
+ dom_explorer_.AddRootEntries(&counter);
+ return
+ v8_heap_explorer_.IterateAndExtractReferences(&counter) &&
+ dom_explorer_.IterateAndExtractReferences(&counter);
}
bool HeapSnapshotGenerator::FillReferences() {
SnapshotFiller filler(snapshot_, &entries_);
- return v8_heap_explorer_.IterateAndExtractReferences(&filler);
+ return
+ v8_heap_explorer_.IterateAndExtractReferences(&filler) &&
+ dom_explorer_.IterateAndExtractReferences(&filler);
}
@@ -2447,83 +2660,6 @@ bool HeapSnapshotGenerator::ApproximateRetainedSizes() {
}
-void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) {
- raw_additions_root_ =
- NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0));
- additions_root()->Init(
- snapshot2_, HeapEntry::kHidden, "", 0, 0, additions_count, 0);
- raw_deletions_root_ =
- NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0));
- deletions_root()->Init(
- snapshot1_, HeapEntry::kHidden, "", 0, 0, deletions_count, 0);
-}
-
-
-static void DeleteHeapSnapshotsDiff(HeapSnapshotsDiff** diff_ptr) {
- delete *diff_ptr;
-}
-
-HeapSnapshotsComparator::~HeapSnapshotsComparator() {
- diffs_.Iterate(DeleteHeapSnapshotsDiff);
-}
-
-
-HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1,
- HeapSnapshot* snapshot2) {
- snapshot1->ClearPaint();
- snapshot1->root()->PaintAllReachable();
- snapshot2->ClearPaint();
- snapshot2->root()->PaintAllReachable();
-
- List<HeapEntry*>* entries1 = snapshot1->GetSortedEntriesList();
- List<HeapEntry*>* entries2 = snapshot2->GetSortedEntriesList();
- int i = 0, j = 0;
- List<HeapEntry*> added_entries, deleted_entries;
- while (i < entries1->length() && j < entries2->length()) {
- uint64_t id1 = entries1->at(i)->id();
- uint64_t id2 = entries2->at(j)->id();
- if (id1 == id2) {
- HeapEntry* entry1 = entries1->at(i++);
- HeapEntry* entry2 = entries2->at(j++);
- if (entry1->painted_reachable() != entry2->painted_reachable()) {
- if (entry1->painted_reachable())
- deleted_entries.Add(entry1);
- else
- added_entries.Add(entry2);
- }
- } else if (id1 < id2) {
- HeapEntry* entry = entries1->at(i++);
- deleted_entries.Add(entry);
- } else {
- HeapEntry* entry = entries2->at(j++);
- added_entries.Add(entry);
- }
- }
- while (i < entries1->length()) {
- HeapEntry* entry = entries1->at(i++);
- deleted_entries.Add(entry);
- }
- while (j < entries2->length()) {
- HeapEntry* entry = entries2->at(j++);
- added_entries.Add(entry);
- }
-
- HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2);
- diffs_.Add(diff);
- diff->CreateRoots(added_entries.length(), deleted_entries.length());
-
- for (int i = 0; i < deleted_entries.length(); ++i) {
- HeapEntry* entry = deleted_entries[i];
- diff->AddDeletedEntry(i, i + 1, entry);
- }
- for (int i = 0; i < added_entries.length(); ++i) {
- HeapEntry* entry = added_entries[i];
- diff->AddAddedEntry(i, i + 1, entry);
- }
- return diff;
-}
-
-
class OutputStreamWriter {
public:
explicit OutputStreamWriter(v8::OutputStream* stream)
@@ -2735,7 +2871,8 @@ void HeapSnapshotJSONSerializer::SerializeNodes() {
"," JSON_S("code")
"," JSON_S("closure")
"," JSON_S("regexp")
- "," JSON_S("number"))
+ "," JSON_S("number")
+ "," JSON_S("native"))
"," JSON_S("string")
"," JSON_S("number")
"," JSON_S("number")
@@ -2890,7 +3027,7 @@ void HeapSnapshotJSONSerializer::SortHashMap(
String* GetConstructorNameForHeapProfile(JSObject* object) {
- if (object->IsJSFunction()) return Heap::closure_symbol();
+ if (object->IsJSFunction()) return HEAP->closure_symbol();
return object->constructor_name();
}
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 4762eb63..377c083c 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -66,6 +66,9 @@ class StringsStorage {
StringsStorage();
~StringsStorage();
+ const char* GetCopy(const char* src);
+ const char* GetFormatted(const char* format, ...);
+ const char* GetVFormatted(const char* format, va_list args);
const char* GetName(String* name);
const char* GetName(int index);
inline const char* GetFunctionName(String* name);
@@ -76,11 +79,10 @@ class StringsStorage {
return strcmp(reinterpret_cast<char*>(key1),
reinterpret_cast<char*>(key2)) == 0;
}
+ const char* AddOrDisposeString(char* str, uint32_t hash);
// Mapping of strings by String::Hash to const char* strings.
HashMap names_;
- // Mapping from ints to char* strings.
- List<char*> index_names_;
DISALLOW_COPY_AND_ASSIGN(StringsStorage);
};
@@ -112,7 +114,7 @@ class CodeEntry {
uint32_t GetCallUid() const;
bool IsSameAs(CodeEntry* entry) const;
- static const char* kEmptyNamePrefix;
+ static const char* const kEmptyNamePrefix;
private:
Logger::LogEventsAndTags tag_;
@@ -236,12 +238,12 @@ class CpuProfile {
class CodeMap {
public:
- CodeMap() : next_sfi_tag_(1) { }
+ CodeMap() : next_shared_id_(1) { }
INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
INLINE(void MoveCode(Address from, Address to));
INLINE(void DeleteCode(Address addr));
CodeEntry* FindEntry(Address addr);
- int GetSFITag(Address addr);
+ int GetSharedId(Address addr);
void Print();
@@ -269,11 +271,11 @@ class CodeMap {
void Call(const Address& key, const CodeEntryInfo& value);
};
- // Fake CodeEntry pointer to distinguish SFI entries.
- static CodeEntry* const kSfiCodeEntry;
+ // Fake CodeEntry pointer to distinguish shared function entries.
+ static CodeEntry* const kSharedFunctionCodeEntry;
CodeTree tree_;
- int next_sfi_tag_;
+ int next_shared_id_;
DISALLOW_COPY_AND_ASSIGN(CodeMap);
};
@@ -298,6 +300,8 @@ class CpuProfilesCollection {
}
CpuProfile* GetProfile(int security_token_id, unsigned uid);
bool IsLastProfile(const char* title);
+ void RemoveProfile(CpuProfile* profile);
+ bool HasDetachedProfiles() { return detached_profiles_.length() > 0; }
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
String* name, String* resource_name, int line_number);
@@ -320,6 +324,7 @@ class CpuProfilesCollection {
const char* GetFunctionName(const char* name) {
return function_and_resource_names_.GetFunctionName(name);
}
+ int GetProfileIndex(unsigned uid);
List<CpuProfile*>* GetProfilesList(int security_token_id);
int TokenToIndex(int security_token_id);
@@ -333,6 +338,7 @@ class CpuProfilesCollection {
// Mapping from profiles' uids to indexes in the second nested list
// of profiles_by_token_.
HashMap profiles_uids_;
+ List<CpuProfile*> detached_profiles_;
// Accessed by VM thread and profile generator thread.
List<CpuProfile*> current_profiles_;
@@ -420,9 +426,9 @@ class ProfileGenerator {
return sample_rate_calc_.ticks_per_ms();
}
- static const char* kAnonymousFunctionName;
- static const char* kProgramEntryName;
- static const char* kGarbageCollectorEntryName;
+ static const char* const kAnonymousFunctionName;
+ static const char* const kProgramEntryName;
+ static const char* const kGarbageCollectorEntryName;
private:
INLINE(CodeEntry* EntryForVMState(StateTag tag));
@@ -484,8 +490,6 @@ class HeapGraphEdge BASE_EMBEDDED {
};
-class CachedHeapGraphPath;
-class HeapGraphPath;
class HeapSnapshot;
// HeapEntry instances represent an entity from the heap (or a special
@@ -517,7 +521,8 @@ class HeapEntry BASE_EMBEDDED {
kCode = v8::HeapGraphNode::kCode,
kClosure = v8::HeapGraphNode::kClosure,
kRegExp = v8::HeapGraphNode::kRegExp,
- kHeapNumber = v8::HeapGraphNode::kHeapNumber
+ kHeapNumber = v8::HeapGraphNode::kHeapNumber,
+ kNative = v8::HeapGraphNode::kNative
};
HeapEntry() { }
@@ -544,7 +549,6 @@ class HeapEntry BASE_EMBEDDED {
return Vector<HeapGraphEdge>(children_arr(), children_count_); }
Vector<HeapGraphEdge*> retainers() {
return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); }
- List<HeapGraphPath*>* GetRetainingPaths();
HeapEntry* dominator() { return dominator_; }
void set_dominator(HeapEntry* entry) { dominator_ = entry; }
@@ -578,18 +582,12 @@ class HeapEntry BASE_EMBEDDED {
int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); }
int RetainedSize(bool exact);
- List<HeapGraphPath*>* CalculateRetainingPaths();
void Print(int max_depth, int indent);
static int EntriesSize(int entries_count,
int children_count,
int retainers_count);
- static uint32_t Hash(HeapEntry* entry) {
- return ComputeIntegerHash(
- static_cast<uint32_t>(reinterpret_cast<uintptr_t>(entry)));
- }
- static bool Match(void* entry1, void* entry2) { return entry1 == entry2; }
private:
HeapGraphEdge* children_arr() {
@@ -599,13 +597,11 @@ class HeapEntry BASE_EMBEDDED {
return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
}
void CalculateExactRetainedSize();
- void FindRetainingPaths(CachedHeapGraphPath* prev_path,
- List<HeapGraphPath*>* retaining_paths);
const char* TypeAsString();
unsigned painted_: 2;
- unsigned type_: 3;
- int children_count_: 27;
+ unsigned type_: 4;
+ int children_count_: 26;
int retainers_count_;
int self_size_;
union {
@@ -631,27 +627,7 @@ class HeapEntry BASE_EMBEDDED {
};
-class HeapGraphPath {
- public:
- HeapGraphPath()
- : path_(8) { }
- explicit HeapGraphPath(const List<HeapGraphEdge*>& path);
-
- void Add(HeapGraphEdge* edge) { path_.Add(edge); }
- void Set(int index, HeapGraphEdge* edge) { path_[index] = edge; }
- const List<HeapGraphEdge*>* path() { return &path_; }
-
- void Print();
-
- private:
- List<HeapGraphEdge*> path_;
-
- DISALLOW_COPY_AND_ASSIGN(HeapGraphPath);
-};
-
-
class HeapSnapshotsCollection;
-class HeapSnapshotsDiff;
// HeapSnapshot represents a single heap snapshot. It is stored in
// HeapSnapshotsCollection, which is also a factory for
@@ -670,6 +646,7 @@ class HeapSnapshot {
const char* title,
unsigned uid);
~HeapSnapshot();
+ void Delete();
HeapSnapshotsCollection* collection() { return collection_; }
Type type() { return type_; }
@@ -677,6 +654,7 @@ class HeapSnapshot {
unsigned uid() { return uid_; }
HeapEntry* root() { return root_entry_; }
HeapEntry* gc_roots() { return gc_roots_entry_; }
+ HeapEntry* natives_root() { return natives_root_entry_; }
List<HeapEntry*>* entries() { return &entries_; }
void AllocateEntries(
@@ -689,10 +667,9 @@ class HeapSnapshot {
int retainers_count);
HeapEntry* AddRootEntry(int children_count);
HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
+ HeapEntry* AddNativesRootEntry(int children_count, int retainers_count);
void ClearPaint();
- HeapSnapshotsDiff* CompareWith(HeapSnapshot* snapshot);
HeapEntry* GetEntryById(uint64_t id);
- List<HeapGraphPath*>* GetRetainingPaths(HeapEntry* entry);
List<HeapEntry*>* GetSortedEntriesList();
template<class Visitor>
void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); }
@@ -710,10 +687,10 @@ class HeapSnapshot {
unsigned uid_;
HeapEntry* root_entry_;
HeapEntry* gc_roots_entry_;
+ HeapEntry* natives_root_entry_;
char* raw_entries_;
List<HeapEntry*> entries_;
bool entries_sorted_;
- HashMap retaining_paths_;
#ifdef DEBUG
int raw_entries_size_;
#endif
@@ -733,8 +710,11 @@ class HeapObjectsMap {
uint64_t FindObject(Address addr);
void MoveObject(Address from, Address to);
+ static uint64_t GenerateId(v8::RetainedObjectInfo* info);
+
static const uint64_t kInternalRootObjectId;
static const uint64_t kGcRootsObjectId;
+ static const uint64_t kNativesRootObjectId;
static const uint64_t kFirstAvailableObjectId;
private:
@@ -767,58 +747,6 @@ class HeapObjectsMap {
};
-class HeapSnapshotsDiff {
- public:
- HeapSnapshotsDiff(HeapSnapshot* snapshot1, HeapSnapshot* snapshot2)
- : snapshot1_(snapshot1),
- snapshot2_(snapshot2),
- raw_additions_root_(NULL),
- raw_deletions_root_(NULL) { }
-
- ~HeapSnapshotsDiff() {
- DeleteArray(raw_deletions_root_);
- DeleteArray(raw_additions_root_);
- }
-
- void AddAddedEntry(int child_index, int index, HeapEntry* entry) {
- additions_root()->SetUnidirElementReference(child_index, index, entry);
- }
-
- void AddDeletedEntry(int child_index, int index, HeapEntry* entry) {
- deletions_root()->SetUnidirElementReference(child_index, index, entry);
- }
-
- void CreateRoots(int additions_count, int deletions_count);
-
- HeapEntry* additions_root() {
- return reinterpret_cast<HeapEntry*>(raw_additions_root_);
- }
- HeapEntry* deletions_root() {
- return reinterpret_cast<HeapEntry*>(raw_deletions_root_);
- }
-
- private:
- HeapSnapshot* snapshot1_;
- HeapSnapshot* snapshot2_;
- char* raw_additions_root_;
- char* raw_deletions_root_;
-
- DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsDiff);
-};
-
-
-class HeapSnapshotsComparator {
- public:
- HeapSnapshotsComparator() { }
- ~HeapSnapshotsComparator();
- HeapSnapshotsDiff* Compare(HeapSnapshot* snapshot1, HeapSnapshot* snapshot2);
- private:
- List<HeapSnapshotsDiff*> diffs_;
-
- DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsComparator);
-};
-
-
class HeapSnapshotsCollection {
public:
HeapSnapshotsCollection();
@@ -831,21 +759,14 @@ class HeapSnapshotsCollection {
void SnapshotGenerationFinished(HeapSnapshot* snapshot);
List<HeapSnapshot*>* snapshots() { return &snapshots_; }
HeapSnapshot* GetSnapshot(unsigned uid);
+ void RemoveSnapshot(HeapSnapshot* snapshot);
- const char* GetName(String* name) { return names_.GetName(name); }
- const char* GetName(int index) { return names_.GetName(index); }
- const char* GetFunctionName(String* name) {
- return names_.GetFunctionName(name);
- }
-
+ StringsStorage* names() { return &names_; }
TokenEnumerator* token_enumerator() { return token_enumerator_; }
uint64_t GetObjectId(Address addr) { return ids_.FindObject(addr); }
void ObjectMoveEvent(Address from, Address to) { ids_.MoveObject(from, to); }
- HeapSnapshotsDiff* CompareSnapshots(HeapSnapshot* snapshot1,
- HeapSnapshot* snapshot2);
-
private:
INLINE(static bool HeapSnapshotsMatch(void* key1, void* key2)) {
return key1 == key2;
@@ -859,7 +780,6 @@ class HeapSnapshotsCollection {
TokenEnumerator* token_enumerator_;
// Mapping from HeapObject addresses to objects' uids.
HeapObjectsMap ids_;
- HeapSnapshotsComparator comparator_;
DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsCollection);
};
@@ -950,8 +870,11 @@ class HeapObjectsSet {
class SnapshotFillerInterface {
public:
virtual ~SnapshotFillerInterface() { }
- virtual HeapEntry* AddEntry(HeapThing ptr) = 0;
- virtual HeapEntry* FindOrAddEntry(HeapThing ptr) = 0;
+ virtual HeapEntry* AddEntry(HeapThing ptr,
+ HeapEntriesAllocator* allocator) = 0;
+ virtual HeapEntry* FindEntry(HeapThing ptr) = 0;
+ virtual HeapEntry* FindOrAddEntry(HeapThing ptr,
+ HeapEntriesAllocator* allocator) = 0;
virtual void SetIndexedReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
@@ -990,13 +913,15 @@ class V8HeapExplorer : public HeapEntriesAllocator {
public:
V8HeapExplorer(HeapSnapshot* snapshot,
SnapshottingProgressReportingInterface* progress);
- ~V8HeapExplorer();
+ virtual ~V8HeapExplorer();
virtual HeapEntry* AllocateEntry(
HeapThing ptr, int children_count, int retainers_count);
void AddRootEntries(SnapshotFillerInterface* filler);
int EstimateObjectsCount();
bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
+ static HeapObject* const kInternalRootObject;
+
private:
HeapEntry* AddEntry(
HeapObject* object, int children_count, int retainers_count);
@@ -1021,11 +946,13 @@ class V8HeapExplorer : public HeapEntriesAllocator {
void SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent,
const char* reference_name,
- Object* child);
+ Object* child,
+ int field_offset = -1);
void SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent,
int index,
- Object* child);
+ Object* child,
+ int field_offset = -1);
void SetHiddenReference(HeapObject* parent_obj,
HeapEntry* parent,
int index,
@@ -1033,7 +960,8 @@ class V8HeapExplorer : public HeapEntriesAllocator {
void SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent,
String* reference_name,
- Object* child);
+ Object* child,
+ int field_offset = -1);
void SetPropertyShortcutReference(HeapObject* parent_obj,
HeapEntry* parent,
String* reference_name,
@@ -1047,12 +975,8 @@ class V8HeapExplorer : public HeapEntriesAllocator {
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
SnapshottingProgressReportingInterface* progress_;
- // Used during references extraction to mark heap objects that
- // are references via non-hidden properties.
- HeapObjectsSet known_references_;
SnapshotFillerInterface* filler_;
- static HeapObject* const kInternalRootObject;
static HeapObject* const kGcRootsObject;
friend class IndexedReferencesExtractor;
@@ -1062,6 +986,54 @@ class V8HeapExplorer : public HeapEntriesAllocator {
};
+// An implementation of retained native objects extractor.
+class NativeObjectsExplorer : public HeapEntriesAllocator {
+ public:
+ NativeObjectsExplorer(HeapSnapshot* snapshot,
+ SnapshottingProgressReportingInterface* progress);
+ virtual ~NativeObjectsExplorer();
+ virtual HeapEntry* AllocateEntry(
+ HeapThing ptr, int children_count, int retainers_count);
+ void AddRootEntries(SnapshotFillerInterface* filler);
+ int EstimateObjectsCount();
+ bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
+
+ private:
+ void FillRetainedObjects();
+ List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
+ void SetNativeRootReference(v8::RetainedObjectInfo* info);
+ void SetRootNativesRootReference();
+ void SetWrapperNativeReferences(HeapObject* wrapper,
+ v8::RetainedObjectInfo* info);
+ void VisitSubtreeWrapper(Object** p, uint16_t class_id);
+
+ static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
+ return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()));
+ }
+ static bool RetainedInfosMatch(void* key1, void* key2) {
+ return key1 == key2 ||
+ (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
+ reinterpret_cast<v8::RetainedObjectInfo*>(key2));
+ }
+
+ HeapSnapshot* snapshot_;
+ HeapSnapshotsCollection* collection_;
+ SnapshottingProgressReportingInterface* progress_;
+ bool embedder_queried_;
+ HeapObjectsSet in_groups_;
+ // RetainedObjectInfo* -> List<HeapObject*>*
+ HashMap objects_by_info_;
+ // Used during references extraction.
+ SnapshotFillerInterface* filler_;
+
+ static HeapThing const kNativesRootObject;
+
+ friend class GlobalHandlesExtractor;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
+};
+
+
class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
public:
HeapSnapshotGenerator(HeapSnapshot* snapshot,
@@ -1083,6 +1055,7 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
HeapSnapshot* snapshot_;
v8::ActivityControl* control_;
V8HeapExplorer v8_heap_explorer_;
+ NativeObjectsExplorer dom_explorer_;
// Mapping from HeapThing pointers to HeapEntry* pointers.
HeapEntriesMap entries_;
// Used during snapshot generation.
diff --git a/src/property.cc b/src/property.cc
index 96774333..c35fb834 100644
--- a/src/property.cc
+++ b/src/property.cc
@@ -52,6 +52,12 @@ void LookupResult::Print(FILE* out) {
GetTransitionMap()->Print(out);
PrintF(out, "\n");
break;
+ case EXTERNAL_ARRAY_TRANSITION:
+ PrintF(out, " -type = external array transition\n");
+ PrintF(out, " -map:\n");
+ GetTransitionMap()->Print(out);
+ PrintF(out, "\n");
+ break;
case CONSTANT_FUNCTION:
PrintF(out, " -type = constant function\n");
PrintF(out, " -function:\n");
diff --git a/src/property.h b/src/property.h
index c39fe41e..fa3916eb 100644
--- a/src/property.h
+++ b/src/property.h
@@ -48,7 +48,7 @@ class Descriptor BASE_EMBEDDED {
MUST_USE_RESULT MaybeObject* KeyToSymbol() {
if (!StringShape(key_).IsSymbol()) {
Object* result;
- { MaybeObject* maybe_result = Heap::LookupSymbol(key_);
+ { MaybeObject* maybe_result = HEAP->LookupSymbol(key_);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
key_ = String::cast(result);
@@ -110,6 +110,16 @@ class MapTransitionDescriptor: public Descriptor {
: Descriptor(key, map, attributes, MAP_TRANSITION) { }
};
+class ExternalArrayTransitionDescriptor: public Descriptor {
+ public:
+ ExternalArrayTransitionDescriptor(String* key,
+ Map* map,
+ ExternalArrayType array_type)
+ : Descriptor(key, map, PropertyDetails(NONE,
+ EXTERNAL_ARRAY_TRANSITION,
+ array_type)) { }
+};
+
// Marks a field name in a map so that adding the field is guaranteed
// to create a FIELD descriptor in the new map. Used after adding
// a constant function the first time, creating a CONSTANT_FUNCTION
@@ -262,7 +272,8 @@ class LookupResult BASE_EMBEDDED {
Map* GetTransitionMap() {
ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
- ASSERT(type() == MAP_TRANSITION || type() == CONSTANT_TRANSITION);
+ ASSERT(type() == MAP_TRANSITION || type() == CONSTANT_TRANSITION ||
+ type() == EXTERNAL_ARRAY_TRANSITION);
return Map::cast(GetValue());
}
@@ -305,7 +316,7 @@ class LookupResult BASE_EMBEDDED {
Object* GetCallbackObject() {
if (lookup_type_ == CONSTANT_TYPE) {
// For now we only have the __proto__ as constant type.
- return Heap::prototype_accessors();
+ return HEAP->prototype_accessors();
}
return GetValue();
}
diff --git a/src/regexp-macro-assembler-irregexp.cc b/src/regexp-macro-assembler-irregexp.cc
index 6fbb14ad..d41a97ca 100644
--- a/src/regexp-macro-assembler-irregexp.cc
+++ b/src/regexp-macro-assembler-irregexp.cc
@@ -438,7 +438,7 @@ void RegExpMacroAssemblerIrregexp::IfRegisterEqPos(int register_index,
Handle<Object> RegExpMacroAssemblerIrregexp::GetCode(Handle<String> source) {
Bind(&backtrack_);
Emit(BC_POP_BT, 0);
- Handle<ByteArray> array = Factory::NewByteArray(length());
+ Handle<ByteArray> array = FACTORY->NewByteArray(length());
Copy(array->GetDataStartAddress());
return array;
}
diff --git a/src/regexp-macro-assembler.cc b/src/regexp-macro-assembler.cc
index 51f4015f..ea41db63 100644
--- a/src/regexp-macro-assembler.cc
+++ b/src/regexp-macro-assembler.cc
@@ -105,7 +105,8 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match(
Handle<String> subject,
int* offsets_vector,
int offsets_vector_length,
- int previous_index) {
+ int previous_index,
+ Isolate* isolate) {
ASSERT(subject->IsFlat());
ASSERT(previous_index >= 0);
@@ -142,7 +143,8 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match(
start_offset,
input_start,
input_end,
- offsets_vector);
+ offsets_vector,
+ isolate);
return res;
}
@@ -153,10 +155,12 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute(
int start_offset,
const byte* input_start,
const byte* input_end,
- int* output) {
+ int* output,
+ Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
// Ensure that the minimum stack has been allocated.
- RegExpStack stack;
- Address stack_base = RegExpStack::stack_base();
+ RegExpStackScope stack_scope(isolate);
+ Address stack_base = stack_scope.stack()->stack_base();
int direct_call = 0;
int result = CALL_GENERATED_REGEXP_CODE(code->entry(),
@@ -166,23 +170,21 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute(
input_end,
output,
stack_base,
- direct_call);
+ direct_call,
+ isolate);
ASSERT(result <= SUCCESS);
ASSERT(result >= RETRY);
- if (result == EXCEPTION && !Top::has_pending_exception()) {
+ if (result == EXCEPTION && !isolate->has_pending_exception()) {
// We detected a stack overflow (on the backtrack stack) in RegExp code,
// but haven't created the exception yet.
- Top::StackOverflow();
+ isolate->StackOverflow();
}
return static_cast<Result>(result);
}
-static unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
-
-
-byte NativeRegExpMacroAssembler::word_character_map[] = {
+const byte NativeRegExpMacroAssembler::word_character_map[] = {
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
@@ -208,7 +210,11 @@ byte NativeRegExpMacroAssembler::word_character_map[] = {
int NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16(
Address byte_offset1,
Address byte_offset2,
- size_t byte_length) {
+ size_t byte_length,
+ Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ unibrow::Mapping<unibrow::Ecma262Canonicalize>* canonicalize =
+ isolate->regexp_macro_assembler_canonicalize();
// This function is not allowed to cause a garbage collection.
// A GC might move the calling generated code and invalidate the
// return address on the stack.
@@ -222,10 +228,10 @@ int NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16(
unibrow::uchar c2 = substring2[i];
if (c1 != c2) {
unibrow::uchar s1[1] = { c1 };
- canonicalize.get(c1, '\0', s1);
+ canonicalize->get(c1, '\0', s1);
if (s1[0] != c2) {
unibrow::uchar s2[1] = { c2 };
- canonicalize.get(c2, '\0', s2);
+ canonicalize->get(c2, '\0', s2);
if (s1[0] != s2[0]) {
return 0;
}
@@ -237,13 +243,16 @@ int NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16(
Address NativeRegExpMacroAssembler::GrowStack(Address stack_pointer,
- Address* stack_base) {
- size_t size = RegExpStack::stack_capacity();
- Address old_stack_base = RegExpStack::stack_base();
+ Address* stack_base,
+ Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ RegExpStack* regexp_stack = isolate->regexp_stack();
+ size_t size = regexp_stack->stack_capacity();
+ Address old_stack_base = regexp_stack->stack_base();
ASSERT(old_stack_base == *stack_base);
ASSERT(stack_pointer <= old_stack_base);
ASSERT(static_cast<size_t>(old_stack_base - stack_pointer) <= size);
- Address new_stack_base = RegExpStack::EnsureCapacity(size * 2);
+ Address new_stack_base = regexp_stack->EnsureCapacity(size * 2);
if (new_stack_base == NULL) {
return NULL;
}
diff --git a/src/regexp-macro-assembler.h b/src/regexp-macro-assembler.h
index ef85d27e..1268e783 100644
--- a/src/regexp-macro-assembler.h
+++ b/src/regexp-macro-assembler.h
@@ -48,6 +48,7 @@ class RegExpMacroAssembler {
enum IrregexpImplementation {
kIA32Implementation,
kARMImplementation,
+ kMIPSImplementation,
kX64Implementation,
kBytecodeImplementation
};
@@ -190,30 +191,33 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
Handle<String> subject,
int* offsets_vector,
int offsets_vector_length,
- int previous_index);
+ int previous_index,
+ Isolate* isolate);
// Compares two-byte strings case insensitively.
// Called from generated RegExp code.
static int CaseInsensitiveCompareUC16(Address byte_offset1,
Address byte_offset2,
- size_t byte_length);
+ size_t byte_length,
+ Isolate* isolate);
// Called from RegExp if the backtrack stack limit is hit.
// Tries to expand the stack. Returns the new stack-pointer if
// successful, and updates the stack_top address, or returns 0 if unable
// to grow the stack.
// This function must not trigger a garbage collection.
- static Address GrowStack(Address stack_pointer, Address* stack_top);
+ static Address GrowStack(Address stack_pointer, Address* stack_top,
+ Isolate* isolate);
static const byte* StringCharacterPosition(String* subject, int start_index);
// Byte map of ASCII characters with a 0xff if the character is a word
// character (digit, letter or underscore) and 0x00 otherwise.
// Used by generated RegExp code.
- static byte word_character_map[128];
+ static const byte word_character_map[128];
static Address word_character_map_address() {
- return &word_character_map[0];
+ return const_cast<Address>(&word_character_map[0]);
}
static Result Execute(Code* code,
@@ -221,7 +225,8 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
int start_offset,
const byte* input_start,
const byte* input_end,
- int* output);
+ int* output,
+ Isolate* isolate);
};
#endif // V8_INTERPRETED_REGEXP
diff --git a/src/regexp-stack.cc b/src/regexp-stack.cc
index 7696279a..ff9547f3 100644
--- a/src/regexp-stack.cc
+++ b/src/regexp-stack.cc
@@ -26,21 +26,31 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "v8.h"
-#include "top.h"
#include "regexp-stack.h"
namespace v8 {
namespace internal {
-RegExpStack::RegExpStack() {
+RegExpStackScope::RegExpStackScope(Isolate* isolate)
+ : regexp_stack_(isolate->regexp_stack()) {
// Initialize, if not already initialized.
- RegExpStack::EnsureCapacity(0);
+ regexp_stack_->EnsureCapacity(0);
}
-RegExpStack::~RegExpStack() {
+RegExpStackScope::~RegExpStackScope() {
+ ASSERT(Isolate::Current() == regexp_stack_->isolate_);
// Reset the buffer if it has grown.
- RegExpStack::Reset();
+ regexp_stack_->Reset();
+}
+
+
+RegExpStack::RegExpStack()
+ : isolate_(NULL) {
+}
+
+
+RegExpStack::~RegExpStack() {
}
@@ -70,9 +80,9 @@ void RegExpStack::Reset() {
void RegExpStack::ThreadLocal::Free() {
- if (thread_local_.memory_size_ > 0) {
- DeleteArray(thread_local_.memory_);
- thread_local_ = ThreadLocal();
+ if (memory_size_ > 0) {
+ DeleteArray(memory_);
+ Clear();
}
}
@@ -98,6 +108,4 @@ Address RegExpStack::EnsureCapacity(size_t size) {
}
-RegExpStack::ThreadLocal RegExpStack::thread_local_;
-
}} // namespace v8::internal
diff --git a/src/regexp-stack.h b/src/regexp-stack.h
index b4fa2e92..59432067 100644
--- a/src/regexp-stack.h
+++ b/src/regexp-stack.h
@@ -31,11 +31,30 @@
namespace v8 {
namespace internal {
+class RegExpStack;
+
// Maintains a per-v8thread stack area that can be used by irregexp
// implementation for its backtracking stack.
// Since there is only one stack area, the Irregexp implementation is not
// re-entrant. I.e., no regular expressions may be executed in the same thread
// during a preempted Irregexp execution.
+class RegExpStackScope {
+ public:
+ // Create and delete an instance to control the life-time of a growing stack.
+
+ // Initializes the stack memory area if necessary.
+ explicit RegExpStackScope(Isolate* isolate);
+ ~RegExpStackScope(); // Releases the stack if it has grown.
+
+ RegExpStack* stack() const { return regexp_stack_; }
+
+ private:
+ RegExpStack* regexp_stack_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegExpStackScope);
+};
+
+
class RegExpStack {
public:
// Number of allocated locations on the stack below the limit.
@@ -43,39 +62,37 @@ class RegExpStack {
// check.
static const int kStackLimitSlack = 32;
- // Create and delete an instance to control the life-time of a growing stack.
- RegExpStack(); // Initializes the stack memory area if necessary.
- ~RegExpStack(); // Releases the stack if it has grown.
-
// Gives the top of the memory used as stack.
- static Address stack_base() {
+ Address stack_base() {
ASSERT(thread_local_.memory_size_ != 0);
return thread_local_.memory_ + thread_local_.memory_size_;
}
// The total size of the memory allocated for the stack.
- static size_t stack_capacity() { return thread_local_.memory_size_; }
+ size_t stack_capacity() { return thread_local_.memory_size_; }
// If the stack pointer gets below the limit, we should react and
// either grow the stack or report an out-of-stack exception.
// There is only a limited number of locations below the stack limit,
// so users of the stack should check the stack limit during any
// sequence of pushes longer that this.
- static Address* limit_address() { return &(thread_local_.limit_); }
+ Address* limit_address() { return &(thread_local_.limit_); }
// Ensures that there is a memory area with at least the specified size.
// If passing zero, the default/minimum size buffer is allocated.
- static Address EnsureCapacity(size_t size);
+ Address EnsureCapacity(size_t size);
// Thread local archiving.
static int ArchiveSpacePerThread() {
- return static_cast<int>(sizeof(thread_local_));
+ return static_cast<int>(sizeof(ThreadLocal));
}
- static char* ArchiveStack(char* to);
- static char* RestoreStack(char* from);
- static void FreeThreadResources() { thread_local_.Free(); }
-
+ char* ArchiveStack(char* to);
+ char* RestoreStack(char* from);
+ void FreeThreadResources() { thread_local_.Free(); }
private:
+ RegExpStack();
+ ~RegExpStack();
+
// Artificial limit used when no memory has been allocated.
static const uintptr_t kMemoryTop = static_cast<uintptr_t>(-1);
@@ -87,35 +104,42 @@ class RegExpStack {
// Structure holding the allocated memory, size and limit.
struct ThreadLocal {
- ThreadLocal()
- : memory_(NULL),
- memory_size_(0),
- limit_(reinterpret_cast<Address>(kMemoryTop)) {}
+ ThreadLocal() { Clear(); }
// If memory_size_ > 0 then memory_ must be non-NULL.
Address memory_;
size_t memory_size_;
Address limit_;
+ void Clear() {
+ memory_ = NULL;
+ memory_size_ = 0;
+ limit_ = reinterpret_cast<Address>(kMemoryTop);
+ }
void Free();
};
// Address of allocated memory.
- static Address memory_address() {
+ Address memory_address() {
return reinterpret_cast<Address>(&thread_local_.memory_);
}
// Address of size of allocated memory.
- static Address memory_size_address() {
+ Address memory_size_address() {
return reinterpret_cast<Address>(&thread_local_.memory_size_);
}
// Resets the buffer if it has grown beyond the default/minimum size.
// After this, the buffer is either the default size, or it is empty, so
// you have to call EnsureCapacity before using it again.
- static void Reset();
+ void Reset();
- static ThreadLocal thread_local_;
+ ThreadLocal thread_local_;
+ Isolate* isolate_;
friend class ExternalReference;
+ friend class Isolate;
+ friend class RegExpStackScope;
+
+ DISALLOW_COPY_AND_ASSIGN(RegExpStack);
};
}} // namespace v8::internal
diff --git a/src/register-allocator-inl.h b/src/register-allocator-inl.h
index e0ea9e18..5a68ab0c 100644
--- a/src/register-allocator-inl.h
+++ b/src/register-allocator-inl.h
@@ -63,14 +63,14 @@ Result& Result::operator=(const Result& other) {
Result::~Result() {
if (is_register()) {
- CodeGeneratorScope::Current()->allocator()->Unuse(reg());
+ CodeGeneratorScope::Current(Isolate::Current())->allocator()->Unuse(reg());
}
}
void Result::Unuse() {
if (is_register()) {
- CodeGeneratorScope::Current()->allocator()->Unuse(reg());
+ CodeGeneratorScope::Current(Isolate::Current())->allocator()->Unuse(reg());
}
invalidate();
}
@@ -79,7 +79,7 @@ void Result::Unuse() {
void Result::CopyTo(Result* destination) const {
destination->value_ = value_;
if (is_register()) {
- CodeGeneratorScope::Current()->allocator()->Use(reg());
+ CodeGeneratorScope::Current(Isolate::Current())->allocator()->Use(reg());
}
}
diff --git a/src/register-allocator.cc b/src/register-allocator.cc
index 31d0a49f..cb5e35fe 100644
--- a/src/register-allocator.cc
+++ b/src/register-allocator.cc
@@ -40,19 +40,13 @@ namespace internal {
Result::Result(Register reg, TypeInfo info) {
ASSERT(reg.is_valid() && !RegisterAllocator::IsReserved(reg));
- CodeGeneratorScope::Current()->allocator()->Use(reg);
+ CodeGeneratorScope::Current(Isolate::Current())->allocator()->Use(reg);
value_ = TypeField::encode(REGISTER)
| TypeInfoField::encode(info.ToInt())
| DataField::encode(reg.code_);
}
-Result::ZoneObjectList* Result::ConstantList() {
- static ZoneObjectList list(10);
- return &list;
-}
-
-
// -------------------------------------------------------------------------
// RegisterAllocator implementation.
diff --git a/src/register-allocator.h b/src/register-allocator.h
index a03a9d2f..f0ef9c32 100644
--- a/src/register-allocator.h
+++ b/src/register-allocator.h
@@ -69,12 +69,13 @@ class Result BASE_EMBEDDED {
// Construct a Result whose value is a compile-time constant.
explicit Result(Handle<Object> value) {
+ ZoneObjectList* constant_list = Isolate::Current()->result_constant_list();
TypeInfo info = TypeInfo::TypeFromValue(value);
value_ = TypeField::encode(CONSTANT)
| TypeInfoField::encode(info.ToInt())
| IsUntaggedInt32Field::encode(false)
- | DataField::encode(ConstantList()->length());
- ConstantList()->Add(value);
+ | DataField::encode(constant_list->length());
+ constant_list->Add(value);
}
// The copy constructor and assignment operators could each create a new
@@ -85,18 +86,6 @@ class Result BASE_EMBEDDED {
inline ~Result();
- // Static indirection table for handles to constants. If a Result
- // represents a constant, the data contains an index into this table
- // of handles to the actual constants.
- typedef ZoneList<Handle<Object> > ZoneObjectList;
-
- static ZoneObjectList* ConstantList();
-
- // Clear the constants indirection table.
- static void ClearConstantList() {
- ConstantList()->Clear();
- }
-
inline void Unuse();
Type type() const { return TypeField::decode(value_); }
@@ -137,7 +126,8 @@ class Result BASE_EMBEDDED {
Handle<Object> handle() const {
ASSERT(type() == CONSTANT);
- return ConstantList()->at(DataField::decode(value_));
+ return Isolate::Current()->result_constant_list()->
+ at(DataField::decode(value_));
}
// Move this result to an arbitrary register. The register is not
diff --git a/src/rewriter.cc b/src/rewriter.cc
index fd40cdc3..780314d9 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -989,7 +989,8 @@ bool Rewriter::Rewrite(CompilationInfo* info) {
ZoneList<Statement*>* body = function->body();
if (!body->is_empty()) {
- Variable* result = scope->NewTemporary(Factory::result_symbol());
+ Variable* result = scope->NewTemporary(
+ info->isolate()->factory()->result_symbol());
Processor processor(result);
processor.Process(body);
if (processor.HasStackOverflow()) return false;
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index df6471e9..c6e2b465 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -36,8 +36,8 @@
#include "execution.h"
#include "global-handles.h"
#include "mark-compact.h"
+#include "platform.h"
#include "scopeinfo.h"
-#include "top.h"
namespace v8 {
namespace internal {
@@ -69,16 +69,9 @@ class PendingListNode : public Malloced {
};
-enum SamplerState {
- IN_NON_JS_STATE = 0,
- IN_JS_STATE = 1
-};
-
-
// Optimization sampler constants.
static const int kSamplerFrameCount = 2;
static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
-static const int kSamplerWindowSize = 16;
static const int kSamplerTicksBetweenThresholdAdjustment = 32;
@@ -92,34 +85,19 @@ static const int kSamplerThresholdSizeFactorDelta = 1;
static const int kSizeLimit = 1500;
-static int sampler_threshold = kSamplerThresholdInit;
-static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
-
-static int sampler_ticks_until_threshold_adjustment =
- kSamplerTicksBetweenThresholdAdjustment;
-
-// The ratio of ticks spent in JS code in percent.
-static Atomic32 js_ratio;
-
-static Object* sampler_window[kSamplerWindowSize] = { NULL, };
-static int sampler_window_position = 0;
-static int sampler_window_weight[kSamplerWindowSize] = { 0, };
-
-
-// Support for pending 'optimize soon' requests.
-static PendingListNode* optimize_soon_list = NULL;
-
PendingListNode::PendingListNode(JSFunction* function) : next_(NULL) {
- function_ = GlobalHandles::Create(function);
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
+ function_ = global_handles->Create(function);
start_ = OS::Ticks();
- GlobalHandles::MakeWeak(function_.location(), this, &WeakCallback);
+ global_handles->MakeWeak(function_.location(), this, &WeakCallback);
}
void PendingListNode::Destroy() {
if (!IsValid()) return;
- GlobalHandles::Destroy(function_.location());
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
+ global_handles->Destroy(function_.location());
function_= Handle<Object>::null();
}
@@ -135,7 +113,37 @@ static bool IsOptimizable(JSFunction* function) {
}
-static void Optimize(JSFunction* function, bool eager, int delay) {
+Atomic32 RuntimeProfiler::state_ = 0;
+// TODO(isolates): Create the semaphore lazily and clean it up when no
+// longer required.
+#ifdef ENABLE_LOGGING_AND_PROFILING
+Semaphore* RuntimeProfiler::semaphore_ = OS::CreateSemaphore(0);
+#endif
+
+
+RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
+ : isolate_(isolate),
+ sampler_threshold_(kSamplerThresholdInit),
+ sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit),
+ sampler_ticks_until_threshold_adjustment_(
+ kSamplerTicksBetweenThresholdAdjustment),
+ js_ratio_(0),
+ sampler_window_position_(0),
+ optimize_soon_list_(NULL),
+ state_window_position_(0) {
+ state_counts_[0] = kStateWindowSize;
+ state_counts_[1] = 0;
+ memset(state_window_, 0, sizeof(state_window_));
+ ClearSampleBuffer();
+}
+
+
+bool RuntimeProfiler::IsEnabled() {
+ return V8::UseCrankshaft() && FLAG_opt;
+}
+
+
+void RuntimeProfiler::Optimize(JSFunction* function, bool eager, int delay) {
ASSERT(IsOptimizable(function));
if (FLAG_trace_opt) {
PrintF("[marking (%s) ", eager ? "eagerly" : "lazily");
@@ -152,11 +160,13 @@ static void Optimize(JSFunction* function, bool eager, int delay) {
}
-static void AttemptOnStackReplacement(JSFunction* function) {
+void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) {
// See AlwaysFullCompiler (in compiler.cc) comment on why we need
// Debug::has_break_points().
ASSERT(function->IsMarkedForLazyRecompilation());
- if (!FLAG_use_osr || Debug::has_break_points() || function->IsBuiltin()) {
+ if (!FLAG_use_osr ||
+ isolate_->debug()->has_break_points() ||
+ function->IsBuiltin()) {
return;
}
@@ -186,7 +196,8 @@ static void AttemptOnStackReplacement(JSFunction* function) {
Object* check_code;
MaybeObject* maybe_check_code = check_stub.TryGetCode();
if (maybe_check_code->ToObject(&check_code)) {
- Code* replacement_code = Builtins::builtin(Builtins::OnStackReplacement);
+ Code* replacement_code =
+ isolate_->builtins()->builtin(Builtins::kOnStackReplacement);
Code* unoptimized_code = shared->code();
Deoptimizer::PatchStackCheckCode(unoptimized_code,
Code::cast(check_code),
@@ -195,21 +206,19 @@ static void AttemptOnStackReplacement(JSFunction* function) {
}
-static void ClearSampleBuffer() {
- for (int i = 0; i < kSamplerWindowSize; i++) {
- sampler_window[i] = NULL;
- sampler_window_weight[i] = 0;
- }
+void RuntimeProfiler::ClearSampleBuffer() {
+ memset(sampler_window_, 0, sizeof(sampler_window_));
+ memset(sampler_window_weight_, 0, sizeof(sampler_window_weight_));
}
-static int LookupSample(JSFunction* function) {
+int RuntimeProfiler::LookupSample(JSFunction* function) {
int weight = 0;
for (int i = 0; i < kSamplerWindowSize; i++) {
- Object* sample = sampler_window[i];
+ Object* sample = sampler_window_[i];
if (sample != NULL) {
if (function == sample) {
- weight += sampler_window_weight[i];
+ weight += sampler_window_weight_[i];
}
}
}
@@ -217,18 +226,18 @@ static int LookupSample(JSFunction* function) {
}
-static void AddSample(JSFunction* function, int weight) {
+void RuntimeProfiler::AddSample(JSFunction* function, int weight) {
ASSERT(IsPowerOf2(kSamplerWindowSize));
- sampler_window[sampler_window_position] = function;
- sampler_window_weight[sampler_window_position] = weight;
- sampler_window_position = (sampler_window_position + 1) &
+ sampler_window_[sampler_window_position_] = function;
+ sampler_window_weight_[sampler_window_position_] = weight;
+ sampler_window_position_ = (sampler_window_position_ + 1) &
(kSamplerWindowSize - 1);
}
void RuntimeProfiler::OptimizeNow() {
- HandleScope scope;
- PendingListNode* current = optimize_soon_list;
+ HandleScope scope(isolate_);
+ PendingListNode* current = optimize_soon_list_;
while (current != NULL) {
PendingListNode* next = current->next();
if (current->IsValid()) {
@@ -241,7 +250,7 @@ void RuntimeProfiler::OptimizeNow() {
delete current;
current = next;
}
- optimize_soon_list = NULL;
+ optimize_soon_list_ = NULL;
// Run through the JavaScript frames and collect them. If we already
// have a sample of the function, we mark it for optimizations
@@ -257,14 +266,14 @@ void RuntimeProfiler::OptimizeNow() {
// Adjust threshold each time we have processed
// a certain number of ticks.
- if (sampler_ticks_until_threshold_adjustment > 0) {
- sampler_ticks_until_threshold_adjustment--;
- if (sampler_ticks_until_threshold_adjustment <= 0) {
+ if (sampler_ticks_until_threshold_adjustment_ > 0) {
+ sampler_ticks_until_threshold_adjustment_--;
+ if (sampler_ticks_until_threshold_adjustment_ <= 0) {
// If the threshold is not already at the minimum
// modify and reset the ticks until next adjustment.
- if (sampler_threshold > kSamplerThresholdMin) {
- sampler_threshold -= kSamplerThresholdDelta;
- sampler_ticks_until_threshold_adjustment =
+ if (sampler_threshold_ > kSamplerThresholdMin) {
+ sampler_threshold_ -= kSamplerThresholdDelta;
+ sampler_ticks_until_threshold_adjustment_ =
kSamplerTicksBetweenThresholdAdjustment;
}
}
@@ -284,11 +293,11 @@ void RuntimeProfiler::OptimizeNow() {
int function_size = function->shared()->SourceSize();
int threshold_size_factor = (function_size > kSizeLimit)
- ? sampler_threshold_size_factor
+ ? sampler_threshold_size_factor_
: 1;
- int threshold = sampler_threshold * threshold_size_factor;
- int current_js_ratio = NoBarrier_Load(&js_ratio);
+ int threshold = sampler_threshold_ * threshold_size_factor;
+ int current_js_ratio = NoBarrier_Load(&js_ratio_);
// Adjust threshold depending on the ratio of time spent
// in JS code.
@@ -304,7 +313,8 @@ void RuntimeProfiler::OptimizeNow() {
if (LookupSample(function) >= threshold) {
Optimize(function, false, 0);
- CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function));
+ isolate_->compilation_cache()->MarkForEagerOptimizing(
+ Handle<JSFunction>(function));
}
}
@@ -320,26 +330,21 @@ void RuntimeProfiler::OptimizeNow() {
void RuntimeProfiler::OptimizeSoon(JSFunction* function) {
if (!IsOptimizable(function)) return;
PendingListNode* node = new PendingListNode(function);
- node->set_next(optimize_soon_list);
- optimize_soon_list = node;
+ node->set_next(optimize_soon_list_);
+ optimize_soon_list_ = node;
}
#ifdef ENABLE_LOGGING_AND_PROFILING
-static void UpdateStateRatio(SamplerState current_state) {
- static const int kStateWindowSize = 128;
- static SamplerState state_window[kStateWindowSize];
- static int state_window_position = 0;
- static int state_counts[2] = { kStateWindowSize, 0 };
-
- SamplerState old_state = state_window[state_window_position];
- state_counts[old_state]--;
- state_window[state_window_position] = current_state;
- state_counts[current_state]++;
+void RuntimeProfiler::UpdateStateRatio(SamplerState current_state) {
+ SamplerState old_state = state_window_[state_window_position_];
+ state_counts_[old_state]--;
+ state_window_[state_window_position_] = current_state;
+ state_counts_[current_state]++;
ASSERT(IsPowerOf2(kStateWindowSize));
- state_window_position = (state_window_position + 1) &
+ state_window_position_ = (state_window_position_ + 1) &
(kStateWindowSize - 1);
- NoBarrier_Store(&js_ratio, state_counts[IN_JS_STATE] * 100 /
+ NoBarrier_Store(&js_ratio_, state_counts_[IN_JS_STATE] * 100 /
kStateWindowSize);
}
#endif
@@ -348,11 +353,11 @@ static void UpdateStateRatio(SamplerState current_state) {
void RuntimeProfiler::NotifyTick() {
#ifdef ENABLE_LOGGING_AND_PROFILING
// Record state sample.
- SamplerState state = Top::IsInJSState()
+ SamplerState state = IsSomeIsolateInJS()
? IN_JS_STATE
: IN_NON_JS_STATE;
UpdateStateRatio(state);
- StackGuard::RequestRuntimeProfilerTick();
+ isolate_->stack_guard()->RequestRuntimeProfilerTick();
#endif
}
@@ -361,15 +366,15 @@ void RuntimeProfiler::Setup() {
ClearSampleBuffer();
// If the ticker hasn't already started, make sure to do so to get
// the ticks for the runtime profiler.
- if (IsEnabled()) Logger::EnsureTickerStarted();
+ if (IsEnabled()) isolate_->logger()->EnsureTickerStarted();
}
void RuntimeProfiler::Reset() {
- sampler_threshold = kSamplerThresholdInit;
- sampler_ticks_until_threshold_adjustment =
+ sampler_threshold_ = kSamplerThresholdInit;
+ sampler_threshold_size_factor_ = kSamplerThresholdSizeFactorInit;
+ sampler_ticks_until_threshold_adjustment_ =
kSamplerTicksBetweenThresholdAdjustment;
- sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
}
@@ -386,24 +391,61 @@ int RuntimeProfiler::SamplerWindowSize() {
// Update the pointers in the sampler window after a GC.
void RuntimeProfiler::UpdateSamplesAfterScavenge() {
for (int i = 0; i < kSamplerWindowSize; i++) {
- Object* function = sampler_window[i];
- if (function != NULL && Heap::InNewSpace(function)) {
+ Object* function = sampler_window_[i];
+ if (function != NULL && isolate_->heap()->InNewSpace(function)) {
MapWord map_word = HeapObject::cast(function)->map_word();
if (map_word.IsForwardingAddress()) {
- sampler_window[i] = map_word.ToForwardingAddress();
+ sampler_window_[i] = map_word.ToForwardingAddress();
} else {
- sampler_window[i] = NULL;
+ sampler_window_[i] = NULL;
}
}
}
}
+void RuntimeProfiler::HandleWakeUp(Isolate* isolate) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ // The profiler thread must still be waiting.
+ ASSERT(NoBarrier_Load(&state_) >= 0);
+ // In IsolateEnteredJS we have already incremented the counter and
+ // undid the decrement done by the profiler thread. Increment again
+ // to get the right count of active isolates.
+ NoBarrier_AtomicIncrement(&state_, 1);
+ semaphore_->Signal();
+ isolate->ResetEagerOptimizingData();
+#endif
+}
+
+
+bool RuntimeProfiler::IsSomeIsolateInJS() {
+ return NoBarrier_Load(&state_) > 0;
+}
+
+
+bool RuntimeProfiler::WaitForSomeIsolateToEnterJS() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ Atomic32 old_state = NoBarrier_CompareAndSwap(&state_, 0, -1);
+ ASSERT(old_state >= -1);
+ if (old_state != 0) return false;
+ semaphore_->Wait();
+#endif
+ return true;
+}
+
+
+void RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ semaphore_->Signal();
+#endif
+}
+
+
void RuntimeProfiler::RemoveDeadSamples() {
for (int i = 0; i < kSamplerWindowSize; i++) {
- Object* function = sampler_window[i];
+ Object* function = sampler_window_[i];
if (function != NULL && !HeapObject::cast(function)->IsMarked()) {
- sampler_window[i] = NULL;
+ sampler_window_[i] = NULL;
}
}
}
@@ -411,7 +453,7 @@ void RuntimeProfiler::RemoveDeadSamples() {
void RuntimeProfiler::UpdateSamplesAfterCompact(ObjectVisitor* visitor) {
for (int i = 0; i < kSamplerWindowSize; i++) {
- visitor->VisitPointer(&sampler_window[i]);
+ visitor->VisitPointer(&sampler_window_[i]);
}
}
@@ -419,20 +461,13 @@ void RuntimeProfiler::UpdateSamplesAfterCompact(ObjectVisitor* visitor) {
bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
#ifdef ENABLE_LOGGING_AND_PROFILING
static const int kNonJSTicksThreshold = 100;
- // We suspend the runtime profiler thread when not running
- // JavaScript. If the CPU profiler is active we must not do this
- // because it samples both JavaScript and C++ code.
- if (RuntimeProfiler::IsEnabled() &&
- !CpuProfiler::is_profiling() &&
- !(FLAG_prof && FLAG_prof_auto)) {
- if (Top::IsInJSState()) {
- non_js_ticks_ = 0;
+ if (RuntimeProfiler::IsSomeIsolateInJS()) {
+ non_js_ticks_ = 0;
+ } else {
+ if (non_js_ticks_ < kNonJSTicksThreshold) {
+ ++non_js_ticks_;
} else {
- if (non_js_ticks_ < kNonJSTicksThreshold) {
- ++non_js_ticks_;
- } else {
- if (Top::WaitForJSState()) return true;
- }
+ return RuntimeProfiler::WaitForSomeIsolateToEnterJS();
}
}
#endif
diff --git a/src/runtime-profiler.h b/src/runtime-profiler.h
index 02defc9b..8074035a 100644
--- a/src/runtime-profiler.h
+++ b/src/runtime-profiler.h
@@ -28,29 +28,122 @@
#ifndef V8_RUNTIME_PROFILER_H_
#define V8_RUNTIME_PROFILER_H_
-#include "v8.h"
#include "allocation.h"
+#include "atomicops.h"
namespace v8 {
namespace internal {
-class RuntimeProfiler : public AllStatic {
+class Isolate;
+class JSFunction;
+class Object;
+class PendingListNode;
+class Semaphore;
+
+
+enum SamplerState {
+ IN_NON_JS_STATE = 0,
+ IN_JS_STATE = 1
+};
+
+
+class RuntimeProfiler {
public:
- static bool IsEnabled() { return V8::UseCrankshaft() && FLAG_opt; }
+ explicit RuntimeProfiler(Isolate* isolate);
+
+ static bool IsEnabled();
+
+ void OptimizeNow();
+ void OptimizeSoon(JSFunction* function);
+
+ void NotifyTick();
+
+ void Setup();
+ void Reset();
+ void TearDown();
+
+ Object** SamplerWindowAddress();
+ int SamplerWindowSize();
+
+ // Rate limiting support.
+
+ // VM thread interface.
+ //
+ // Called by isolates when their states change.
+ static inline void IsolateEnteredJS(Isolate* isolate);
+ static inline void IsolateExitedJS(Isolate* isolate);
+
+ // Profiler thread interface.
+ //
+ // IsSomeIsolateInJS():
+ // The profiler thread can query whether some isolate is currently
+ // running JavaScript code.
+ //
+ // WaitForSomeIsolateToEnterJS():
+ // When no isolates are running JavaScript code for some time the
+ // profiler thread suspends itself by calling the wait function. The
+ // wait function returns true after it waited or false immediately.
+ // While the function was waiting the profiler may have been
+ // disabled so it *must check* whether it is allowed to continue.
+ static bool IsSomeIsolateInJS();
+ static bool WaitForSomeIsolateToEnterJS();
+
+ // When shutting down we join the profiler thread. Doing so while
+ // it's waiting on a semaphore will cause a deadlock, so we have to
+ // wake it up first.
+ static void WakeUpRuntimeProfilerThreadBeforeShutdown();
+
+ void UpdateSamplesAfterScavenge();
+ void RemoveDeadSamples();
+ void UpdateSamplesAfterCompact(ObjectVisitor* visitor);
- static void OptimizeNow();
- static void OptimizeSoon(JSFunction* function);
+ private:
+ static const int kSamplerWindowSize = 16;
+ static const int kStateWindowSize = 128;
+
+ static void HandleWakeUp(Isolate* isolate);
+
+ void Optimize(JSFunction* function, bool eager, int delay);
+
+ void AttemptOnStackReplacement(JSFunction* function);
+
+ void ClearSampleBuffer();
+
+ void ClearSampleBufferNewSpaceEntries();
+
+ int LookupSample(JSFunction* function);
+
+ void AddSample(JSFunction* function, int weight);
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ void UpdateStateRatio(SamplerState current_state);
+#endif
- static void NotifyTick();
+ Isolate* isolate_;
- static void Setup();
- static void Reset();
- static void TearDown();
+ int sampler_threshold_;
+ int sampler_threshold_size_factor_;
+ int sampler_ticks_until_threshold_adjustment_;
- static int SamplerWindowSize();
- static void UpdateSamplesAfterScavenge();
- static void RemoveDeadSamples();
- static void UpdateSamplesAfterCompact(ObjectVisitor* visitor);
+ // The ratio of ticks spent in JS code in percent.
+ Atomic32 js_ratio_;
+
+ Object* sampler_window_[kSamplerWindowSize];
+ int sampler_window_position_;
+ int sampler_window_weight_[kSamplerWindowSize];
+
+ // Support for pending 'optimize soon' requests.
+ PendingListNode* optimize_soon_list_;
+
+ SamplerState state_window_[kStateWindowSize];
+ int state_window_position_;
+ int state_counts_[2];
+
+ // Possible state values:
+ // -1 => the profiler thread is waiting on the semaphore
+ // 0 or positive => the number of isolates running JavaScript code.
+ static Atomic32 state_;
+ static Semaphore* semaphore_;
};
@@ -59,9 +152,10 @@ class RuntimeProfilerRateLimiter BASE_EMBEDDED {
public:
RuntimeProfilerRateLimiter() : non_js_ticks_(0) { }
- // Suspends the current thread when not executing JavaScript to
- // minimize CPU usage. Returns whether this thread was suspended
- // (and so might have to check whether profiling is still active.)
+ // Suspends the current thread (which must be the profiler thread)
+ // when not executing JavaScript to minimize CPU usage. Returns
+ // whether the thread was suspended (and so must check whether
+ // profiling is still active.)
//
// Does nothing when runtime profiling is not enabled.
bool SuspendIfNecessary();
@@ -72,6 +166,27 @@ class RuntimeProfilerRateLimiter BASE_EMBEDDED {
DISALLOW_COPY_AND_ASSIGN(RuntimeProfilerRateLimiter);
};
+
+// Implementation of RuntimeProfiler inline functions.
+
+void RuntimeProfiler::IsolateEnteredJS(Isolate* isolate) {
+ Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, 1);
+ if (new_state == 0) {
+ // Just incremented from -1 to 0. -1 can only be set by the
+ // profiler thread before it suspends itself and starts waiting on
+ // the semaphore.
+ HandleWakeUp(isolate);
+ }
+ ASSERT(new_state >= 0);
+}
+
+
+void RuntimeProfiler::IsolateExitedJS(Isolate* isolate) {
+ Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, -1);
+ ASSERT(new_state >= 0);
+ USE(new_state);
+}
+
} } // namespace v8::internal
#endif // V8_RUNTIME_PROFILER_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index 965a083a..c979849d 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -59,7 +59,7 @@ namespace internal {
#define RUNTIME_ASSERT(value) \
- if (!(value)) return Top::ThrowIllegalOperation();
+ if (!(value)) return isolate->ThrowIllegalOperation();
// Cast the given object to a value of the specified type and store
// it in a variable with the given name. If the object is not of the
@@ -100,16 +100,15 @@ namespace internal {
RUNTIME_ASSERT(obj->IsNumber()); \
type name = NumberTo##Type(obj);
-// Non-reentrant string buffer for efficient general use in this file.
-static StaticResource<StringInputBuffer> runtime_string_input_buffer;
+MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
+ JSObject* boilerplate) {
+ StackLimitCheck check(isolate);
+ if (check.HasOverflowed()) return isolate->StackOverflow();
-MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
- StackLimitCheck check;
- if (check.HasOverflowed()) return Top::StackOverflow();
-
+ Heap* heap = isolate->heap();
Object* result;
- { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
+ { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
JSObject* copy = JSObject::cast(result);
@@ -121,7 +120,7 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
Object* value = properties->get(i);
if (value->IsJSObject()) {
JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
+ { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
properties->set(i, result);
@@ -132,7 +131,7 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
Object* value = copy->InObjectPropertyAt(i);
if (value->IsJSObject()) {
JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
+ { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
copy->InObjectPropertyAtPut(i, result);
@@ -140,7 +139,7 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
}
} else {
{ MaybeObject* maybe_result =
- Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
+ heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
if (!maybe_result->ToObject(&result)) return maybe_result;
}
FixedArray* names = FixedArray::cast(result);
@@ -158,7 +157,7 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
if (value->IsJSObject()) {
JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
+ { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
{ MaybeObject* maybe_result =
@@ -172,12 +171,12 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
// Deep copy local elements.
// Pixel elements cannot be created using an object literal.
- ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
+ ASSERT(!copy->HasExternalArrayElements());
switch (copy->GetElementsKind()) {
case JSObject::FAST_ELEMENTS: {
FixedArray* elements = FixedArray::cast(copy->elements());
- if (elements->map() == Heap::fixed_cow_array_map()) {
- Counters::cow_arrays_created_runtime.Increment();
+ if (elements->map() == heap->fixed_cow_array_map()) {
+ isolate->counters()->cow_arrays_created_runtime()->Increment();
#ifdef DEBUG
for (int i = 0; i < elements->length(); i++) {
ASSERT(!elements->get(i)->IsJSObject());
@@ -188,7 +187,8 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
Object* value = elements->get(i);
if (value->IsJSObject()) {
JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
+ { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
+ js_object);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
elements->set(i, result);
@@ -206,7 +206,8 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
Object* value = element_dictionary->ValueAt(i);
if (value->IsJSObject()) {
JSObject* js_object = JSObject::cast(value);
- { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
+ { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
+ js_object);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
element_dictionary->ValueAtPut(i, result);
@@ -223,15 +224,19 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
}
-static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
+static MaybeObject* Runtime_CloneLiteralBoilerplate(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
CONVERT_CHECKED(JSObject, boilerplate, args[0]);
- return DeepCopyBoilerplate(boilerplate);
+ return DeepCopyBoilerplate(isolate, boilerplate);
}
-static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
+static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
CONVERT_CHECKED(JSObject, boilerplate, args[0]);
- return Heap::CopyJSObject(boilerplate);
+ return isolate->heap()->CopyJSObject(boilerplate);
}
@@ -239,6 +244,7 @@ static Handle<Map> ComputeObjectLiteralMap(
Handle<Context> context,
Handle<FixedArray> constant_properties,
bool* is_result_from_cache) {
+ Isolate* isolate = context->GetIsolate();
int properties_length = constant_properties->length();
int number_of_properties = properties_length / 2;
if (FLAG_canonicalize_object_literal_maps) {
@@ -265,7 +271,8 @@ static Handle<Map> ComputeObjectLiteralMap(
if ((number_of_symbol_keys == number_of_properties) &&
(number_of_symbol_keys < kMaxKeys)) {
// Create the fixed array with the key.
- Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
+ Handle<FixedArray> keys =
+ isolate->factory()->NewFixedArray(number_of_symbol_keys);
if (number_of_symbol_keys > 0) {
int index = 0;
for (int p = 0; p < properties_length; p += 2) {
@@ -277,25 +284,28 @@ static Handle<Map> ComputeObjectLiteralMap(
ASSERT(index == number_of_symbol_keys);
}
*is_result_from_cache = true;
- return Factory::ObjectLiteralMapFromCache(context, keys);
+ return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
}
}
*is_result_from_cache = false;
- return Factory::CopyMap(
+ return isolate->factory()->CopyMap(
Handle<Map>(context->object_function()->initial_map()),
number_of_properties);
}
static Handle<Object> CreateLiteralBoilerplate(
+ Isolate* isolate,
Handle<FixedArray> literals,
Handle<FixedArray> constant_properties);
static Handle<Object> CreateObjectLiteralBoilerplate(
+ Isolate* isolate,
Handle<FixedArray> literals,
Handle<FixedArray> constant_properties,
- bool should_have_fast_elements) {
+ bool should_have_fast_elements,
+ bool has_function_literal) {
// Get the global context from the literals array. This is the
// context in which the function was created and we use the object
// function from this context to create the object literal. We do
@@ -305,69 +315,90 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
Handle<Context> context =
Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
- bool is_result_from_cache;
- Handle<Map> map = ComputeObjectLiteralMap(context,
- constant_properties,
- &is_result_from_cache);
+ // In case we have function literals, we want the object to be in
+ // slow properties mode for now. We don't go in the map cache because
+ // maps with constant functions can't be shared if the functions are
+ // not the same (which is the common case).
+ bool is_result_from_cache = false;
+ Handle<Map> map = has_function_literal
+ ? Handle<Map>(context->object_function()->initial_map())
+ : ComputeObjectLiteralMap(context,
+ constant_properties,
+ &is_result_from_cache);
- Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
+ Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
// Normalize the elements of the boilerplate to save space if needed.
if (!should_have_fast_elements) NormalizeElements(boilerplate);
- { // Add the constant properties to the boilerplate.
- int length = constant_properties->length();
- OptimizedObjectForAddingMultipleProperties opt(boilerplate,
- length / 2,
- !is_result_from_cache);
- for (int index = 0; index < length; index +=2) {
- Handle<Object> key(constant_properties->get(index+0));
- Handle<Object> value(constant_properties->get(index+1));
- if (value->IsFixedArray()) {
- // The value contains the constant_properties of a
- // simple object literal.
- Handle<FixedArray> array = Handle<FixedArray>::cast(value);
- value = CreateLiteralBoilerplate(literals, array);
- if (value.is_null()) return value;
- }
- Handle<Object> result;
- uint32_t element_index = 0;
- if (key->IsSymbol()) {
- if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
- // Array index as string (uint32).
- result = SetOwnElement(boilerplate,
- element_index,
- value,
- kNonStrictMode);
- } else {
- Handle<String> name(String::cast(*key));
- ASSERT(!name->AsArrayIndex(&element_index));
- result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
- value, NONE);
- }
- } else if (key->ToArrayIndex(&element_index)) {
- // Array index (uint32).
+ // Add the constant properties to the boilerplate.
+ int length = constant_properties->length();
+ bool should_transform =
+ !is_result_from_cache && boilerplate->HasFastProperties();
+ if (should_transform || has_function_literal) {
+ // Normalize the properties of object to avoid n^2 behavior
+ // when extending the object multiple properties. Indicate the number of
+ // properties to be added.
+ NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
+ }
+
+ for (int index = 0; index < length; index +=2) {
+ Handle<Object> key(constant_properties->get(index+0), isolate);
+ Handle<Object> value(constant_properties->get(index+1), isolate);
+ if (value->IsFixedArray()) {
+ // The value contains the constant_properties of a
+ // simple object or array literal.
+ Handle<FixedArray> array = Handle<FixedArray>::cast(value);
+ value = CreateLiteralBoilerplate(isolate, literals, array);
+ if (value.is_null()) return value;
+ }
+ Handle<Object> result;
+ uint32_t element_index = 0;
+ if (key->IsSymbol()) {
+ if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
+ // Array index as string (uint32).
result = SetOwnElement(boilerplate,
element_index,
value,
kNonStrictMode);
} else {
- // Non-uint32 number.
- ASSERT(key->IsNumber());
- double num = key->Number();
- char arr[100];
- Vector<char> buffer(arr, ARRAY_SIZE(arr));
- const char* str = DoubleToCString(num, buffer);
- Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
+ Handle<String> name(String::cast(*key));
+ ASSERT(!name->AsArrayIndex(&element_index));
result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
value, NONE);
}
- // If setting the property on the boilerplate throws an
- // exception, the exception is converted to an empty handle in
- // the handle based operations. In that case, we need to
- // convert back to an exception.
- if (result.is_null()) return result;
- }
+ } else if (key->ToArrayIndex(&element_index)) {
+ // Array index (uint32).
+ result = SetOwnElement(boilerplate,
+ element_index,
+ value,
+ kNonStrictMode);
+ } else {
+ // Non-uint32 number.
+ ASSERT(key->IsNumber());
+ double num = key->Number();
+ char arr[100];
+ Vector<char> buffer(arr, ARRAY_SIZE(arr));
+ const char* str = DoubleToCString(num, buffer);
+ Handle<String> name =
+ isolate->factory()->NewStringFromAscii(CStrVector(str));
+ result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
+ value, NONE);
+ }
+ // If setting the property on the boilerplate throws an
+ // exception, the exception is converted to an empty handle in
+ // the handle based operations. In that case, we need to
+ // convert back to an exception.
+ if (result.is_null()) return result;
+ }
+
+ // Transform to fast properties if necessary. For object literals with
+ // containing function literals we defer this operation until after all
+ // computed properties have been assigned so that we can generate
+ // constant function properties.
+ if (should_transform && !has_function_literal) {
+ TransformToFastProperties(boilerplate,
+ boilerplate->map()->unused_property_fields());
}
return boilerplate;
@@ -375,16 +406,18 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
static Handle<Object> CreateArrayLiteralBoilerplate(
+ Isolate* isolate,
Handle<FixedArray> literals,
Handle<FixedArray> elements) {
// Create the JSArray.
Handle<JSFunction> constructor(
JSFunction::GlobalContextFromLiterals(*literals)->array_function());
- Handle<Object> object = Factory::NewJSObject(constructor);
+ Handle<Object> object = isolate->factory()->NewJSObject(constructor);
- const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
+ const bool is_cow =
+ (elements->map() == isolate->heap()->fixed_cow_array_map());
Handle<FixedArray> copied_elements =
- is_cow ? elements : Factory::CopyFixedArray(elements);
+ is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
if (is_cow) {
@@ -398,10 +431,10 @@ static Handle<Object> CreateArrayLiteralBoilerplate(
for (int i = 0; i < content->length(); i++) {
if (content->get(i)->IsFixedArray()) {
// The value contains the constant_properties of a
- // simple object literal.
+ // simple object or array literal.
Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
Handle<Object> result =
- CreateLiteralBoilerplate(literals, fa);
+ CreateLiteralBoilerplate(isolate, literals, fa);
if (result.is_null()) return result;
content->set(i, *result);
}
@@ -415,16 +448,26 @@ static Handle<Object> CreateArrayLiteralBoilerplate(
static Handle<Object> CreateLiteralBoilerplate(
+ Isolate* isolate,
Handle<FixedArray> literals,
Handle<FixedArray> array) {
Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
+ const bool kHasNoFunctionLiteral = false;
switch (CompileTimeValue::GetType(array)) {
case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
- return CreateObjectLiteralBoilerplate(literals, elements, true);
+ return CreateObjectLiteralBoilerplate(isolate,
+ literals,
+ elements,
+ true,
+ kHasNoFunctionLiteral);
case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
- return CreateObjectLiteralBoilerplate(literals, elements, false);
+ return CreateObjectLiteralBoilerplate(isolate,
+ literals,
+ elements,
+ false,
+ kHasNoFunctionLiteral);
case CompileTimeValue::ARRAY_LITERAL:
- return CreateArrayLiteralBoilerplate(literals, elements);
+ return CreateArrayLiteralBoilerplate(isolate, literals, elements);
default:
UNREACHABLE();
return Handle<Object>::null();
@@ -432,19 +475,22 @@ static Handle<Object> CreateLiteralBoilerplate(
}
-static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
+static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
// Takes a FixedArray of elements containing the literal elements of
// the array literal and produces JSArray with those elements.
// Additionally takes the literals array of the surrounding function
// which contains the context from which to get the Array function
// to use for creating the array literal.
- HandleScope scope;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, elements, 2);
- Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
+ Handle<Object> object =
+ CreateArrayLiteralBoilerplate(isolate, literals, elements);
if (object.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
@@ -453,103 +499,118 @@ static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
}
-static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_CreateObjectLiteral(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 4);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
- CONVERT_SMI_CHECKED(fast_elements, args[3]);
- bool should_have_fast_elements = fast_elements == 1;
+ CONVERT_SMI_CHECKED(flags, args[3]);
+ bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
+ bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
// Check if boilerplate exists. If not, create it first.
- Handle<Object> boilerplate(literals->get(literals_index));
- if (*boilerplate == Heap::undefined_value()) {
- boilerplate = CreateObjectLiteralBoilerplate(literals,
+ Handle<Object> boilerplate(literals->get(literals_index), isolate);
+ if (*boilerplate == isolate->heap()->undefined_value()) {
+ boilerplate = CreateObjectLiteralBoilerplate(isolate,
+ literals,
constant_properties,
- should_have_fast_elements);
+ should_have_fast_elements,
+ has_function_literal);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
- return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
+ return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
}
-static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_CreateObjectLiteralShallow(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 4);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
- CONVERT_SMI_CHECKED(fast_elements, args[3]);
- bool should_have_fast_elements = fast_elements == 1;
+ CONVERT_SMI_CHECKED(flags, args[3]);
+ bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
+ bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
// Check if boilerplate exists. If not, create it first.
- Handle<Object> boilerplate(literals->get(literals_index));
- if (*boilerplate == Heap::undefined_value()) {
- boilerplate = CreateObjectLiteralBoilerplate(literals,
+ Handle<Object> boilerplate(literals->get(literals_index), isolate);
+ if (*boilerplate == isolate->heap()->undefined_value()) {
+ boilerplate = CreateObjectLiteralBoilerplate(isolate,
+ literals,
constant_properties,
- should_have_fast_elements);
+ should_have_fast_elements,
+ has_function_literal);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
- return Heap::CopyJSObject(JSObject::cast(*boilerplate));
+ return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
}
-static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_CreateArrayLiteral(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, elements, 2);
// Check if boilerplate exists. If not, create it first.
- Handle<Object> boilerplate(literals->get(literals_index));
- if (*boilerplate == Heap::undefined_value()) {
- boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
+ Handle<Object> boilerplate(literals->get(literals_index), isolate);
+ if (*boilerplate == isolate->heap()->undefined_value()) {
+ boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
- return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
+ return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
}
-static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_CreateArrayLiteralShallow(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, elements, 2);
// Check if boilerplate exists. If not, create it first.
- Handle<Object> boilerplate(literals->get(literals_index));
- if (*boilerplate == Heap::undefined_value()) {
- boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
+ Handle<Object> boilerplate(literals->get(literals_index), isolate);
+ if (*boilerplate == isolate->heap()->undefined_value()) {
+ boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
if (JSObject::cast(*boilerplate)->elements()->map() ==
- Heap::fixed_cow_array_map()) {
- Counters::cow_arrays_created_runtime.Increment();
+ isolate->heap()->fixed_cow_array_map()) {
+ isolate->counters()->cow_arrays_created_runtime()->Increment();
}
- return Heap::CopyJSObject(JSObject::cast(*boilerplate));
+ return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
}
-static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
+static MaybeObject* Runtime_CreateCatchExtensionObject(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
CONVERT_CHECKED(String, key, args[0]);
Object* value = args[1];
// Create a catch context extension object.
JSFunction* constructor =
- Top::context()->global_context()->context_extension_function();
+ isolate->context()->global_context()->
+ context_extension_function();
Object* object;
- { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
+ { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
// Assign the exception value to the catch variable and make sure
@@ -564,16 +625,18 @@ static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
}
-static MaybeObject* Runtime_ClassOf(Arguments args) {
+static MaybeObject* Runtime_ClassOf(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
Object* obj = args[0];
- if (!obj->IsJSObject()) return Heap::null_value();
+ if (!obj->IsJSObject()) return isolate->heap()->null_value();
return JSObject::cast(obj)->class_name();
}
-static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
+static MaybeObject* Runtime_IsInPrototypeChain(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
// See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
@@ -581,15 +644,16 @@ static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
Object* V = args[1];
while (true) {
Object* prototype = V->GetPrototype();
- if (prototype->IsNull()) return Heap::false_value();
- if (O == prototype) return Heap::true_value();
+ if (prototype->IsNull()) return isolate->heap()->false_value();
+ if (O == prototype) return isolate->heap()->true_value();
V = prototype;
}
}
// Inserts an object as the hidden prototype of another object.
-static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
+static MaybeObject* Runtime_SetHiddenPrototype(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSObject, jsobject, args[0]);
@@ -627,15 +691,16 @@ static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
new_map->set_prototype(proto);
jsobject->set_map(new_map);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_IsConstructCall(Arguments args) {
+static MaybeObject* Runtime_IsConstructCall(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 0);
JavaScriptFrameIterator it;
- return Heap::ToBoolean(it.frame()->IsConstructor());
+ return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
}
@@ -682,9 +747,10 @@ static bool CheckAccess(JSObject* obj,
JSObject* holder = result->holder();
JSObject* current = obj;
+ Isolate* isolate = obj->GetIsolate();
while (true) {
if (current->IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(current, name, access_type)) {
+ !isolate->MayNamedAccess(current, name, access_type)) {
// Access check callback denied the access, but some properties
// can have a special permissions which override callbacks descision
// (currently see v8::AccessControl).
@@ -721,7 +787,7 @@ static bool CheckAccess(JSObject* obj,
break;
}
- Top::ReportFailedAccessCheck(current, access_type);
+ isolate->ReportFailedAccessCheck(current, access_type);
return false;
}
@@ -731,7 +797,7 @@ static bool CheckElementAccess(JSObject* obj,
uint32_t index,
v8::AccessType access_type) {
if (obj->IsAccessCheckNeeded() &&
- !Top::MayIndexedAccess(obj, index, access_type)) {
+ !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
return false;
}
@@ -758,11 +824,13 @@ enum PropertyDescriptorIndices {
// [false, value, Writeable, Enumerable, Configurable]
// if args[1] is an accessor on args[0]
// [true, GetFunction, SetFunction, Enumerable, Configurable]
-static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
+static MaybeObject* Runtime_GetOwnProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
- Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
- Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
+ Heap* heap = isolate->heap();
+ HandleScope scope(isolate);
+ Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
+ Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
LookupResult result;
CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_ARG_CHECKED(String, name, 1);
@@ -772,7 +840,7 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
if (name->AsArrayIndex(&index)) {
switch (obj->HasLocalElement(index)) {
case JSObject::UNDEFINED_ELEMENT:
- return Heap::undefined_value();
+ return heap->undefined_value();
case JSObject::STRING_CHARACTER_ELEMENT: {
// Special handling of string objects according to ECMAScript 5
@@ -783,23 +851,23 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
Handle<String> str(String::cast(js_value->value()));
Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
- elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+ elms->set(IS_ACCESSOR_INDEX, heap->false_value());
elms->set(VALUE_INDEX, *substr);
- elms->set(WRITABLE_INDEX, Heap::false_value());
- elms->set(ENUMERABLE_INDEX, Heap::false_value());
- elms->set(CONFIGURABLE_INDEX, Heap::false_value());
+ elms->set(WRITABLE_INDEX, heap->false_value());
+ elms->set(ENUMERABLE_INDEX, heap->false_value());
+ elms->set(CONFIGURABLE_INDEX, heap->false_value());
return *desc;
}
case JSObject::INTERCEPTED_ELEMENT:
case JSObject::FAST_ELEMENT: {
- elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+ elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Handle<Object> value = GetElement(obj, index);
- RETURN_IF_EMPTY_HANDLE(value);
+ RETURN_IF_EMPTY_HANDLE(isolate, value);
elms->set(VALUE_INDEX, *value);
- elms->set(WRITABLE_INDEX, Heap::true_value());
- elms->set(ENUMERABLE_INDEX, Heap::true_value());
- elms->set(CONFIGURABLE_INDEX, Heap::true_value());
+ elms->set(WRITABLE_INDEX, heap->true_value());
+ elms->set(ENUMERABLE_INDEX, heap->true_value());
+ elms->set(CONFIGURABLE_INDEX, heap->true_value());
return *desc;
}
@@ -807,7 +875,7 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
Handle<JSObject> holder = obj;
if (obj->IsJSGlobalProxy()) {
Object* proto = obj->GetPrototype();
- if (proto->IsNull()) return Heap::undefined_value();
+ if (proto->IsNull()) return heap->undefined_value();
ASSERT(proto->IsJSGlobalObject());
holder = Handle<JSObject>(JSObject::cast(proto));
}
@@ -820,7 +888,7 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
// This is an accessor property with getter and/or setter.
FixedArray* callbacks =
FixedArray::cast(dictionary->ValueAt(entry));
- elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
+ elms->set(IS_ACCESSOR_INDEX, heap->true_value());
if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
elms->set(GETTER_INDEX, callbacks->get(0));
}
@@ -831,19 +899,19 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
}
case NORMAL: {
// This is a data property.
- elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+ elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Handle<Object> value = GetElement(obj, index);
ASSERT(!value.is_null());
elms->set(VALUE_INDEX, *value);
- elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
+ elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
break;
}
default:
UNREACHABLE();
break;
}
- elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
- elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
+ elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
+ elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
return *desc;
}
}
@@ -853,22 +921,22 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
GetOwnPropertyImplementation(*obj, *name, &result);
if (!result.IsProperty()) {
- return Heap::undefined_value();
+ return heap->undefined_value();
}
if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
- return Heap::false_value();
+ return heap->false_value();
}
- elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
- elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
+ elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
+ elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
bool is_js_accessor = (result.type() == CALLBACKS) &&
(result.GetCallbackObject()->IsFixedArray());
if (is_js_accessor) {
// __defineGetter__/__defineSetter__ callback.
- elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
+ elms->set(IS_ACCESSOR_INDEX, heap->true_value());
FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
@@ -878,8 +946,8 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
elms->set(SETTER_INDEX, structure->get(1));
}
} else {
- elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
- elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
+ elms->set(IS_ACCESSOR_INDEX, heap->false_value());
+ elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
PropertyAttributes attrs;
Object* value;
@@ -894,29 +962,32 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
}
-static MaybeObject* Runtime_PreventExtensions(Arguments args) {
+static MaybeObject* Runtime_PreventExtensions(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSObject, obj, args[0]);
return obj->PreventExtensions();
}
-static MaybeObject* Runtime_IsExtensible(Arguments args) {
+static MaybeObject* Runtime_IsExtensible(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSObject, obj, args[0]);
if (obj->IsJSGlobalProxy()) {
Object* proto = obj->GetPrototype();
- if (proto->IsNull()) return Heap::false_value();
+ if (proto->IsNull()) return isolate->heap()->false_value();
ASSERT(proto->IsJSGlobalObject());
obj = JSObject::cast(proto);
}
- return obj->map()->is_extensible() ? Heap::true_value()
- : Heap::false_value();
+ return obj->map()->is_extensible() ? isolate->heap()->true_value()
+ : isolate->heap()->false_value();
}
-static MaybeObject* Runtime_RegExpCompile(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_RegExpCompile(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(JSRegExp, re, 0);
CONVERT_ARG_CHECKED(String, pattern, 1);
@@ -927,23 +998,26 @@ static MaybeObject* Runtime_RegExpCompile(Arguments args) {
}
-static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_CreateApiFunction(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
- return *Factory::CreateApiFunction(data);
+ return *isolate->factory()->CreateApiFunction(data);
}
-static MaybeObject* Runtime_IsTemplate(Arguments args) {
+static MaybeObject* Runtime_IsTemplate(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
Object* arg = args[0];
bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
- return Heap::ToBoolean(result);
+ return isolate->heap()->ToBoolean(result);
}
-static MaybeObject* Runtime_GetTemplateField(Arguments args) {
+static MaybeObject* Runtime_GetTemplateField(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
CONVERT_CHECKED(HeapObject, templ, args[0]);
CONVERT_CHECKED(Smi, field, args[1]);
@@ -962,7 +1036,8 @@ static MaybeObject* Runtime_GetTemplateField(Arguments args) {
}
-static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
+static MaybeObject* Runtime_DisableAccessChecks(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(HeapObject, object, args[0]);
Map* old_map = object->map();
@@ -977,11 +1052,13 @@ static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
Map::cast(new_map)->set_is_access_check_needed(false);
object->set_map(Map::cast(new_map));
}
- return needs_access_checks ? Heap::true_value() : Heap::false_value();
+ return needs_access_checks ? isolate->heap()->true_value()
+ : isolate->heap()->false_value();
}
-static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
+static MaybeObject* Runtime_EnableAccessChecks(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(HeapObject, object, args[0]);
Map* old_map = object->map();
@@ -995,24 +1072,29 @@ static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
Map::cast(new_map)->set_is_access_check_needed(true);
object->set_map(Map::cast(new_map));
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
- HandleScope scope;
- Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
+static Failure* ThrowRedeclarationError(Isolate* isolate,
+ const char* type,
+ Handle<String> name) {
+ HandleScope scope(isolate);
+ Handle<Object> type_handle =
+ isolate->factory()->NewStringFromAscii(CStrVector(type));
Handle<Object> args[2] = { type_handle, name };
Handle<Object> error =
- Factory::NewTypeError("redeclaration", HandleVector(args, 2));
- return Top::Throw(*error);
+ isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
+ return isolate->Throw(*error);
}
-static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
+static MaybeObject* Runtime_DeclareGlobals(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 4);
- HandleScope scope;
- Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
+ HandleScope scope(isolate);
+ Handle<GlobalObject> global = Handle<GlobalObject>(
+ isolate->context()->global());
Handle<Context> context = args.at<Context>(0);
CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
@@ -1030,9 +1112,9 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
// Traverse the name/value pairs and set the properties.
int length = pairs->length();
for (int i = 0; i < length; i += 2) {
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<String> name(String::cast(pairs->get(i)));
- Handle<Object> value(pairs->get(i + 1));
+ Handle<Object> value(pairs->get(i + 1), isolate);
// We have to declare a global const property. To capture we only
// assign to it when evaluating the assignment for "const x =
@@ -1062,7 +1144,7 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
// Check if the existing property conflicts with regards to const.
if (is_local && (is_read_only || is_const_property)) {
const char* type = (is_read_only) ? "const" : "var";
- return ThrowRedeclarationError(type, name);
+ return ThrowRedeclarationError(isolate, type, name);
};
// The property already exists without conflicting: Go to
// the next declaration.
@@ -1074,12 +1156,12 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
// For const properties, we treat a callback with this name
// even in the prototype as a conflicting declaration.
if (is_const_property && (lookup.type() == CALLBACKS)) {
- return ThrowRedeclarationError("const", name);
+ return ThrowRedeclarationError(isolate, "const", name);
}
// Otherwise, we check for locally conflicting declarations.
if (is_local && (is_read_only || is_const_property)) {
const char* type = (is_read_only) ? "const" : "var";
- return ThrowRedeclarationError(type, name);
+ return ThrowRedeclarationError(isolate, type, name);
}
// The property already exists without conflicting: Go to
// the next declaration.
@@ -1091,7 +1173,9 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>::cast(value);
Handle<JSFunction> function =
- Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
+ context,
+ TENURED);
value = function;
}
@@ -1113,7 +1197,7 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
(lookup.type() != INTERCEPTOR) &&
(lookup.IsReadOnly() || is_const_property)) {
const char* type = (lookup.IsReadOnly()) ? "const" : "var";
- return ThrowRedeclarationError(type, name);
+ return ThrowRedeclarationError(isolate, type, name);
}
// Safari does not allow the invocation of callback setters for
@@ -1129,12 +1213,14 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
attributes = static_cast<PropertyAttributes>(
attributes | (lookup.GetAttributes() & DONT_DELETE));
}
- RETURN_IF_EMPTY_HANDLE(SetLocalPropertyIgnoreAttributes(global,
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ SetLocalPropertyIgnoreAttributes(global,
name,
value,
attributes));
} else {
- RETURN_IF_EMPTY_HANDLE(SetProperty(global,
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ SetProperty(global,
name,
value,
attributes,
@@ -1142,13 +1228,14 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
}
}
- ASSERT(!Top::has_pending_exception());
- return Heap::undefined_value();
+ ASSERT(!isolate->has_pending_exception());
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DeclareContextSlot(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 4);
CONVERT_ARG_CHECKED(Context, context, 0);
@@ -1156,7 +1243,7 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
PropertyAttributes mode =
static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
- Handle<Object> initial_value(args[3]);
+ Handle<Object> initial_value(args[3], isolate);
// Declarations are always done in the function context.
context = Handle<Context>(context->fcontext());
@@ -1175,7 +1262,7 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
// Functions are not read-only.
ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
- return ThrowRedeclarationError(type, name);
+ return ThrowRedeclarationError(isolate, type, name);
}
// Initialize it if necessary.
@@ -1200,6 +1287,7 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
// Slow case: The property is not in the FixedArray part of the context.
Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
RETURN_IF_EMPTY_HANDLE(
+ isolate,
SetProperty(context_ext, name, initial_value,
mode, kNonStrictMode));
}
@@ -1216,7 +1304,8 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
} else {
// The function context's extension context does not exists - allocate
// it.
- context_ext = Factory::NewJSObject(Top::context_extension_function());
+ context_ext = isolate->factory()->NewJSObject(
+ isolate->context_extension_function());
// And store it in the extension slot.
context->set_extension(*context_ext);
}
@@ -1226,7 +1315,7 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
// or undefined, and use the correct mode (e.g. READ_ONLY attribute for
// constant declarations).
ASSERT(!context_ext->HasLocalProperty(*name));
- Handle<Object> value(Heap::undefined_value());
+ Handle<Object> value(isolate->heap()->undefined_value(), isolate);
if (*initial_value != NULL) value = initial_value;
// Declaring a const context slot is a conflicting declaration if
// there is a callback with that name in a prototype. It is
@@ -1239,18 +1328,20 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
LookupResult lookup;
context_ext->Lookup(*name, &lookup);
if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
- return ThrowRedeclarationError("const", name);
+ return ThrowRedeclarationError(isolate, "const", name);
}
}
- RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode,
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ SetProperty(context_ext, name, value, mode,
kNonStrictMode));
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
+static MaybeObject* Runtime_InitializeVarGlobal(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation nha;
// args[0] == name
// args[1] == strict_mode
@@ -1262,7 +1353,7 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
bool assign = args.length() == 3;
CONVERT_ARG_CHECKED(String, name, 0);
- GlobalObject* global = Top::context()->global();
+ GlobalObject* global = isolate->context()->global();
RUNTIME_ASSERT(args[1]->IsSmi());
StrictModeFlag strict_mode =
static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
@@ -1288,8 +1379,8 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
if (lookup.IsReadOnly()) {
// If we found readonly property on one of hidden prototypes,
// just shadow it.
- if (real_holder != Top::context()->global()) break;
- return ThrowRedeclarationError("const", name);
+ if (real_holder != isolate->context()->global()) break;
+ return ThrowRedeclarationError(isolate, "const", name);
}
// Determine if this is a redeclaration of an intercepted read-only
@@ -1297,7 +1388,7 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
bool found = true;
PropertyType type = lookup.type();
if (type == INTERCEPTOR) {
- HandleScope handle_scope;
+ HandleScope handle_scope(isolate);
Handle<JSObject> holder(real_holder);
PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
real_holder = *holder;
@@ -1310,19 +1401,19 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
// overwrite it with a variable declaration we must throw a
// re-declaration error. However if we found readonly property
// on one of hidden prototypes, just shadow it.
- if (real_holder != Top::context()->global()) break;
- return ThrowRedeclarationError("const", name);
+ if (real_holder != isolate->context()->global()) break;
+ return ThrowRedeclarationError(isolate, "const", name);
}
}
if (found && !assign) {
// The global property is there and we're not assigning any value
// to it. Just return.
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// Assign the value (or undefined) to the property.
- Object* value = (assign) ? args[2] : Heap::undefined_value();
+ Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
return real_holder->SetProperty(
&lookup, *name, value, attributes, strict_mode);
}
@@ -1337,15 +1428,16 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
real_holder = JSObject::cast(proto);
}
- global = Top::context()->global();
+ global = isolate->context()->global();
if (assign) {
return global->SetProperty(*name, args[2], attributes, strict_mode);
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
+static MaybeObject* Runtime_InitializeConstGlobal(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
// All constants are declared with an initial value. The name
// of the constant is the first argument and the initial value
// is the second.
@@ -1354,7 +1446,7 @@ static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
Handle<Object> value = args.at<Object>(1);
// Get the current global object from top.
- GlobalObject* global = Top::context()->global();
+ GlobalObject* global = isolate->context()->global();
// According to ECMA-262, section 12.2, page 62, the property must
// not be deletable. Since it's a const, it must be READ_ONLY too.
@@ -1379,7 +1471,7 @@ static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
// need to ask it for the property attributes.
if (!lookup.IsReadOnly()) {
if (lookup.type() != INTERCEPTOR) {
- return ThrowRedeclarationError("var", name);
+ return ThrowRedeclarationError(isolate, "var", name);
}
PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
@@ -1387,20 +1479,21 @@ static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
// Throw re-declaration error if the intercepted property is present
// but not read-only.
if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
- return ThrowRedeclarationError("var", name);
+ return ThrowRedeclarationError(isolate, "var", name);
}
// Restore global object from context (in case of GC) and continue
// with setting the value because the property is either absent or
// read-only. We also have to do redo the lookup.
- HandleScope handle_scope;
- Handle<GlobalObject> global(Top::context()->global());
+ HandleScope handle_scope(isolate);
+ Handle<GlobalObject> global(isolate->context()->global());
// BUG 1213575: Handle the case where we have to set a read-only
// property through an interceptor and only do it if it's
// uninitialized, e.g. the hole. Nirk...
// Passing non-strict mode because the property is writable.
- RETURN_IF_EMPTY_HANDLE(SetProperty(global,
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ SetProperty(global,
name,
value,
attributes,
@@ -1434,11 +1527,13 @@ static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
}
-static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_InitializeConstContextSlot(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
- Handle<Object> value(args[0]);
+ Handle<Object> value(args[0], isolate);
ASSERT(!value->IsTheHole());
CONVERT_ARG_CHECKED(Context, context, 1);
Handle<String> name(String::cast(args[2]));
@@ -1479,6 +1574,7 @@ static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
ASSERT((attributes & READ_ONLY) == 0);
Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
RETURN_IF_EMPTY_HANDLE(
+ isolate,
SetElement(arguments, index, value, kNonStrictMode));
}
return *value;
@@ -1487,9 +1583,11 @@ static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
// The property could not be found, we introduce it in the global
// context.
if (attributes == ABSENT) {
- Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
+ Handle<JSObject> global = Handle<JSObject>(
+ isolate->context()->global());
// Strict mode not needed (const disallowed in strict mode).
RETURN_IF_EMPTY_HANDLE(
+ isolate,
SetProperty(global, name, value, NONE, kNonStrictMode));
return *value;
}
@@ -1529,6 +1627,7 @@ static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
if ((attributes & READ_ONLY) == 0) {
// Strict mode not needed (const disallowed in strict mode).
RETURN_IF_EMPTY_HANDLE(
+ isolate,
SetProperty(context_ext, name, value, attributes, kNonStrictMode));
}
}
@@ -1538,8 +1637,9 @@ static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
- Arguments args) {
- HandleScope scope;
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSObject, object, 0);
CONVERT_SMI_CHECKED(properties, args[1]);
@@ -1550,8 +1650,9 @@ static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
}
-static MaybeObject* Runtime_RegExpExec(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_RegExpExec(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 4);
CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
CONVERT_ARG_CHECKED(String, subject, 1);
@@ -1562,7 +1663,7 @@ static MaybeObject* Runtime_RegExpExec(Arguments args) {
RUNTIME_ASSERT(last_match_info->HasFastElements());
RUNTIME_ASSERT(index >= 0);
RUNTIME_ASSERT(index <= subject->length());
- Counters::regexp_entry_runtime.Increment();
+ isolate->counters()->regexp_entry_runtime()->Increment();
Handle<Object> result = RegExpImpl::Exec(regexp,
subject,
index,
@@ -1572,31 +1673,31 @@ static MaybeObject* Runtime_RegExpExec(Arguments args) {
}
-static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
+static MaybeObject* Runtime_RegExpConstructResult(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 3);
CONVERT_SMI_CHECKED(elements_count, args[0]);
if (elements_count > JSArray::kMaxFastElementsLength) {
- return Top::ThrowIllegalOperation();
+ return isolate->ThrowIllegalOperation();
}
Object* new_object;
{ MaybeObject* maybe_new_object =
- Heap::AllocateFixedArrayWithHoles(elements_count);
+ isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
}
FixedArray* elements = FixedArray::cast(new_object);
- { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
- NEW_SPACE,
- OLD_POINTER_SPACE);
+ { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
+ JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
}
{
AssertNoAllocation no_gc;
- HandleScope scope;
+ HandleScope scope(isolate);
reinterpret_cast<HeapObject*>(new_object)->
- set_map(Top::global_context()->regexp_result_map());
+ set_map(isolate->global_context()->regexp_result_map());
}
JSArray* array = JSArray::cast(new_object);
- array->set_properties(Heap::empty_fixed_array());
+ array->set_properties(isolate->heap()->empty_fixed_array());
array->set_elements(elements);
array->set_length(Smi::FromInt(elements_count));
// Write in-object properties after the length of the array.
@@ -1606,20 +1707,21 @@ static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
}
-static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
+static MaybeObject* Runtime_RegExpInitializeObject(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
AssertNoAllocation no_alloc;
ASSERT(args.length() == 5);
CONVERT_CHECKED(JSRegExp, regexp, args[0]);
CONVERT_CHECKED(String, source, args[1]);
Object* global = args[2];
- if (!global->IsTrue()) global = Heap::false_value();
+ if (!global->IsTrue()) global = isolate->heap()->false_value();
Object* ignoreCase = args[3];
- if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
+ if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
Object* multiline = args[4];
- if (!multiline->IsTrue()) multiline = Heap::false_value();
+ if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
Map* map = regexp->map();
Object* constructor = map->constructor();
@@ -1638,33 +1740,32 @@ static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
return regexp;
}
- // Map has changed, so use generic, but slower, method. Since these
- // properties were all added as DONT_DELETE they must be present and
- // normal so no failures can be expected.
+ // Map has changed, so use generic, but slower, method.
PropertyAttributes final =
static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
PropertyAttributes writable =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
+ Heap* heap = isolate->heap();
MaybeObject* result;
- result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
+ result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
source,
final);
ASSERT(!result->IsFailure());
- result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
+ result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
global,
final);
ASSERT(!result->IsFailure());
result =
- regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
+ regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
ignoreCase,
final);
ASSERT(!result->IsFailure());
- result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
+ result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
multiline,
final);
ASSERT(!result->IsFailure());
result =
- regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
+ regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
Smi::FromInt(0),
writable);
ASSERT(!result->IsFailure());
@@ -1673,59 +1774,68 @@ static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
}
-static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_FinishArrayPrototypeSetup(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSArray, prototype, 0);
// This is necessary to enable fast checks for absence of elements
// on Array.prototype and below.
- prototype->set_elements(Heap::empty_fixed_array());
+ prototype->set_elements(isolate->heap()->empty_fixed_array());
return Smi::FromInt(0);
}
-static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
+static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
+ Handle<JSObject> holder,
const char* name,
Builtins::Name builtin_name) {
- Handle<String> key = Factory::LookupAsciiSymbol(name);
- Handle<Code> code(Builtins::builtin(builtin_name));
- Handle<JSFunction> optimized = Factory::NewFunction(key,
- JS_OBJECT_TYPE,
- JSObject::kHeaderSize,
- code,
- false);
+ Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
+ Handle<Code> code(isolate->builtins()->builtin(builtin_name));
+ Handle<JSFunction> optimized =
+ isolate->factory()->NewFunction(key,
+ JS_OBJECT_TYPE,
+ JSObject::kHeaderSize,
+ code,
+ false);
optimized->shared()->DontAdaptArguments();
SetProperty(holder, key, optimized, NONE, kStrictMode);
return optimized;
}
-static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_SpecialArrayFunctions(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSObject, holder, 0);
- InstallBuiltin(holder, "pop", Builtins::ArrayPop);
- InstallBuiltin(holder, "push", Builtins::ArrayPush);
- InstallBuiltin(holder, "shift", Builtins::ArrayShift);
- InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
- InstallBuiltin(holder, "slice", Builtins::ArraySlice);
- InstallBuiltin(holder, "splice", Builtins::ArraySplice);
- InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
+ InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
+ InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
+ InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
+ InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
+ InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
+ InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
+ InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
return *holder;
}
-static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
+static MaybeObject* Runtime_GetGlobalReceiver(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
// Returns a real global receiver, not one of builtins object.
- Context* global_context = Top::context()->global()->global_context();
+ Context* global_context =
+ isolate->context()->global()->global_context();
return global_context->global()->global_receiver();
}
-static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_MaterializeRegExpLiteral(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 4);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
int index = Smi::cast(args[1])->value();
@@ -1746,7 +1856,7 @@ static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
&has_pending_exception);
if (has_pending_exception) {
- ASSERT(Top::has_pending_exception());
+ ASSERT(isolate->has_pending_exception());
return Failure::Exception();
}
literals->set(index, *regexp);
@@ -1754,7 +1864,8 @@ static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
}
-static MaybeObject* Runtime_FunctionGetName(Arguments args) {
+static MaybeObject* Runtime_FunctionGetName(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -1763,44 +1874,47 @@ static MaybeObject* Runtime_FunctionGetName(Arguments args) {
}
-static MaybeObject* Runtime_FunctionSetName(Arguments args) {
+static MaybeObject* Runtime_FunctionSetName(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSFunction, f, args[0]);
CONVERT_CHECKED(String, name, args[1]);
f->shared()->set_name(name);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
+static MaybeObject* Runtime_FunctionRemovePrototype(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSFunction, f, args[0]);
- Object* obj;
- { MaybeObject* maybe_obj = f->RemovePrototype();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ Object* obj = f->RemovePrototype();
+ if (obj->IsFailure()) return obj;
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_FunctionGetScript(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSFunction, fun, args[0]);
- Handle<Object> script = Handle<Object>(fun->shared()->script());
- if (!script->IsScript()) return Heap::undefined_value();
+ Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
+ if (!script->IsScript()) return isolate->heap()->undefined_value();
return *GetScriptWrapper(Handle<Script>::cast(script));
}
-static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
+static MaybeObject* Runtime_FunctionGetSourceCode(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -1809,7 +1923,9 @@ static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
}
-static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
+static MaybeObject* Runtime_FunctionGetScriptSourcePosition(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -1819,7 +1935,9 @@ static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
}
-static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
+static MaybeObject* Runtime_FunctionGetPositionForOffset(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
CONVERT_CHECKED(Code, code, args[0]);
@@ -1832,19 +1950,21 @@ static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
}
-
-static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
+static MaybeObject* Runtime_FunctionSetInstanceClassName(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSFunction, fun, args[0]);
CONVERT_CHECKED(String, name, args[1]);
fun->SetInstanceClassName(name);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
+static MaybeObject* Runtime_FunctionSetLength(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -1855,7 +1975,8 @@ static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
}
-static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
+static MaybeObject* Runtime_FunctionSetPrototype(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -1870,26 +1991,31 @@ static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
}
-static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
+static MaybeObject* Runtime_FunctionIsAPIFunction(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSFunction, f, args[0]);
- return f->shared()->IsApiFunction() ? Heap::true_value()
- : Heap::false_value();
+ return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
+ : isolate->heap()->false_value();
}
-static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
+
+static MaybeObject* Runtime_FunctionIsBuiltin(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSFunction, f, args[0]);
- return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
+ return f->IsBuiltin() ? isolate->heap()->true_value() :
+ isolate->heap()->false_value();
}
-static MaybeObject* Runtime_SetCode(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_SetCode(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSFunction, target, 0);
@@ -1921,7 +2047,7 @@ static MaybeObject* Runtime_SetCode(Arguments args) {
// SetCode is only used for built-in constructors like String,
// Array, and Object, and some web code
// doesn't like seeing source code for constructors.
- target->shared()->set_script(Heap::undefined_value());
+ target->shared()->set_script(isolate->heap()->undefined_value());
target->shared()->code()->set_optimizable(false);
// Clear the optimization hints related to the compiled code as these are no
// longer valid when the code is overwritten.
@@ -1932,7 +2058,7 @@ static MaybeObject* Runtime_SetCode(Arguments args) {
// cross context contamination.
int number_of_literals = fun->NumberOfLiterals();
Handle<FixedArray> literals =
- Factory::NewFixedArray(number_of_literals, TENURED);
+ isolate->factory()->NewFixedArray(number_of_literals, TENURED);
if (number_of_literals > 0) {
// Insert the object, regexp and array functions in the literals
// array prefix. These are the functions that will be used when
@@ -1943,7 +2069,7 @@ static MaybeObject* Runtime_SetCode(Arguments args) {
// It's okay to skip the write barrier here because the literals
// are guaranteed to be in old space.
target->set_literals(*literals, SKIP_WRITE_BARRIER);
- target->set_next_function_link(Heap::undefined_value());
+ target->set_next_function_link(isolate->heap()->undefined_value());
}
target->set_context(*context);
@@ -1951,29 +2077,33 @@ static MaybeObject* Runtime_SetCode(Arguments args) {
}
-static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_SetExpectedNumberOfProperties(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
CONVERT_SMI_CHECKED(num, args[1]);
RUNTIME_ASSERT(num >= 0);
SetExpectedNofProperties(function, num);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
+MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
+ Object* char_code) {
uint32_t code;
if (char_code->ToArrayIndex(&code)) {
if (code <= 0xffff) {
- return Heap::LookupSingleCharacterStringFromCode(code);
+ return isolate->heap()->LookupSingleCharacterStringFromCode(code);
}
}
- return Heap::empty_string();
+ return isolate->heap()->empty_string();
}
-static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
+static MaybeObject* Runtime_StringCharCodeAt(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -1984,7 +2114,7 @@ static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
uint32_t i = 0;
if (index->IsSmi()) {
int value = Smi::cast(index)->value();
- if (value < 0) return Heap::nan_value();
+ if (value < 0) return isolate->heap()->nan_value();
i = value;
} else {
ASSERT(index->IsHeapNumber());
@@ -2002,24 +2132,25 @@ static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
subject = String::cast(flat);
if (i >= static_cast<uint32_t>(subject->length())) {
- return Heap::nan_value();
+ return isolate->heap()->nan_value();
}
return Smi::FromInt(subject->Get(i));
}
-static MaybeObject* Runtime_CharFromCode(Arguments args) {
+static MaybeObject* Runtime_CharFromCode(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- return CharFromCode(args[0]);
+ return CharFromCode(isolate, args[0]);
}
class FixedArrayBuilder {
public:
- explicit FixedArrayBuilder(int initial_capacity)
- : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
+ explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
+ : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
length_(0) {
// Require a non-zero initial size. Ensures that doubling the size to
// extend the array will work.
@@ -2049,7 +2180,7 @@ class FixedArrayBuilder {
new_length *= 2;
} while (new_length < required_length);
Handle<FixedArray> extended_array =
- Factory::NewFixedArrayWithHoles(new_length);
+ array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
array_->CopyTo(0, *extended_array, 0, length_);
array_ = extended_array;
}
@@ -2080,7 +2211,7 @@ class FixedArrayBuilder {
}
Handle<JSArray> ToJSArray() {
- Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
+ Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
result_array->set_length(Smi::FromInt(length_));
return result_array;
}
@@ -2117,8 +2248,11 @@ typedef BitField<int,
class ReplacementStringBuilder {
public:
- ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
- : array_builder_(estimated_part_count),
+ ReplacementStringBuilder(Heap* heap,
+ Handle<String> subject,
+ int estimated_part_count)
+ : heap_(heap),
+ array_builder_(heap->isolate(), estimated_part_count),
subject_(subject),
character_count_(0),
is_ascii_(subject->IsAsciiRepresentation()) {
@@ -2170,7 +2304,7 @@ class ReplacementStringBuilder {
Handle<String> ToString() {
if (array_builder_.length() == 0) {
- return Factory::empty_string();
+ return heap_->isolate()->factory()->empty_string();
}
Handle<String> joined_string;
@@ -2211,12 +2345,14 @@ class ReplacementStringBuilder {
private:
Handle<String> NewRawAsciiString(int size) {
- CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
+ CALL_HEAP_FUNCTION(heap_->isolate(),
+ heap_->AllocateRawAsciiString(size), String);
}
Handle<String> NewRawTwoByteString(int size) {
- CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
+ CALL_HEAP_FUNCTION(heap_->isolate(),
+ heap_->AllocateRawTwoByteString(size), String);
}
@@ -2226,6 +2362,7 @@ class ReplacementStringBuilder {
array_builder_.Add(element);
}
+ Heap* heap_;
FixedArrayBuilder array_builder_;
Handle<String> subject_;
int character_count_;
@@ -2436,6 +2573,7 @@ void CompiledReplacement::Compile(Handle<String> replacement,
capture_count,
subject_length);
}
+ Isolate* isolate = replacement->GetIsolate();
// Find substrings of replacement string and create them as String objects.
int substring_index = 0;
for (int i = 0, n = parts_.length(); i < n; i++) {
@@ -2443,7 +2581,8 @@ void CompiledReplacement::Compile(Handle<String> replacement,
if (tag <= 0) { // A replacement string slice.
int from = -tag;
int to = parts_[i].data;
- replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
+ replacement_substrings_.Add(
+ isolate->factory()->NewSubString(replacement, from, to));
parts_[i].tag = REPLACEMENT_SUBSTRING;
parts_[i].data = substring_index;
substring_index++;
@@ -2496,6 +2635,7 @@ void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
+ Isolate* isolate,
String* subject,
JSRegExp* regexp,
String* replacement,
@@ -2503,7 +2643,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
ASSERT(subject->IsFlat());
ASSERT(replacement->IsFlat());
- HandleScope handles;
+ HandleScope handles(isolate);
int length = subject->length();
Handle<String> subject_handle(subject);
@@ -2537,7 +2677,9 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
// conservatively.
int expected_parts =
(compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
- ReplacementStringBuilder builder(subject_handle, expected_parts);
+ ReplacementStringBuilder builder(isolate->heap(),
+ subject_handle,
+ expected_parts);
// Index of end of last match.
int prev = 0;
@@ -2553,7 +2695,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
// so its internal buffer can safely allocate a new handle if it grows.
builder.EnsureCapacity(parts_added_per_loop);
- HandleScope loop_scope;
+ HandleScope loop_scope(isolate);
int start, end;
{
AssertNoAllocation match_info_array_is_not_in_a_handle;
@@ -2605,12 +2747,13 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
template <typename ResultSeqString>
MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
+ Isolate* isolate,
String* subject,
JSRegExp* regexp,
JSArray* last_match_info) {
ASSERT(subject->IsFlat());
- HandleScope handles;
+ HandleScope handles(isolate);
Handle<String> subject_handle(subject);
Handle<JSRegExp> regexp_handle(regexp);
@@ -2624,7 +2767,6 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
ASSERT(last_match_info_handle->HasFastElements());
- HandleScope loop_scope;
int start, end;
{
AssertNoAllocation match_info_array_is_not_in_a_handle;
@@ -2638,15 +2780,15 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
int length = subject->length();
int new_length = length - (end - start);
if (new_length == 0) {
- return Heap::empty_string();
+ return isolate->heap()->empty_string();
}
Handle<ResultSeqString> answer;
if (ResultSeqString::kHasAsciiEncoding) {
- answer =
- Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
+ answer = Handle<ResultSeqString>::cast(
+ isolate->factory()->NewRawAsciiString(new_length));
} else {
- answer =
- Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
+ answer = Handle<ResultSeqString>::cast(
+ isolate->factory()->NewRawTwoByteString(new_length));
}
// If the regexp isn't global, only match once.
@@ -2694,7 +2836,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
if (match->IsNull()) break;
ASSERT(last_match_info_handle->HasFastElements());
- HandleScope loop_scope;
+ HandleScope loop_scope(isolate);
{
AssertNoAllocation match_info_array_is_not_in_a_handle;
FixedArray* match_info_array =
@@ -2714,7 +2856,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
}
if (position == 0) {
- return Heap::empty_string();
+ return isolate->heap()->empty_string();
}
// Shorten string and fill
@@ -2726,13 +2868,15 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
if (delta == 0) return *answer;
Address end_of_string = answer->address() + string_size;
- Heap::CreateFillerObjectAt(end_of_string, delta);
+ isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
return *answer;
}
-static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
+static MaybeObject* Runtime_StringReplaceRegExpWithString(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 4);
CONVERT_CHECKED(String, subject, args[0]);
@@ -2765,14 +2909,15 @@ static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
if (replacement->length() == 0) {
if (subject->HasOnlyAsciiChars()) {
return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
- subject, regexp, last_match_info);
+ isolate, subject, regexp, last_match_info);
} else {
return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
- subject, regexp, last_match_info);
+ isolate, subject, regexp, last_match_info);
}
}
- return StringReplaceRegExpWithString(subject,
+ return StringReplaceRegExpWithString(isolate,
+ subject,
regexp,
replacement,
last_match_info);
@@ -2782,7 +2927,8 @@ static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
// Perform string match of pattern on subject, starting at start index.
// Caller must ensure that 0 <= start_index <= sub->length(),
// and should check that pat->length() + start_index <= sub->length().
-int Runtime::StringMatch(Handle<String> sub,
+int Runtime::StringMatch(Isolate* isolate,
+ Handle<String> sub,
Handle<String> pat,
int start_index) {
ASSERT(0 <= start_index);
@@ -2808,20 +2954,33 @@ int Runtime::StringMatch(Handle<String> sub,
if (seq_pat->IsAsciiRepresentation()) {
Vector<const char> pat_vector = seq_pat->ToAsciiVector();
if (seq_sub->IsAsciiRepresentation()) {
- return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
+ return SearchString(isolate,
+ seq_sub->ToAsciiVector(),
+ pat_vector,
+ start_index);
}
- return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
+ return SearchString(isolate,
+ seq_sub->ToUC16Vector(),
+ pat_vector,
+ start_index);
}
Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
if (seq_sub->IsAsciiRepresentation()) {
- return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
+ return SearchString(isolate,
+ seq_sub->ToAsciiVector(),
+ pat_vector,
+ start_index);
}
- return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
+ return SearchString(isolate,
+ seq_sub->ToUC16Vector(),
+ pat_vector,
+ start_index);
}
-static MaybeObject* Runtime_StringIndexOf(Arguments args) {
- HandleScope scope; // create a new handle scope
+static MaybeObject* Runtime_StringIndexOf(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate); // create a new handle scope
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(String, sub, 0);
@@ -2832,7 +2991,8 @@ static MaybeObject* Runtime_StringIndexOf(Arguments args) {
if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
- int position = Runtime::StringMatch(sub, pat, start_index);
+ int position =
+ Runtime::StringMatch(isolate, sub, pat, start_index);
return Smi::FromInt(position);
}
@@ -2871,8 +3031,9 @@ static int StringMatchBackwards(Vector<const schar> subject,
return -1;
}
-static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
- HandleScope scope; // create a new handle scope
+static MaybeObject* Runtime_StringLastIndexOf(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate); // create a new handle scope
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(String, sub, 0);
@@ -2928,7 +3089,8 @@ static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
}
-static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
+static MaybeObject* Runtime_StringLocaleCompare(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -2958,8 +3120,10 @@ static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
str1->TryFlatten();
str2->TryFlatten();
- static StringInputBuffer buf1;
- static StringInputBuffer buf2;
+ StringInputBuffer& buf1 =
+ *isolate->runtime_state()->string_locale_compare_buf1();
+ StringInputBuffer& buf2 =
+ *isolate->runtime_state()->string_locale_compare_buf2();
buf1.Reset(str1);
buf2.Reset(str2);
@@ -2974,7 +3138,8 @@ static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
}
-static MaybeObject* Runtime_SubString(Arguments args) {
+static MaybeObject* Runtime_SubString(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 3);
@@ -2996,12 +3161,13 @@ static MaybeObject* Runtime_SubString(Arguments args) {
RUNTIME_ASSERT(end >= start);
RUNTIME_ASSERT(start >= 0);
RUNTIME_ASSERT(end <= value->length());
- Counters::sub_string_runtime.Increment();
+ isolate->counters()->sub_string_runtime()->Increment();
return value->SubString(start, end);
}
-static MaybeObject* Runtime_StringMatch(Arguments args) {
+static MaybeObject* Runtime_StringMatch(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT_EQ(3, args.length());
CONVERT_ARG_CHECKED(String, subject, 0);
@@ -3015,7 +3181,7 @@ static MaybeObject* Runtime_StringMatch(Arguments args) {
return Failure::Exception();
}
if (match->IsNull()) {
- return Heap::null_value();
+ return isolate->heap()->null_value();
}
int length = subject->length();
@@ -3040,14 +3206,14 @@ static MaybeObject* Runtime_StringMatch(Arguments args) {
}
} while (!match->IsNull());
int matches = offsets.length() / 2;
- Handle<FixedArray> elements = Factory::NewFixedArray(matches);
+ Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
for (int i = 0; i < matches ; i++) {
int from = offsets.at(i * 2);
int to = offsets.at(i * 2 + 1);
- Handle<String> match = Factory::NewSubString(subject, from, to);
+ Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
elements->set(i, *match);
}
- Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
+ Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
result->set_length(Smi::FromInt(matches));
return *result;
}
@@ -3074,7 +3240,8 @@ static void SetLastMatchInfoNoCaptures(Handle<String> subject,
template <typename SubjectChar, typename PatternChar>
-static bool SearchStringMultiple(Vector<const SubjectChar> subject,
+static bool SearchStringMultiple(Isolate* isolate,
+ Vector<const SubjectChar> subject,
Vector<const PatternChar> pattern,
String* pattern_string,
FixedArrayBuilder* builder,
@@ -3083,7 +3250,7 @@ static bool SearchStringMultiple(Vector<const SubjectChar> subject,
int subject_length = subject.length();
int pattern_length = pattern.length();
int max_search_start = subject_length - pattern_length;
- StringSearch<PatternChar, SubjectChar> search(pattern);
+ StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
while (pos <= max_search_start) {
if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
*match_pos = pos;
@@ -3116,7 +3283,8 @@ static bool SearchStringMultiple(Vector<const SubjectChar> subject,
}
-static bool SearchStringMultiple(Handle<String> subject,
+static bool SearchStringMultiple(Isolate* isolate,
+ Handle<String> subject,
Handle<String> pattern,
Handle<JSArray> last_match_info,
FixedArrayBuilder* builder) {
@@ -3132,13 +3300,15 @@ static bool SearchStringMultiple(Handle<String> subject,
if (subject->IsAsciiRepresentation()) {
Vector<const char> subject_vector = subject->ToAsciiVector();
if (pattern->IsAsciiRepresentation()) {
- if (SearchStringMultiple(subject_vector,
+ if (SearchStringMultiple(isolate,
+ subject_vector,
pattern->ToAsciiVector(),
*pattern,
builder,
&match_pos)) break;
} else {
- if (SearchStringMultiple(subject_vector,
+ if (SearchStringMultiple(isolate,
+ subject_vector,
pattern->ToUC16Vector(),
*pattern,
builder,
@@ -3147,13 +3317,15 @@ static bool SearchStringMultiple(Handle<String> subject,
} else {
Vector<const uc16> subject_vector = subject->ToUC16Vector();
if (pattern->IsAsciiRepresentation()) {
- if (SearchStringMultiple(subject_vector,
+ if (SearchStringMultiple(isolate,
+ subject_vector,
pattern->ToAsciiVector(),
*pattern,
builder,
&match_pos)) break;
} else {
- if (SearchStringMultiple(subject_vector,
+ if (SearchStringMultiple(isolate,
+ subject_vector,
pattern->ToUC16Vector(),
*pattern,
builder,
@@ -3174,6 +3346,7 @@ static bool SearchStringMultiple(Handle<String> subject,
static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
+ Isolate* isolate,
Handle<String> subject,
Handle<JSRegExp> regexp,
Handle<JSArray> last_match_array,
@@ -3204,8 +3377,10 @@ static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
match_start);
}
match_end = register_vector[1];
- HandleScope loop_scope;
- builder->Add(*Factory::NewSubString(subject, match_start, match_end));
+ HandleScope loop_scope(isolate);
+ builder->Add(*isolate->factory()->NewSubString(subject,
+ match_start,
+ match_end));
if (match_start != match_end) {
pos = match_end;
} else {
@@ -3238,6 +3413,7 @@ static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
static RegExpImpl::IrregexpResult SearchRegExpMultiple(
+ Isolate* isolate,
Handle<String> subject,
Handle<JSRegExp> regexp,
Handle<JSArray> last_match_array,
@@ -3281,31 +3457,32 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple(
{
// Avoid accumulating new handles inside loop.
- HandleScope temp_scope;
+ HandleScope temp_scope(isolate);
// Arguments array to replace function is match, captures, index and
// subject, i.e., 3 + capture count in total.
- Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
- Handle<String> match = Factory::NewSubString(subject,
- match_start,
- match_end);
+ Handle<FixedArray> elements =
+ isolate->factory()->NewFixedArray(3 + capture_count);
+ Handle<String> match = isolate->factory()->NewSubString(subject,
+ match_start,
+ match_end);
elements->set(0, *match);
for (int i = 1; i <= capture_count; i++) {
int start = register_vector[i * 2];
if (start >= 0) {
int end = register_vector[i * 2 + 1];
ASSERT(start <= end);
- Handle<String> substring = Factory::NewSubString(subject,
- start,
- end);
+ Handle<String> substring = isolate->factory()->NewSubString(subject,
+ start,
+ end);
elements->set(i, *substring);
} else {
ASSERT(register_vector[i * 2 + 1] < 0);
- elements->set(i, Heap::undefined_value());
+ elements->set(i, isolate->heap()->undefined_value());
}
}
elements->set(capture_count + 1, Smi::FromInt(match_start));
elements->set(capture_count + 2, *subject);
- builder->Add(*Factory::NewJSArrayWithElements(elements));
+ builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
}
// Swap register vectors, so the last successful match is in
// prev_register_vector.
@@ -3356,9 +3533,10 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple(
}
-static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
+static MaybeObject* Runtime_RegExpExecMultiple(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 4);
- HandleScope handles;
+ HandleScope handles(isolate);
CONVERT_ARG_CHECKED(String, subject, 1);
if (!subject->IsFlat()) { FlattenString(subject); }
@@ -3373,7 +3551,7 @@ static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
result_elements =
Handle<FixedArray>(FixedArray::cast(result_array->elements()));
} else {
- result_elements = Factory::NewFixedArrayWithHoles(16);
+ result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
}
FixedArrayBuilder builder(result_elements);
@@ -3381,31 +3559,38 @@ static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
Handle<String> pattern(
String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
ASSERT(pattern->IsFlat());
- if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
+ if (SearchStringMultiple(isolate, subject, pattern,
+ last_match_info, &builder)) {
return *builder.ToJSArray(result_array);
}
- return Heap::null_value();
+ return isolate->heap()->null_value();
}
ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
RegExpImpl::IrregexpResult result;
if (regexp->CaptureCount() == 0) {
- result = SearchRegExpNoCaptureMultiple(subject,
+ result = SearchRegExpNoCaptureMultiple(isolate,
+ subject,
regexp,
last_match_info,
&builder);
} else {
- result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
+ result = SearchRegExpMultiple(isolate,
+ subject,
+ regexp,
+ last_match_info,
+ &builder);
}
if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
- if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
+ if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
return Failure::Exception();
}
-static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
+static MaybeObject* Runtime_NumberToRadixString(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -3417,100 +3602,108 @@ static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
RUNTIME_ASSERT(radix <= 36);
// Character array used for conversion.
static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
+ return isolate->heap()->
+ LookupSingleCharacterStringFromCode(kCharTable[value]);
}
}
// Slow case.
CONVERT_DOUBLE_CHECKED(value, args[0]);
if (isnan(value)) {
- return Heap::AllocateStringFromAscii(CStrVector("NaN"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
}
if (isinf(value)) {
if (value < 0) {
- return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
}
- return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
}
CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
int radix = FastD2I(radix_number);
RUNTIME_ASSERT(2 <= radix && radix <= 36);
char* str = DoubleToRadixCString(value, radix);
- MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
+ MaybeObject* result =
+ isolate->heap()->AllocateStringFromAscii(CStrVector(str));
DeleteArray(str);
return result;
}
-static MaybeObject* Runtime_NumberToFixed(Arguments args) {
+static MaybeObject* Runtime_NumberToFixed(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_DOUBLE_CHECKED(value, args[0]);
if (isnan(value)) {
- return Heap::AllocateStringFromAscii(CStrVector("NaN"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
}
if (isinf(value)) {
if (value < 0) {
- return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
}
- return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
}
CONVERT_DOUBLE_CHECKED(f_number, args[1]);
int f = FastD2I(f_number);
RUNTIME_ASSERT(f >= 0);
char* str = DoubleToFixedCString(value, f);
- MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
+ MaybeObject* res =
+ isolate->heap()->AllocateStringFromAscii(CStrVector(str));
DeleteArray(str);
- return result;
+ return res;
}
-static MaybeObject* Runtime_NumberToExponential(Arguments args) {
+static MaybeObject* Runtime_NumberToExponential(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_DOUBLE_CHECKED(value, args[0]);
if (isnan(value)) {
- return Heap::AllocateStringFromAscii(CStrVector("NaN"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
}
if (isinf(value)) {
if (value < 0) {
- return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
}
- return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
}
CONVERT_DOUBLE_CHECKED(f_number, args[1]);
int f = FastD2I(f_number);
RUNTIME_ASSERT(f >= -1 && f <= 20);
char* str = DoubleToExponentialCString(value, f);
- MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
+ MaybeObject* res =
+ isolate->heap()->AllocateStringFromAscii(CStrVector(str));
DeleteArray(str);
- return result;
+ return res;
}
-static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
+static MaybeObject* Runtime_NumberToPrecision(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_DOUBLE_CHECKED(value, args[0]);
if (isnan(value)) {
- return Heap::AllocateStringFromAscii(CStrVector("NaN"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
}
if (isinf(value)) {
if (value < 0) {
- return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
}
- return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
+ return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
}
CONVERT_DOUBLE_CHECKED(f_number, args[1]);
int f = FastD2I(f_number);
RUNTIME_ASSERT(f >= 1 && f <= 21);
char* str = DoubleToPrecisionCString(value, f);
- MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
+ MaybeObject* res =
+ isolate->heap()->AllocateStringFromAscii(CStrVector(str));
DeleteArray(str);
- return result;
+ return res;
}
@@ -3526,7 +3719,8 @@ static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
}
-MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
+MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
+ Handle<Object> object,
uint32_t index) {
// Handle [] indexing on Strings
if (object->IsString()) {
@@ -3556,22 +3750,23 @@ MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
}
-MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
+MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
+ Handle<Object> object,
Handle<Object> key) {
- HandleScope scope;
+ HandleScope scope(isolate);
if (object->IsUndefined() || object->IsNull()) {
Handle<Object> args[2] = { key, object };
Handle<Object> error =
- Factory::NewTypeError("non_object_property_load",
- HandleVector(args, 2));
- return Top::Throw(*error);
+ isolate->factory()->NewTypeError("non_object_property_load",
+ HandleVector(args, 2));
+ return isolate->Throw(*error);
}
// Check if the given key is an array index.
uint32_t index;
if (key->ToArrayIndex(&index)) {
- return GetElementOrCharAt(object, index);
+ return GetElementOrCharAt(isolate, object, index);
}
// Convert the key to a string - possibly by calling back into JavaScript.
@@ -3589,7 +3784,7 @@ MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
// Check if the name is trivially convertible to an index and get
// the element if so.
if (name->AsArrayIndex(&index)) {
- return GetElementOrCharAt(object, index);
+ return GetElementOrCharAt(isolate, object, index);
} else {
PropertyAttributes attr;
return object->GetProperty(*name, &attr);
@@ -3597,19 +3792,21 @@ MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
}
-static MaybeObject* Runtime_GetProperty(Arguments args) {
+static MaybeObject* Runtime_GetProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
Handle<Object> object = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
- return Runtime::GetObjectProperty(object, key);
+ return Runtime::GetObjectProperty(isolate, object, key);
}
// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
-static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
+static MaybeObject* Runtime_KeyedGetProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -3633,17 +3830,18 @@ static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
if (receiver->HasFastProperties()) {
// Attempt to use lookup cache.
Map* receiver_map = receiver->map();
- int offset = KeyedLookupCache::Lookup(receiver_map, key);
+ KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
+ int offset = keyed_lookup_cache->Lookup(receiver_map, key);
if (offset != -1) {
Object* value = receiver->FastPropertyAt(offset);
- return value->IsTheHole() ? Heap::undefined_value() : value;
+ return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
}
// Lookup cache miss. Perform lookup and update the cache if appropriate.
LookupResult result;
receiver->LocalLookup(key, &result);
if (result.IsProperty() && result.type() == FIELD) {
int offset = result.GetFieldIndex();
- KeyedLookupCache::Update(receiver_map, key, offset);
+ keyed_lookup_cache->Update(receiver_map, key, offset);
return receiver->FastPropertyAt(offset);
}
} else {
@@ -3661,7 +3859,7 @@ static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
}
} else if (args[0]->IsString() && args[1]->IsSmi()) {
// Fast case for string indexing using [] with a smi index.
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<String> str = args.at<String>(0);
int index = Smi::cast(args[1])->value();
if (index >= 0 && index < str->length()) {
@@ -3671,7 +3869,8 @@ static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
}
// Fall back to GetObjectProperty.
- return Runtime::GetObjectProperty(args.at<Object>(0),
+ return Runtime::GetObjectProperty(isolate,
+ args.at<Object>(0),
args.at<Object>(1));
}
@@ -3681,9 +3880,11 @@ static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
// Steps 9c & 12 - replace an existing data property with an accessor property.
// Step 12 - update an existing accessor property with an accessor or generic
// descriptor.
-static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
+static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 5);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_CHECKED(String, name, args[1]);
CONVERT_CHECKED(Smi, flag_setter, args[2]);
@@ -3718,9 +3919,11 @@ static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
// Steps 9b & 12 - replace an existing accessor property with a data property.
// Step 12 - update an existing data property with a data or generic
// descriptor.
-static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
+static MaybeObject* Runtime_DefineOrRedefineDataProperty(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 4);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSObject, js_object, 0);
CONVERT_ARG_CHECKED(String, name, 1);
Handle<Object> obj_value = args.at<Object>(2);
@@ -3762,6 +3965,14 @@ static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
LookupResult result;
js_object->LookupRealNamedProperty(*name, &result);
+ // To be compatible with safari we do not change the value on API objects
+ // in defineProperty. Firefox disagrees here, and actually changes the value.
+ if (result.IsProperty() &&
+ (result.type() == CALLBACKS) &&
+ result.GetCallbackObject()->IsAccessorInfo()) {
+ return isolate->heap()->undefined_value();
+ }
+
// Take special care when attributes are different and there is already
// a property. For simplicity we normalize the property which enables us
// to not worry about changing the instance_descriptor and creating a new
@@ -3784,23 +3995,28 @@ static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
attr);
}
- return Runtime::ForceSetObjectProperty(js_object, name, obj_value, attr);
+ return Runtime::ForceSetObjectProperty(isolate,
+ js_object,
+ name,
+ obj_value,
+ attr);
}
-MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
+MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
+ Handle<Object> object,
Handle<Object> key,
Handle<Object> value,
PropertyAttributes attr,
StrictModeFlag strict_mode) {
- HandleScope scope;
+ HandleScope scope(isolate);
if (object->IsUndefined() || object->IsNull()) {
Handle<Object> args[2] = { key, object };
Handle<Object> error =
- Factory::NewTypeError("non_object_property_store",
- HandleVector(args, 2));
- return Top::Throw(*error);
+ isolate->factory()->NewTypeError("non_object_property_store",
+ HandleVector(args, 2));
+ return isolate->Throw(*error);
}
// If the object isn't a JavaScript object, we ignore the store.
@@ -3854,11 +4070,12 @@ MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
}
-MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
+MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
+ Handle<JSObject> js_object,
Handle<Object> key,
Handle<Object> value,
PropertyAttributes attr) {
- HandleScope scope;
+ HandleScope scope(isolate);
// Check if the given key is an array index.
uint32_t index;
@@ -3903,9 +4120,10 @@ MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
}
-MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
+MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
+ Handle<JSObject> js_object,
Handle<Object> key) {
- HandleScope scope;
+ HandleScope scope(isolate);
// Check if the given key is an array index.
uint32_t index;
@@ -3917,7 +4135,7 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
// underlying string does nothing with the deletion, we can ignore
// such deletions.
if (js_object->IsStringObjectWithCharacterAt(index)) {
- return Heap::true_value();
+ return isolate->heap()->true_value();
}
return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
@@ -3939,7 +4157,8 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
}
-static MaybeObject* Runtime_SetProperty(Arguments args) {
+static MaybeObject* Runtime_SetProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
@@ -3961,7 +4180,8 @@ static MaybeObject* Runtime_SetProperty(Arguments args) {
strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
}
- return Runtime::SetObjectProperty(object,
+ return Runtime::SetObjectProperty(isolate,
+ object,
key,
value,
attributes,
@@ -3971,7 +4191,9 @@ static MaybeObject* Runtime_SetProperty(Arguments args) {
// Set a local property, even if it is READ_ONLY. If the property does not
// exist, it will be added with attributes NONE.
-static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
+static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
CONVERT_CHECKED(JSObject, object, args[0]);
@@ -3992,7 +4214,8 @@ static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
}
-static MaybeObject* Runtime_DeleteProperty(Arguments args) {
+static MaybeObject* Runtime_DeleteProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 3);
@@ -4005,22 +4228,26 @@ static MaybeObject* Runtime_DeleteProperty(Arguments args) {
}
-static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
+static Object* HasLocalPropertyImplementation(Isolate* isolate,
+ Handle<JSObject> object,
Handle<String> key) {
- if (object->HasLocalProperty(*key)) return Heap::true_value();
+ if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
// Handle hidden prototypes. If there's a hidden prototype above this thing
// then we have to check it for properties, because they are supposed to
// look like they are on this object.
Handle<Object> proto(object->GetPrototype());
if (proto->IsJSObject() &&
Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
- return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
+ return HasLocalPropertyImplementation(isolate,
+ Handle<JSObject>::cast(proto),
+ key);
}
- return Heap::false_value();
+ return isolate->heap()->false_value();
}
-static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
+static MaybeObject* Runtime_HasLocalProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(String, key, args[1]);
@@ -4030,11 +4257,12 @@ static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
if (obj->IsJSObject()) {
JSObject* object = JSObject::cast(obj);
// Fast case - no interceptors.
- if (object->HasRealNamedProperty(key)) return Heap::true_value();
+ if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
// Slow case. Either it's not there or we have an interceptor. We should
// have handles for this kind of deal.
- HandleScope scope;
- return HasLocalPropertyImplementation(Handle<JSObject>(object),
+ HandleScope scope(isolate);
+ return HasLocalPropertyImplementation(isolate,
+ Handle<JSObject>(object),
Handle<String>(key));
} else if (obj->IsString()) {
// Well, there is one exception: Handle [] on strings.
@@ -4042,14 +4270,15 @@ static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
if (key->AsArrayIndex(&index)) {
String* string = String::cast(obj);
if (index < static_cast<uint32_t>(string->length()))
- return Heap::true_value();
+ return isolate->heap()->true_value();
}
}
- return Heap::false_value();
+ return isolate->heap()->false_value();
}
-static MaybeObject* Runtime_HasProperty(Arguments args) {
+static MaybeObject* Runtime_HasProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 2);
@@ -4057,13 +4286,14 @@ static MaybeObject* Runtime_HasProperty(Arguments args) {
if (args[0]->IsJSObject()) {
JSObject* object = JSObject::cast(args[0]);
CONVERT_CHECKED(String, key, args[1]);
- if (object->HasProperty(key)) return Heap::true_value();
+ if (object->HasProperty(key)) return isolate->heap()->true_value();
}
- return Heap::false_value();
+ return isolate->heap()->false_value();
}
-static MaybeObject* Runtime_HasElement(Arguments args) {
+static MaybeObject* Runtime_HasElement(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation na;
ASSERT(args.length() == 2);
@@ -4072,13 +4302,14 @@ static MaybeObject* Runtime_HasElement(Arguments args) {
JSObject* object = JSObject::cast(args[0]);
CONVERT_CHECKED(Smi, index_obj, args[1]);
uint32_t index = index_obj->value();
- if (object->HasElement(index)) return Heap::true_value();
+ if (object->HasElement(index)) return isolate->heap()->true_value();
}
- return Heap::false_value();
+ return isolate->heap()->false_value();
}
-static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
+static MaybeObject* Runtime_IsPropertyEnumerable(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -4087,16 +4318,17 @@ static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
uint32_t index;
if (key->AsArrayIndex(&index)) {
- return Heap::ToBoolean(object->HasElement(index));
+ return isolate->heap()->ToBoolean(object->HasElement(index));
}
PropertyAttributes att = object->GetLocalPropertyAttribute(key);
- return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
+ return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
}
-static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetPropertyNames(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSObject, object, 0);
return *GetKeysFor(object);
@@ -4108,14 +4340,15 @@ static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
// all enumerable properties of the object and its prototypes
// have none, the map of the object. This is used to speed up
// the check for deletions during a for-in.
-static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
+static MaybeObject* Runtime_GetPropertyNamesFast(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSObject, raw_object, args[0]);
if (raw_object->IsSimpleEnum()) return raw_object->map();
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<JSObject> object(raw_object);
Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
INCLUDE_PROTOS);
@@ -4144,11 +4377,12 @@ static int LocalPrototypeChainLength(JSObject* obj) {
// Return the names of the local named properties.
// args[0]: object
-static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetLocalPropertyNames(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
if (!args[0]->IsJSObject()) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
CONVERT_ARG_CHECKED(JSObject, obj, 0);
@@ -4157,9 +4391,11 @@ static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
if (obj->IsJSGlobalProxy()) {
// Only collect names if access is permitted.
if (obj->IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
- Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
- return *Factory::NewJSArray(0);
+ !isolate->MayNamedAccess(*obj,
+ isolate->heap()->undefined_value(),
+ v8::ACCESS_KEYS)) {
+ isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
+ return *isolate->factory()->NewJSArray(0);
}
obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
}
@@ -4174,11 +4410,11 @@ static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
for (int i = 0; i < length; i++) {
// Only collect names if access is permitted.
if (jsproto->IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(*jsproto,
- Heap::undefined_value(),
- v8::ACCESS_KEYS)) {
- Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
- return *Factory::NewJSArray(0);
+ !isolate->MayNamedAccess(*jsproto,
+ isolate->heap()->undefined_value(),
+ v8::ACCESS_KEYS)) {
+ isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
+ return *isolate->factory()->NewJSArray(0);
}
int n;
n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
@@ -4190,7 +4426,8 @@ static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
}
// Allocate an array with storage for all the property names.
- Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
+ Handle<FixedArray> names =
+ isolate->factory()->NewFixedArray(total_property_count);
// Get the property names.
jsproto = obj;
@@ -4209,43 +4446,45 @@ static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
// Filter out name of hidden propeties object.
if (proto_with_hidden_properties > 0) {
Handle<FixedArray> old_names = names;
- names = Factory::NewFixedArray(
+ names = isolate->factory()->NewFixedArray(
names->length() - proto_with_hidden_properties);
int dest_pos = 0;
for (int i = 0; i < total_property_count; i++) {
Object* name = old_names->get(i);
- if (name == Heap::hidden_symbol()) {
+ if (name == isolate->heap()->hidden_symbol()) {
continue;
}
names->set(dest_pos++, name);
}
}
- return *Factory::NewJSArrayWithElements(names);
+ return *isolate->factory()->NewJSArrayWithElements(names);
}
// Return the names of the local indexed properties.
// args[0]: object
-static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetLocalElementNames(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
if (!args[0]->IsJSObject()) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
CONVERT_ARG_CHECKED(JSObject, obj, 0);
int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
- Handle<FixedArray> names = Factory::NewFixedArray(n);
+ Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
- return *Factory::NewJSArrayWithElements(names);
+ return *isolate->factory()->NewJSArrayWithElements(names);
}
// Return information on whether an object has a named or indexed interceptor.
// args[0]: object
-static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetInterceptorInfo(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
if (!args[0]->IsJSObject()) {
return Smi::FromInt(0);
@@ -4262,8 +4501,10 @@ static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
// Return property names from named interceptor.
// args[0]: object
-static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSObject, obj, 0);
@@ -4271,14 +4512,16 @@ static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// Return element names from indexed interceptor.
// args[0]: object
-static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetIndexedInterceptorElementNames(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSObject, obj, 0);
@@ -4286,28 +4529,29 @@ static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_LocalKeys(Arguments args) {
+static MaybeObject* Runtime_LocalKeys(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT_EQ(args.length(), 1);
CONVERT_CHECKED(JSObject, raw_object, args[0]);
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<JSObject> object(raw_object);
if (object->IsJSGlobalProxy()) {
// Do access checks before going to the global object.
if (object->IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(*object, Heap::undefined_value(),
+ !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
v8::ACCESS_KEYS)) {
- Top::ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
- return *Factory::NewJSArray(0);
+ isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
+ return *isolate->factory()->NewJSArray(0);
}
Handle<Object> proto(object->GetPrototype());
// If proxy is detached we simply return an empty array.
- if (proto->IsNull()) return *Factory::NewJSArray(0);
+ if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
object = Handle<JSObject>::cast(proto);
}
@@ -4317,24 +4561,26 @@ static MaybeObject* Runtime_LocalKeys(Arguments args) {
// property array and since the result is mutable we have to create
// a fresh clone on each invocation.
int length = contents->length();
- Handle<FixedArray> copy = Factory::NewFixedArray(length);
+ Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
for (int i = 0; i < length; i++) {
Object* entry = contents->get(i);
if (entry->IsString()) {
copy->set(i, entry);
} else {
ASSERT(entry->IsNumber());
- HandleScope scope;
- Handle<Object> entry_handle(entry);
- Handle<Object> entry_str = Factory::NumberToString(entry_handle);
+ HandleScope scope(isolate);
+ Handle<Object> entry_handle(entry, isolate);
+ Handle<Object> entry_str =
+ isolate->factory()->NumberToString(entry_handle);
copy->set(i, *entry_str);
}
}
- return *Factory::NewJSArrayWithElements(copy);
+ return *isolate->factory()->NewJSArrayWithElements(copy);
}
-static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
+static MaybeObject* Runtime_GetArgumentsProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -4344,7 +4590,7 @@ static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
JavaScriptFrame* frame = it.frame();
// Get the actual number of provided arguments.
- const uint32_t n = frame->GetProvidedParametersCount();
+ const uint32_t n = frame->ComputeParametersCount();
// Try to convert the key to an index. If successful and within
// index return the the argument from the frame.
@@ -4354,7 +4600,7 @@ static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
}
// Convert the key to a string.
- HandleScope scope;
+ HandleScope scope(isolate);
bool exception = false;
Handle<Object> converted =
Execution::ToString(args.at<Object>(0), &exception);
@@ -4366,21 +4612,30 @@ static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
if (index < n) {
return frame->GetParameter(index);
} else {
- return Top::initial_object_prototype()->GetElement(index);
+ return isolate->initial_object_prototype()->GetElement(index);
}
}
// Handle special arguments properties.
- if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
- if (key->Equals(Heap::callee_symbol())) return frame->function();
+ if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
+ if (key->Equals(isolate->heap()->callee_symbol())) {
+ Object* function = frame->function();
+ if (function->IsJSFunction() &&
+ JSFunction::cast(function)->shared()->strict_mode()) {
+ return isolate->Throw(*isolate->factory()->NewTypeError(
+ "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
+ }
+ return function;
+ }
// Lookup in the initial Object.prototype object.
- return Top::initial_object_prototype()->GetProperty(*key);
+ return isolate->initial_object_prototype()->GetProperty(*key);
}
-static MaybeObject* Runtime_ToFastProperties(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_ToFastProperties(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
Handle<Object> object = args.at<Object>(0);
@@ -4395,8 +4650,9 @@ static MaybeObject* Runtime_ToFastProperties(Arguments args) {
}
-static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_ToSlowProperties(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
Handle<Object> object = args.at<Object>(0);
@@ -4408,7 +4664,8 @@ static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
}
-static MaybeObject* Runtime_ToBool(Arguments args) {
+static MaybeObject* Runtime_ToBool(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -4418,37 +4675,40 @@ static MaybeObject* Runtime_ToBool(Arguments args) {
// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
// Possible optimizations: put the type string into the oddballs.
-static MaybeObject* Runtime_Typeof(Arguments args) {
+static MaybeObject* Runtime_Typeof(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
Object* obj = args[0];
- if (obj->IsNumber()) return Heap::number_symbol();
+ if (obj->IsNumber()) return isolate->heap()->number_symbol();
HeapObject* heap_obj = HeapObject::cast(obj);
// typeof an undetectable object is 'undefined'
- if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
+ if (heap_obj->map()->is_undetectable()) {
+ return isolate->heap()->undefined_symbol();
+ }
InstanceType instance_type = heap_obj->map()->instance_type();
if (instance_type < FIRST_NONSTRING_TYPE) {
- return Heap::string_symbol();
+ return isolate->heap()->string_symbol();
}
switch (instance_type) {
case ODDBALL_TYPE:
if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
- return Heap::boolean_symbol();
+ return isolate->heap()->boolean_symbol();
}
if (heap_obj->IsNull()) {
- return Heap::object_symbol();
+ return isolate->heap()->object_symbol();
}
ASSERT(heap_obj->IsUndefined());
- return Heap::undefined_symbol();
+ return isolate->heap()->undefined_symbol();
case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
- return Heap::function_symbol();
+ return isolate->heap()->function_symbol();
default:
// For any kind of object not handled above, the spec rule for
// host objects gives that it is okay to return "object"
- return Heap::object_symbol();
+ return isolate->heap()->object_symbol();
}
}
@@ -4475,7 +4735,8 @@ static int ParseDecimalInteger(const char*s, int from, int to) {
}
-static MaybeObject* Runtime_StringToNumber(Arguments args) {
+static MaybeObject* Runtime_StringToNumber(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(String, subject, args[0]);
@@ -4491,21 +4752,21 @@ static MaybeObject* Runtime_StringToNumber(Arguments args) {
int start_pos = (minus ? 1 : 0);
if (start_pos == len) {
- return Heap::nan_value();
+ return isolate->heap()->nan_value();
} else if (data[start_pos] > '9') {
// Fast check for a junk value. A valid string may start from a
// whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
// the 'I' character ('Infinity'). All of that have codes not greater than
// '9' except 'I'.
if (data[start_pos] != 'I') {
- return Heap::nan_value();
+ return isolate->heap()->nan_value();
}
} else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
// The maximal/minimal smi has 10 digits. If the string has less digits we
// know it will fit into the smi-data type.
int d = ParseDecimalInteger(data, start_pos, len);
if (minus) {
- if (d == 0) return Heap::minus_zero_value();
+ if (d == 0) return isolate->heap()->minus_zero_value();
d = -d;
} else if (!subject->HasHashCode() &&
len <= String::kMaxArrayIndexSize &&
@@ -4525,11 +4786,13 @@ static MaybeObject* Runtime_StringToNumber(Arguments args) {
}
// Slower case.
- return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
+ return isolate->heap()->NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
}
-static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
+static MaybeObject* Runtime_StringFromCharCodeArray(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -4552,9 +4815,9 @@ static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
MaybeObject* maybe_object = NULL;
if (i == length) { // The string is ASCII.
- maybe_object = Heap::AllocateRawAsciiString(length);
+ maybe_object = isolate->heap()->AllocateRawAsciiString(length);
} else { // The string is not ASCII.
- maybe_object = Heap::AllocateRawTwoByteString(length);
+ maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
}
Object* object = NULL;
@@ -4609,7 +4872,8 @@ static bool IsNotEscaped(uint16_t character) {
}
-static MaybeObject* Runtime_URIEscape(Arguments args) {
+static MaybeObject* Runtime_URIEscape(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
const char hex_chars[] = "0123456789ABCDEF";
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -4620,7 +4884,8 @@ static MaybeObject* Runtime_URIEscape(Arguments args) {
int escaped_length = 0;
int length = source->length();
{
- Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
+ Access<StringInputBuffer> buffer(
+ isolate->runtime_state()->string_input_buffer());
buffer->Reset(source);
while (buffer->has_more()) {
uint16_t character = buffer->GetNext();
@@ -4634,7 +4899,7 @@ static MaybeObject* Runtime_URIEscape(Arguments args) {
// We don't allow strings that are longer than a maximal length.
ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
if (escaped_length > String::kMaxLength) {
- Top::context()->mark_out_of_memory();
+ isolate->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
}
@@ -4644,13 +4909,15 @@ static MaybeObject* Runtime_URIEscape(Arguments args) {
return source;
}
Object* o;
- { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
+ { MaybeObject* maybe_o =
+ isolate->heap()->AllocateRawAsciiString(escaped_length);
if (!maybe_o->ToObject(&o)) return maybe_o;
}
String* destination = String::cast(o);
int dest_position = 0;
- Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
+ Access<StringInputBuffer> buffer(
+ isolate->runtime_state()->string_input_buffer());
buffer->Rewind();
while (buffer->has_more()) {
uint16_t chr = buffer->GetNext();
@@ -4725,7 +4992,8 @@ static inline int Unescape(String* source,
}
-static MaybeObject* Runtime_URIUnescape(Arguments args) {
+static MaybeObject* Runtime_URIUnescape(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(String, source, args[0]);
@@ -4749,9 +5017,10 @@ static MaybeObject* Runtime_URIUnescape(Arguments args) {
return source;
Object* o;
- { MaybeObject* maybe_o = ascii ?
- Heap::AllocateRawAsciiString(unescaped_length) :
- Heap::AllocateRawTwoByteString(unescaped_length);
+ { MaybeObject* maybe_o =
+ ascii ?
+ isolate->heap()->AllocateRawAsciiString(unescaped_length) :
+ isolate->heap()->AllocateRawTwoByteString(unescaped_length);
if (!maybe_o->ToObject(&o)) return maybe_o;
}
String* destination = String::cast(o);
@@ -4836,23 +5105,24 @@ static const byte JsonQuoteLengths[kQuoteTableLength] = {
template <typename StringType>
-MaybeObject* AllocateRawString(int length);
+MaybeObject* AllocateRawString(Isolate* isolate, int length);
template <>
-MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
- return Heap::AllocateRawTwoByteString(length);
+MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
+ return isolate->heap()->AllocateRawTwoByteString(length);
}
template <>
-MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
- return Heap::AllocateRawAsciiString(length);
+MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
+ return isolate->heap()->AllocateRawAsciiString(length);
}
template <typename Char, typename StringType, bool comma>
-static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
+static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
+ Vector<const Char> characters) {
int length = characters.length();
const Char* read_cursor = characters.start();
const Char* end = read_cursor + length;
@@ -4866,7 +5136,8 @@ static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
}
}
- MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
+ MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
+ quoted_length);
Object* new_object;
if (!new_alloc->ToObject(&new_object)) {
return new_alloc;
@@ -4898,29 +5169,31 @@ static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
template <typename Char, typename StringType, bool comma>
-static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
+static MaybeObject* QuoteJsonString(Isolate* isolate,
+ Vector<const Char> characters) {
int length = characters.length();
- Counters::quote_json_char_count.Increment(length);
+ isolate->counters()->quote_json_char_count()->Increment(length);
const int kSpaceForQuotes = 2 + (comma ? 1 :0);
int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
if (worst_case_length > kMaxGuaranteedNewSpaceString) {
- return SlowQuoteJsonString<Char, StringType, comma>(characters);
+ return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
}
- MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
+ MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
+ worst_case_length);
Object* new_object;
if (!new_alloc->ToObject(&new_object)) {
return new_alloc;
}
- if (!Heap::new_space()->Contains(new_object)) {
+ if (!isolate->heap()->new_space()->Contains(new_object)) {
// Even if our string is small enough to fit in new space we still have to
// handle it being allocated in old space as may happen in the third
// attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
// CEntryStub::GenerateCore.
- return SlowQuoteJsonString<Char, StringType, comma>(characters);
+ return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
}
StringType* new_string = StringType::cast(new_object);
- ASSERT(Heap::new_space()->Contains(new_string));
+ ASSERT(isolate->heap()->new_space()->Contains(new_string));
STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
Char* write_cursor = reinterpret_cast<Char*>(
@@ -4957,13 +5230,15 @@ static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
int final_length = static_cast<int>(
write_cursor - reinterpret_cast<Char*>(
new_string->address() + SeqAsciiString::kHeaderSize));
- Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
- final_length);
+ isolate->heap()->new_space()->
+ template ShrinkStringAtAllocationBoundary<StringType>(
+ new_string, final_length);
return new_string;
}
-static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
+static MaybeObject* Runtime_QuoteJSONString(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
CONVERT_CHECKED(String, str, args[0]);
if (!str->IsFlat()) {
@@ -4976,14 +5251,17 @@ static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
ASSERT(str->IsFlat());
}
if (str->IsTwoByteRepresentation()) {
- return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
+ return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
+ str->ToUC16Vector());
} else {
- return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
+ return QuoteJsonString<char, SeqAsciiString, false>(isolate,
+ str->ToAsciiVector());
}
}
-static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
+static MaybeObject* Runtime_QuoteJSONStringComma(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
CONVERT_CHECKED(String, str, args[0]);
if (!str->IsFlat()) {
@@ -4996,14 +5274,16 @@ static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
ASSERT(str->IsFlat());
}
if (str->IsTwoByteRepresentation()) {
- return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
+ return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
+ str->ToUC16Vector());
} else {
- return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
+ return QuoteJsonString<char, SeqAsciiString, true>(isolate,
+ str->ToAsciiVector());
}
}
-
-static MaybeObject* Runtime_StringParseInt(Arguments args) {
+static MaybeObject* Runtime_StringParseInt(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
CONVERT_CHECKED(String, s, args[0]);
@@ -5013,11 +5293,12 @@ static MaybeObject* Runtime_StringParseInt(Arguments args) {
RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
double value = StringToInt(s, radix);
- return Heap::NumberFromDouble(value);
+ return isolate->heap()->NumberFromDouble(value);
}
-static MaybeObject* Runtime_StringParseFloat(Arguments args) {
+static MaybeObject* Runtime_StringParseFloat(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
CONVERT_CHECKED(String, str, args[0]);
@@ -5025,16 +5306,13 @@ static MaybeObject* Runtime_StringParseFloat(Arguments args) {
double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
// Create a number object from the value.
- return Heap::NumberFromDouble(value);
+ return isolate->heap()->NumberFromDouble(value);
}
-static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
-static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
-
-
template <class Converter>
MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
+ Isolate* isolate,
String* s,
int length,
int input_string_length,
@@ -5052,8 +5330,8 @@ MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
// dependent upper/lower conversions.
Object* o;
{ MaybeObject* maybe_o = s->IsAsciiRepresentation()
- ? Heap::AllocateRawAsciiString(length)
- : Heap::AllocateRawTwoByteString(length);
+ ? isolate->heap()->AllocateRawAsciiString(length)
+ : isolate->heap()->AllocateRawTwoByteString(length);
if (!maybe_o->ToObject(&o)) return maybe_o;
}
String* result = String::cast(o);
@@ -5061,7 +5339,8 @@ MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
// Convert all characters to upper case, assuming that they will fit
// in the buffer
- Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
+ Access<StringInputBuffer> buffer(
+ isolate->runtime_state()->string_input_buffer());
buffer->Reset(s);
unibrow::uchar chars[Converter::kMaxWidth];
// We can assume that the string is not empty
@@ -5108,7 +5387,7 @@ MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
if (char_length == 0) char_length = 1;
current_length += char_length;
if (current_length > Smi::kMaxValue) {
- Top::context()->mark_out_of_memory();
+ isolate->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
}
@@ -5266,6 +5545,7 @@ struct ToUpperTraits {
template <typename ConvertTraits>
MUST_USE_RESULT static MaybeObject* ConvertCase(
Arguments args,
+ Isolate* isolate,
unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
NoHandleAllocation ha;
CONVERT_CHECKED(String, s, args[0]);
@@ -5283,7 +5563,7 @@ MUST_USE_RESULT static MaybeObject* ConvertCase(
// dependent upper/lower conversions.
if (s->IsSeqAsciiString()) {
Object* o;
- { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
+ { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
if (!maybe_o->ToObject(&o)) return maybe_o;
}
SeqAsciiString* result = SeqAsciiString::cast(o);
@@ -5293,13 +5573,15 @@ MUST_USE_RESULT static MaybeObject* ConvertCase(
}
Object* answer;
- { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
+ { MaybeObject* maybe_answer =
+ ConvertCaseHelper(isolate, s, length, length, mapping);
if (!maybe_answer->ToObject(&answer)) return maybe_answer;
}
if (answer->IsSmi()) {
// Retry with correct length.
{ MaybeObject* maybe_answer =
- ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
+ ConvertCaseHelper(isolate,
+ s, Smi::cast(answer)->value(), length, mapping);
if (!maybe_answer->ToObject(&answer)) return maybe_answer;
}
}
@@ -5307,13 +5589,17 @@ MUST_USE_RESULT static MaybeObject* ConvertCase(
}
-static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
- return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
+static MaybeObject* Runtime_StringToLowerCase(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ return ConvertCase<ToLowerTraits>(
+ args, isolate, isolate->runtime_state()->to_lower_mapping());
}
-static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
- return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
+static MaybeObject* Runtime_StringToUpperCase(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ return ConvertCase<ToUpperTraits>(
+ args, isolate, isolate->runtime_state()->to_upper_mapping());
}
@@ -5322,7 +5608,8 @@ static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
}
-static MaybeObject* Runtime_StringTrim(Arguments args) {
+static MaybeObject* Runtime_StringTrim(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 3);
@@ -5351,14 +5638,15 @@ static MaybeObject* Runtime_StringTrim(Arguments args) {
template <typename SubjectChar, typename PatternChar>
-void FindStringIndices(Vector<const SubjectChar> subject,
+void FindStringIndices(Isolate* isolate,
+ Vector<const SubjectChar> subject,
Vector<const PatternChar> pattern,
ZoneList<int>* indices,
unsigned int limit) {
ASSERT(limit > 0);
// Collect indices of pattern in subject, and the end-of-string index.
// Stop after finding at most limit values.
- StringSearch<PatternChar, SubjectChar> search(pattern);
+ StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
int pattern_length = pattern.length();
int index = 0;
while (limit > 0) {
@@ -5371,9 +5659,10 @@ void FindStringIndices(Vector<const SubjectChar> subject,
}
-static MaybeObject* Runtime_StringSplit(Arguments args) {
+static MaybeObject* Runtime_StringSplit(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 3);
- HandleScope handle_scope;
+ HandleScope handle_scope(isolate);
CONVERT_ARG_CHECKED(String, subject, 0);
CONVERT_ARG_CHECKED(String, pattern, 1);
CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
@@ -5403,12 +5692,14 @@ static MaybeObject* Runtime_StringSplit(Arguments args) {
if (subject->IsAsciiRepresentation()) {
Vector<const char> subject_vector = subject->ToAsciiVector();
if (pattern->IsAsciiRepresentation()) {
- FindStringIndices(subject_vector,
+ FindStringIndices(isolate,
+ subject_vector,
pattern->ToAsciiVector(),
&indices,
limit);
} else {
- FindStringIndices(subject_vector,
+ FindStringIndices(isolate,
+ subject_vector,
pattern->ToUC16Vector(),
&indices,
limit);
@@ -5416,12 +5707,14 @@ static MaybeObject* Runtime_StringSplit(Arguments args) {
} else {
Vector<const uc16> subject_vector = subject->ToUC16Vector();
if (pattern->IsAsciiRepresentation()) {
- FindStringIndices(subject_vector,
+ FindStringIndices(isolate,
+ subject_vector,
pattern->ToAsciiVector(),
&indices,
limit);
} else {
- FindStringIndices(subject_vector,
+ FindStringIndices(isolate,
+ subject_vector,
pattern->ToUC16Vector(),
&indices,
limit);
@@ -5438,7 +5731,7 @@ static MaybeObject* Runtime_StringSplit(Arguments args) {
// Create JSArray of substrings separated by separator.
int part_count = indices.length();
- Handle<JSArray> result = Factory::NewJSArray(part_count);
+ Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
result->set_length(Smi::FromInt(part_count));
ASSERT(result->HasFastElements());
@@ -5454,7 +5747,7 @@ static MaybeObject* Runtime_StringSplit(Arguments args) {
HandleScope local_loop_handle;
int part_end = indices.at(i);
Handle<String> substring =
- Factory::NewSubString(subject, part_start, part_end);
+ isolate->factory()->NewSubString(subject, part_start, part_end);
elements->set(i, *substring);
part_start = part_end + pattern_length;
}
@@ -5467,17 +5760,18 @@ static MaybeObject* Runtime_StringSplit(Arguments args) {
// one-char strings in the cache. Gives up on the first char that is
// not in the cache and fills the remainder with smi zeros. Returns
// the length of the successfully copied prefix.
-static int CopyCachedAsciiCharsToArray(const char* chars,
+static int CopyCachedAsciiCharsToArray(Heap* heap,
+ const char* chars,
FixedArray* elements,
int length) {
AssertNoAllocation nogc;
- FixedArray* ascii_cache = Heap::single_character_string_cache();
- Object* undefined = Heap::undefined_value();
+ FixedArray* ascii_cache = heap->single_character_string_cache();
+ Object* undefined = heap->undefined_value();
int i;
for (i = 0; i < length; ++i) {
Object* value = ascii_cache->get(chars[i]);
if (value == undefined) break;
- ASSERT(!Heap::InNewSpace(value));
+ ASSERT(!heap->InNewSpace(value));
elements->set(i, value, SKIP_WRITE_BARRIER);
}
if (i < length) {
@@ -5497,8 +5791,9 @@ static int CopyCachedAsciiCharsToArray(const char* chars,
// Converts a String to JSArray.
// For example, "foo" => ["f", "o", "o"].
-static MaybeObject* Runtime_StringToArray(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_StringToArray(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(String, s, 0);
CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
@@ -5509,15 +5804,17 @@ static MaybeObject* Runtime_StringToArray(Arguments args) {
Handle<FixedArray> elements;
if (s->IsFlat() && s->IsAsciiRepresentation()) {
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
+ { MaybeObject* maybe_obj =
+ isolate->heap()->AllocateUninitializedFixedArray(length);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- elements = Handle<FixedArray>(FixedArray::cast(obj));
+ elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
Vector<const char> chars = s->ToAsciiVector();
// Note, this will initialize all elements (not only the prefix)
// to prevent GC from seeing partially initialized array.
- int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
+ int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
+ chars.start(),
*elements,
length);
@@ -5526,7 +5823,7 @@ static MaybeObject* Runtime_StringToArray(Arguments args) {
elements->set(i, *str);
}
} else {
- elements = Factory::NewFixedArray(length);
+ elements = isolate->factory()->NewFixedArray(length);
for (int i = 0; i < length; ++i) {
Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
elements->set(i, *str);
@@ -5539,11 +5836,12 @@ static MaybeObject* Runtime_StringToArray(Arguments args) {
}
#endif
- return *Factory::NewJSArrayWithElements(elements);
+ return *isolate->factory()->NewJSArrayWithElements(elements);
}
-static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
+static MaybeObject* Runtime_NewStringWrapper(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(String, value, args[0]);
@@ -5551,36 +5849,40 @@ static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
}
-bool Runtime::IsUpperCaseChar(uint16_t ch) {
+bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
- int char_length = to_upper_mapping.get(ch, 0, chars);
+ int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
return char_length == 0;
}
-static MaybeObject* Runtime_NumberToString(Arguments args) {
+static MaybeObject* Runtime_NumberToString(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
Object* number = args[0];
RUNTIME_ASSERT(number->IsNumber());
- return Heap::NumberToString(number);
+ return isolate->heap()->NumberToString(number);
}
-static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
+static MaybeObject* Runtime_NumberToStringSkipCache(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
Object* number = args[0];
RUNTIME_ASSERT(number->IsNumber());
- return Heap::NumberToString(number, false);
+ return isolate->heap()->NumberToString(number, false);
}
-static MaybeObject* Runtime_NumberToInteger(Arguments args) {
+static MaybeObject* Runtime_NumberToInteger(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -5590,11 +5892,13 @@ static MaybeObject* Runtime_NumberToInteger(Arguments args) {
if (number > 0 && number <= Smi::kMaxValue) {
return Smi::FromInt(static_cast<int>(number));
}
- return Heap::NumberFromDouble(DoubleToInteger(number));
+ return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
}
-static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
+static MaybeObject* Runtime_NumberToIntegerMapMinusZero(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -5609,20 +5913,22 @@ static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
// Map both -0 and +0 to +0.
if (double_value == 0) double_value = 0;
- return Heap::NumberFromDouble(double_value);
+ return isolate->heap()->NumberFromDouble(double_value);
}
-static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
+static MaybeObject* Runtime_NumberToJSUint32(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
- return Heap::NumberFromUint32(number);
+ return isolate->heap()->NumberFromUint32(number);
}
-static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
+static MaybeObject* Runtime_NumberToJSInt32(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -5632,13 +5938,14 @@ static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
if (number > 0 && number <= Smi::kMaxValue) {
return Smi::FromInt(static_cast<int>(number));
}
- return Heap::NumberFromInt32(DoubleToInt32(number));
+ return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
}
// Converts a Number to a Smi, if possible. Returns NaN if the number is not
// a small integer.
-static MaybeObject* Runtime_NumberToSmi(Arguments args) {
+static MaybeObject* Runtime_NumberToSmi(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -5653,75 +5960,83 @@ static MaybeObject* Runtime_NumberToSmi(Arguments args) {
return Smi::FromInt(int_value);
}
}
- return Heap::nan_value();
+ return isolate->heap()->nan_value();
}
-static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
+static MaybeObject* Runtime_AllocateHeapNumber(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 0);
- return Heap::AllocateHeapNumber(0);
+ return isolate->heap()->AllocateHeapNumber(0);
}
-static MaybeObject* Runtime_NumberAdd(Arguments args) {
+static MaybeObject* Runtime_NumberAdd(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
- return Heap::NumberFromDouble(x + y);
+ return isolate->heap()->NumberFromDouble(x + y);
}
-static MaybeObject* Runtime_NumberSub(Arguments args) {
+static MaybeObject* Runtime_NumberSub(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
- return Heap::NumberFromDouble(x - y);
+ return isolate->heap()->NumberFromDouble(x - y);
}
-static MaybeObject* Runtime_NumberMul(Arguments args) {
+static MaybeObject* Runtime_NumberMul(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
- return Heap::NumberFromDouble(x * y);
+ return isolate->heap()->NumberFromDouble(x * y);
}
-static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
+static MaybeObject* Runtime_NumberUnaryMinus(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return Heap::NumberFromDouble(-x);
+ return isolate->heap()->NumberFromDouble(-x);
}
-static MaybeObject* Runtime_NumberAlloc(Arguments args) {
+static MaybeObject* Runtime_NumberAlloc(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 0);
- return Heap::NumberFromDouble(9876543210.0);
+ return isolate->heap()->NumberFromDouble(9876543210.0);
}
-static MaybeObject* Runtime_NumberDiv(Arguments args) {
+static MaybeObject* Runtime_NumberDiv(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
- return Heap::NumberFromDouble(x / y);
+ return isolate->heap()->NumberFromDouble(x / y);
}
-static MaybeObject* Runtime_NumberMod(Arguments args) {
+static MaybeObject* Runtime_NumberMod(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -5730,17 +6045,18 @@ static MaybeObject* Runtime_NumberMod(Arguments args) {
x = modulo(x, y);
// NumberFromDouble may return a Smi instead of a Number object
- return Heap::NumberFromDouble(x);
+ return isolate->heap()->NumberFromDouble(x);
}
-static MaybeObject* Runtime_StringAdd(Arguments args) {
+static MaybeObject* Runtime_StringAdd(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(String, str1, args[0]);
CONVERT_CHECKED(String, str2, args[1]);
- Counters::string_add_runtime.Increment();
- return Heap::AllocateConsString(str1, str2);
+ isolate->counters()->string_add_runtime()->Increment();
+ return isolate->heap()->AllocateConsString(str1, str2);
}
@@ -5783,12 +6099,13 @@ static inline void StringBuilderConcatHelper(String* special,
}
-static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
+static MaybeObject* Runtime_StringBuilderConcat(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 3);
CONVERT_CHECKED(JSArray, array, args[0]);
if (!args[1]->IsSmi()) {
- Top::context()->mark_out_of_memory();
+ isolate->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
int array_length = Smi::cast(args[1])->value();
@@ -5799,7 +6116,7 @@ static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
int special_length = special->length();
if (!array->HasFastElements()) {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
if (fixed_array->length() < array_length) {
@@ -5807,7 +6124,7 @@ static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
}
if (array_length == 0) {
- return Heap::empty_string();
+ return isolate->heap()->empty_string();
} else if (array_length == 1) {
Object* first = fixed_array->get(0);
if (first->IsString()) return first;
@@ -5833,21 +6150,21 @@ static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
// Get the position and check that it is a positive smi.
i++;
if (i >= array_length) {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
Object* next_smi = fixed_array->get(i);
if (!next_smi->IsSmi()) {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
pos = Smi::cast(next_smi)->value();
if (pos < 0) {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
}
ASSERT(pos >= 0);
ASSERT(len >= 0);
if (pos > special_length || len > special_length - pos) {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
increment = len;
} else if (elt->IsString()) {
@@ -5858,10 +6175,10 @@ static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
ascii = false;
}
} else {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
if (increment > String::kMaxLength - position) {
- Top::context()->mark_out_of_memory();
+ isolate->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
position += increment;
@@ -5871,7 +6188,8 @@ static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
Object* object;
if (ascii) {
- { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
+ { MaybeObject* maybe_object =
+ isolate->heap()->AllocateRawAsciiString(length);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
SeqAsciiString* answer = SeqAsciiString::cast(object);
@@ -5881,7 +6199,8 @@ static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
array_length);
return answer;
} else {
- { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
+ { MaybeObject* maybe_object =
+ isolate->heap()->AllocateRawTwoByteString(length);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
SeqTwoByteString* answer = SeqTwoByteString::cast(object);
@@ -5894,19 +6213,20 @@ static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
}
-static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
+static MaybeObject* Runtime_StringBuilderJoin(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 3);
CONVERT_CHECKED(JSArray, array, args[0]);
if (!args[1]->IsSmi()) {
- Top::context()->mark_out_of_memory();
+ isolate->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
int array_length = Smi::cast(args[1])->value();
CONVERT_CHECKED(String, separator, args[2]);
if (!array->HasFastElements()) {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
if (fixed_array->length() < array_length) {
@@ -5914,7 +6234,7 @@ static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
}
if (array_length == 0) {
- return Heap::empty_string();
+ return isolate->heap()->empty_string();
} else if (array_length == 1) {
Object* first = fixed_array->get(0);
if (first->IsString()) return first;
@@ -5924,7 +6244,7 @@ static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
int max_nof_separators =
(String::kMaxLength + separator_length - 1) / separator_length;
if (max_nof_separators < (array_length - 1)) {
- Top::context()->mark_out_of_memory();
+ isolate->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
int length = (array_length - 1) * separator_length;
@@ -5932,19 +6252,20 @@ static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
Object* element_obj = fixed_array->get(i);
if (!element_obj->IsString()) {
// TODO(1161): handle this case.
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
String* element = String::cast(element_obj);
int increment = element->length();
if (increment > String::kMaxLength - length) {
- Top::context()->mark_out_of_memory();
+ isolate->context()->mark_out_of_memory();
return Failure::OutOfMemoryException();
}
length += increment;
}
Object* object;
- { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
+ { MaybeObject* maybe_object =
+ isolate->heap()->AllocateRawTwoByteString(length);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
SeqTwoByteString* answer = SeqTwoByteString::cast(object);
@@ -5977,76 +6298,84 @@ static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
}
-static MaybeObject* Runtime_NumberOr(Arguments args) {
+static MaybeObject* Runtime_NumberOr(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
- return Heap::NumberFromInt32(x | y);
+ return isolate->heap()->NumberFromInt32(x | y);
}
-static MaybeObject* Runtime_NumberAnd(Arguments args) {
+static MaybeObject* Runtime_NumberAnd(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
- return Heap::NumberFromInt32(x & y);
+ return isolate->heap()->NumberFromInt32(x & y);
}
-static MaybeObject* Runtime_NumberXor(Arguments args) {
+static MaybeObject* Runtime_NumberXor(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
- return Heap::NumberFromInt32(x ^ y);
+ return isolate->heap()->NumberFromInt32(x ^ y);
}
-static MaybeObject* Runtime_NumberNot(Arguments args) {
+static MaybeObject* Runtime_NumberNot(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
- return Heap::NumberFromInt32(~x);
+ return isolate->heap()->NumberFromInt32(~x);
}
-static MaybeObject* Runtime_NumberShl(Arguments args) {
+static MaybeObject* Runtime_NumberShl(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
- return Heap::NumberFromInt32(x << (y & 0x1f));
+ return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
}
-static MaybeObject* Runtime_NumberShr(Arguments args) {
+static MaybeObject* Runtime_NumberShr(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
- return Heap::NumberFromUint32(x >> (y & 0x1f));
+ return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
}
-static MaybeObject* Runtime_NumberSar(Arguments args) {
+static MaybeObject* Runtime_NumberSar(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
- return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
+ return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
}
-static MaybeObject* Runtime_NumberEquals(Arguments args) {
+static MaybeObject* Runtime_NumberEquals(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -6065,7 +6394,8 @@ static MaybeObject* Runtime_NumberEquals(Arguments args) {
}
-static MaybeObject* Runtime_StringEquals(Arguments args) {
+static MaybeObject* Runtime_StringEquals(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -6083,7 +6413,8 @@ static MaybeObject* Runtime_StringEquals(Arguments args) {
}
-static MaybeObject* Runtime_NumberCompare(Arguments args) {
+static MaybeObject* Runtime_NumberCompare(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 3);
@@ -6098,15 +6429,12 @@ static MaybeObject* Runtime_NumberCompare(Arguments args) {
// Compare two Smis as if they were converted to strings and then
// compared lexicographically.
-static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
+static MaybeObject* Runtime_SmiLexicographicCompare(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- // Arrays for the individual characters of the two Smis. Smis are
- // 31 bit integers and 10 decimal digits are therefore enough.
- static int x_elms[10];
- static int y_elms[10];
-
// Extract the integer values from the Smis.
CONVERT_CHECKED(Smi, x, args[0]);
CONVERT_CHECKED(Smi, y, args[1]);
@@ -6130,6 +6458,13 @@ static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
y_value = -y_value;
}
+ // Arrays for the individual characters of the two Smis. Smis are
+ // 31 bit integers and 10 decimal digits are therefore enough.
+ // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
+ int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
+ int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
+
+
// Convert the integers to arrays of their decimal digits.
int x_index = 0;
int y_index = 0;
@@ -6156,9 +6491,11 @@ static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
}
-static Object* StringInputBufferCompare(String* x, String* y) {
- static StringInputBuffer bufx;
- static StringInputBuffer bufy;
+static Object* StringInputBufferCompare(RuntimeState* state,
+ String* x,
+ String* y) {
+ StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
+ StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
bufx.Reset(x);
bufy.Reset(y);
while (bufx.has_more() && bufy.has_more()) {
@@ -6211,19 +6548,21 @@ static Object* FlatStringCompare(String* x, String* y) {
} else {
result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
}
- ASSERT(result == StringInputBufferCompare(x, y));
+ ASSERT(result ==
+ StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
return result;
}
-static MaybeObject* Runtime_StringCompare(Arguments args) {
+static MaybeObject* Runtime_StringCompare(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(String, x, args[0]);
CONVERT_CHECKED(String, y, args[1]);
- Counters::string_compare_runtime.Increment();
+ isolate->counters()->string_compare_runtime()->Increment();
// A few fast case tests before we flatten.
if (x == y) return Smi::FromInt(EQUAL);
@@ -6239,52 +6578,59 @@ static MaybeObject* Runtime_StringCompare(Arguments args) {
else if (d > 0) return Smi::FromInt(GREATER);
Object* obj;
- { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
+ { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
+ { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
- : StringInputBufferCompare(x, y);
+ : StringInputBufferCompare(isolate->runtime_state(), x, y);
}
-static MaybeObject* Runtime_Math_acos(Arguments args) {
+static MaybeObject* Runtime_Math_acos(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_acos.Increment();
+ isolate->counters()->math_acos()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
+ return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
}
-static MaybeObject* Runtime_Math_asin(Arguments args) {
+static MaybeObject* Runtime_Math_asin(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_asin.Increment();
+ isolate->counters()->math_asin()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
+ return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
}
-static MaybeObject* Runtime_Math_atan(Arguments args) {
+static MaybeObject* Runtime_Math_atan(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_atan.Increment();
+ isolate->counters()->math_atan()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
+ return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
}
-static MaybeObject* Runtime_Math_atan2(Arguments args) {
+static const double kPiDividedBy4 = 0.78539816339744830962;
+
+
+static MaybeObject* Runtime_Math_atan2(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- Counters::math_atan2.Increment();
+ isolate->counters()->math_atan2()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
@@ -6294,71 +6640,76 @@ static MaybeObject* Runtime_Math_atan2(Arguments args) {
// is a multiple of Pi / 4. The sign of the result is determined
// by the first argument (x) and the sign of the second argument
// determines the multiplier: one or three.
- static double kPiDividedBy4 = 0.78539816339744830962;
int multiplier = (x < 0) ? -1 : 1;
if (y < 0) multiplier *= 3;
result = multiplier * kPiDividedBy4;
} else {
result = atan2(x, y);
}
- return Heap::AllocateHeapNumber(result);
+ return isolate->heap()->AllocateHeapNumber(result);
}
-static MaybeObject* Runtime_Math_ceil(Arguments args) {
+static MaybeObject* Runtime_Math_ceil(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_ceil.Increment();
+ isolate->counters()->math_ceil()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return Heap::NumberFromDouble(ceiling(x));
+ return isolate->heap()->NumberFromDouble(ceiling(x));
}
-static MaybeObject* Runtime_Math_cos(Arguments args) {
+static MaybeObject* Runtime_Math_cos(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_cos.Increment();
+ isolate->counters()->math_cos()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return TranscendentalCache::Get(TranscendentalCache::COS, x);
+ return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
}
-static MaybeObject* Runtime_Math_exp(Arguments args) {
+static MaybeObject* Runtime_Math_exp(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_exp.Increment();
+ isolate->counters()->math_exp()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return TranscendentalCache::Get(TranscendentalCache::EXP, x);
+ return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
}
-static MaybeObject* Runtime_Math_floor(Arguments args) {
+static MaybeObject* Runtime_Math_floor(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_floor.Increment();
+ isolate->counters()->math_floor()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return Heap::NumberFromDouble(floor(x));
+ return isolate->heap()->NumberFromDouble(floor(x));
}
-static MaybeObject* Runtime_Math_log(Arguments args) {
+static MaybeObject* Runtime_Math_log(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_log.Increment();
+ isolate->counters()->math_log()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return TranscendentalCache::Get(TranscendentalCache::LOG, x);
+ return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
}
-static MaybeObject* Runtime_Math_pow(Arguments args) {
+static MaybeObject* Runtime_Math_pow(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
- Counters::math_pow.Increment();
+ isolate->counters()->math_pow()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
@@ -6366,16 +6717,17 @@ static MaybeObject* Runtime_Math_pow(Arguments args) {
// custom powi() function than the generic pow().
if (args[1]->IsSmi()) {
int y = Smi::cast(args[1])->value();
- return Heap::NumberFromDouble(power_double_int(x, y));
+ return isolate->heap()->NumberFromDouble(power_double_int(x, y));
}
CONVERT_DOUBLE_CHECKED(y, args[1]);
- return Heap::AllocateHeapNumber(power_double_double(x, y));
+ return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
}
// Fast version of Math.pow if we know that y is not an integer and
// y is not -0.5 or 0.5. Used as slowcase from codegen.
-static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
+static MaybeObject* Runtime_Math_pow_cfunction(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_DOUBLE_CHECKED(x, args[0]);
@@ -6383,17 +6735,18 @@ static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
if (y == 0) {
return Smi::FromInt(1);
} else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
- return Heap::nan_value();
+ return isolate->heap()->nan_value();
} else {
- return Heap::AllocateHeapNumber(pow(x, y));
+ return isolate->heap()->AllocateHeapNumber(pow(x, y));
}
}
-static MaybeObject* Runtime_RoundNumber(Arguments args) {
+static MaybeObject* Runtime_RoundNumber(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_round.Increment();
+ isolate->counters()->math_round()->Increment();
if (!args[0]->IsHeapNumber()) {
// Must be smi. Return the argument unchanged for all the other types
@@ -6419,40 +6772,43 @@ static MaybeObject* Runtime_RoundNumber(Arguments args) {
return number;
}
- if (sign && value >= -0.5) return Heap::minus_zero_value();
+ if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
// Do not call NumberFromDouble() to avoid extra checks.
- return Heap::AllocateHeapNumber(floor(value + 0.5));
+ return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
}
-static MaybeObject* Runtime_Math_sin(Arguments args) {
+static MaybeObject* Runtime_Math_sin(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_sin.Increment();
+ isolate->counters()->math_sin()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return TranscendentalCache::Get(TranscendentalCache::SIN, x);
+ return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
}
-static MaybeObject* Runtime_Math_sqrt(Arguments args) {
+static MaybeObject* Runtime_Math_sqrt(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_sqrt.Increment();
+ isolate->counters()->math_sqrt()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return Heap::AllocateHeapNumber(sqrt(x));
+ return isolate->heap()->AllocateHeapNumber(sqrt(x));
}
-static MaybeObject* Runtime_Math_tan(Arguments args) {
+static MaybeObject* Runtime_Math_tan(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- Counters::math_tan.Increment();
+ isolate->counters()->math_tan()->Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return TranscendentalCache::Get(TranscendentalCache::TAN, x);
+ return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
}
@@ -6501,7 +6857,8 @@ static int MakeDay(int year, int month, int day) {
}
-static MaybeObject* Runtime_DateMakeDay(Arguments args) {
+static MaybeObject* Runtime_DateMakeDay(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 3);
@@ -6800,7 +7157,8 @@ static inline void DateYMDFromTime(int date,
}
-static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
+static MaybeObject* Runtime_DateYMDFromTime(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -6810,7 +7168,8 @@ static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
int year, month, day;
DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
- RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
+ RUNTIME_ASSERT(res_array->elements()->map() ==
+ isolate->heap()->fixed_array_map());
FixedArray* elms = FixedArray::cast(res_array->elements());
RUNTIME_ASSERT(elms->length() == 3);
@@ -6818,11 +7177,12 @@ static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
elms->set(1, Smi::FromInt(month));
elms->set(2, Smi::FromInt(day));
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
+static MaybeObject* Runtime_NewArgumentsFast(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 3);
@@ -6831,20 +7191,21 @@ static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
const int length = Smi::cast(args[2])->value();
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
+ { MaybeObject* maybe_result =
+ isolate->heap()->AllocateArgumentsObject(callee, length);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
// Allocate the elements if needed.
if (length > 0) {
// Allocate the fixed array.
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
+ { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
AssertNoAllocation no_gc;
FixedArray* array = reinterpret_cast<FixedArray*>(obj);
- array->set_map(Heap::fixed_array_map());
+ array->set_map(isolate->heap()->fixed_array_map());
array->set_length(length);
WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
@@ -6857,8 +7218,9 @@ static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
}
-static MaybeObject* Runtime_NewClosure(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_NewClosure(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(Context, context, 0);
CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
@@ -6870,15 +7232,15 @@ static MaybeObject* Runtime_NewClosure(Arguments args) {
pretenure = pretenure || (context->global_context() == *context);
PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
Handle<JSFunction> result =
- Factory::NewFunctionFromSharedFunctionInfo(shared,
- context,
- pretenure_flag);
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
+ context,
+ pretenure_flag);
return *result;
}
-
-static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_NewObjectFromBound(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
// First argument is a function to use as a constructor.
CONVERT_ARG_CHECKED(JSFunction, function, 0);
@@ -6899,7 +7261,7 @@ static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
ASSERT(!frame->is_optimized());
it.AdvanceToArgumentsFrame();
frame = it.frame();
- int argc = frame->GetProvidedParametersCount();
+ int argc = frame->ComputeParametersCount();
// Prepend bound arguments to caller's arguments.
int total_argc = bound_argc + argc;
@@ -6925,10 +7287,11 @@ static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
}
-static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
- Handle<Object> prototype = Factory::null_value();
+static void TrySettingInlineConstructStub(Isolate* isolate,
+ Handle<JSFunction> function) {
+ Handle<Object> prototype = isolate->factory()->null_value();
if (function->has_instance_prototype()) {
- prototype = Handle<Object>(function->instance_prototype());
+ prototype = Handle<Object>(function->instance_prototype(), isolate);
}
if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ConstructStubCompiler compiler;
@@ -6941,8 +7304,9 @@ static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
}
-static MaybeObject* Runtime_NewObject(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_NewObject(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
Handle<Object> constructor = args.at<Object>(0);
@@ -6951,8 +7315,8 @@ static MaybeObject* Runtime_NewObject(Arguments args) {
if (!constructor->IsJSFunction()) {
Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
Handle<Object> type_error =
- Factory::NewTypeError("not_constructor", arguments);
- return Top::Throw(*type_error);
+ isolate->factory()->NewTypeError("not_constructor", arguments);
+ return isolate->Throw(*type_error);
}
Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
@@ -6962,14 +7326,15 @@ static MaybeObject* Runtime_NewObject(Arguments args) {
if (!function->should_have_prototype()) {
Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
Handle<Object> type_error =
- Factory::NewTypeError("not_constructor", arguments);
- return Top::Throw(*type_error);
+ isolate->factory()->NewTypeError("not_constructor", arguments);
+ return isolate->Throw(*type_error);
}
#ifdef ENABLE_DEBUGGER_SUPPORT
+ Debug* debug = isolate->debug();
// Handle stepping into constructors if step into is active.
- if (Debug::StepInActive()) {
- Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
+ if (debug->StepInActive()) {
+ debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
}
#endif
@@ -6979,14 +7344,14 @@ static MaybeObject* Runtime_NewObject(Arguments args) {
// called using 'new' and creates a new JSFunction object that
// is returned. The receiver object is only used for error
// reporting if an error occurs when constructing the new
- // JSFunction. Factory::NewJSObject() should not be used to
+ // JSFunction. FACTORY->NewJSObject() should not be used to
// allocate JSFunctions since it does not properly initialize
// the shared part of the function. Since the receiver is
// ignored anyway, we use the global object as the receiver
// instead of a new JSFunction object. This way, errors are
// reported the same way whether or not 'Function' is called
// using 'new'.
- return Top::context()->global();
+ return isolate->context()->global();
}
}
@@ -6994,7 +7359,7 @@ static MaybeObject* Runtime_NewObject(Arguments args) {
// available. We cannot use EnsureCompiled because that forces a
// compilation through the shared function info which makes it
// impossible for us to optimize.
- Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<SharedFunctionInfo> shared(function->shared(), isolate);
if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
if (!function->has_initial_map() &&
@@ -7006,34 +7371,36 @@ static MaybeObject* Runtime_NewObject(Arguments args) {
}
bool first_allocation = !shared->live_objects_may_exist();
- Handle<JSObject> result = Factory::NewJSObject(function);
- RETURN_IF_EMPTY_HANDLE(result);
+ Handle<JSObject> result = isolate->factory()->NewJSObject(function);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
// Delay setting the stub if inobject slack tracking is in progress.
if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
- TrySettingInlineConstructStub(function);
+ TrySettingInlineConstructStub(isolate, function);
}
- Counters::constructed_objects.Increment();
- Counters::constructed_objects_runtime.Increment();
+ isolate->counters()->constructed_objects()->Increment();
+ isolate->counters()->constructed_objects_runtime()->Increment();
return *result;
}
-static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_FinalizeInstanceSize(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
function->shared()->CompleteInobjectSlackTracking();
- TrySettingInlineConstructStub(function);
+ TrySettingInlineConstructStub(isolate, function);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_LazyCompile(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_LazyCompile(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
Handle<JSFunction> function = args.at<JSFunction>(0);
@@ -7063,20 +7430,21 @@ static MaybeObject* Runtime_LazyCompile(Arguments args) {
}
-static MaybeObject* Runtime_LazyRecompile(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_LazyRecompile(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
Handle<JSFunction> function = args.at<JSFunction>(0);
// If the function is not optimizable or debugger is active continue using the
// code from the full compiler.
if (!function->shared()->code()->optimizable() ||
- Debug::has_break_points()) {
+ isolate->debug()->has_break_points()) {
if (FLAG_trace_opt) {
PrintF("[failed to optimize ");
function->PrintName();
PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
function->shared()->code()->optimizable() ? "T" : "F",
- Debug::has_break_points() ? "T" : "F");
+ isolate->debug()->has_break_points() ? "T" : "F");
}
function->ReplaceCode(function->shared()->code());
return function->code();
@@ -7094,14 +7462,15 @@ static MaybeObject* Runtime_LazyRecompile(Arguments args) {
}
-static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_NotifyDeoptimized(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
RUNTIME_ASSERT(args[0]->IsSmi());
Deoptimizer::BailoutType type =
static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
- Deoptimizer* deoptimizer = Deoptimizer::Grab();
- ASSERT(Heap::IsAllocationAllowed());
+ Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
+ ASSERT(isolate->heap()->IsAllocationAllowed());
int frames = deoptimizer->output_count();
JavaScriptFrameIterator it;
@@ -7114,24 +7483,24 @@ static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
delete deoptimizer;
RUNTIME_ASSERT(frame->function()->IsJSFunction());
- Handle<JSFunction> function(JSFunction::cast(frame->function()));
+ Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
Handle<Object> arguments;
for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
- if (frame->GetExpression(i) == Heap::arguments_marker()) {
+ if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
if (arguments.is_null()) {
// FunctionGetArguments can't throw an exception, so cast away the
// doubt with an assert.
arguments = Handle<Object>(
Accessors::FunctionGetArguments(*function,
NULL)->ToObjectUnchecked());
- ASSERT(*arguments != Heap::null_value());
- ASSERT(*arguments != Heap::undefined_value());
+ ASSERT(*arguments != isolate->heap()->null_value());
+ ASSERT(*arguments != isolate->heap()->undefined_value());
}
frame->SetExpression(i, *arguments);
}
}
- CompilationCache::MarkForLazyOptimizing(function);
+ isolate->compilation_cache()->MarkForLazyOptimizing(function);
if (type == Deoptimizer::EAGER) {
RUNTIME_ASSERT(function->IsOptimized());
} else {
@@ -7141,7 +7510,7 @@ static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
// Avoid doing too much work when running with --always-opt and keep
// the optimized code around.
if (FLAG_always_opt || type == Deoptimizer::LAZY) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// Count the number of optimized activations of the function.
@@ -7164,31 +7533,35 @@ static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
}
function->ReplaceCode(function->shared()->code());
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_NotifyOSR(Arguments args) {
- Deoptimizer* deoptimizer = Deoptimizer::Grab();
+static MaybeObject* Runtime_NotifyOSR(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
delete deoptimizer;
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DeoptimizeFunction(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
- if (!function->IsOptimized()) return Heap::undefined_value();
+ if (!function->IsOptimized()) return isolate->heap()->undefined_value();
Deoptimizer::DeoptimizeFunction(*function);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_CompileForOnStackReplacement(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
@@ -7197,7 +7570,7 @@ static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
// We have hit a back edge in an unoptimized frame for a function that was
// selected for on-stack replacement. Find the unoptimized code object.
- Handle<Code> unoptimized(function->shared()->code());
+ Handle<Code> unoptimized(function->shared()->code(), isolate);
// Keep track of whether we've succeeded in optimizing.
bool succeeded = unoptimized->optimizable();
if (succeeded) {
@@ -7221,7 +7594,7 @@ static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
JavaScriptFrameIterator it;
JavaScriptFrame* frame = it.frame();
ASSERT(frame->function() == *function);
- ASSERT(frame->code() == *unoptimized);
+ ASSERT(frame->LookupCode(isolate) == *unoptimized);
ASSERT(unoptimized->contains(frame->pc()));
// Use linear search of the unoptimized code's stack check table to find
@@ -7278,8 +7651,7 @@ static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
}
StackCheckStub check_stub;
Handle<Code> check_code = check_stub.GetCode();
- Handle<Code> replacement_code(
- Builtins::builtin(Builtins::OnStackReplacement));
+ Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
Deoptimizer::RevertStackCheckCode(*unoptimized,
*check_code,
*replacement_code);
@@ -7302,40 +7674,45 @@ static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
}
-static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetFunctionDelegate(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
RUNTIME_ASSERT(!args[0]->IsJSFunction());
return *Execution::GetFunctionDelegate(args.at<Object>(0));
}
-static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetConstructorDelegate(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
RUNTIME_ASSERT(!args[0]->IsJSFunction());
return *Execution::GetConstructorDelegate(args.at<Object>(0));
}
-static MaybeObject* Runtime_NewContext(Arguments args) {
+static MaybeObject* Runtime_NewContext(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSFunction, function, args[0]);
int length = function->shared()->scope_info()->NumberOfContextSlots();
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
+ { MaybeObject* maybe_result =
+ isolate->heap()->AllocateFunctionContext(length, function);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- Top::set_context(Context::cast(result));
+ isolate->set_context(Context::cast(result));
return result; // non-failure
}
-MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
+MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
+ Object* object,
bool is_catch_context) {
// Convert the object to a proper JavaScript object.
Object* js_object = object;
@@ -7345,45 +7722,47 @@ MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
if (!Failure::cast(maybe_js_object)->IsInternalError()) {
return maybe_js_object;
}
- HandleScope scope;
- Handle<Object> handle(object);
+ HandleScope scope(isolate);
+ Handle<Object> handle(object, isolate);
Handle<Object> result =
- Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
- return Top::Throw(*result);
+ isolate->factory()->NewTypeError("with_expression",
+ HandleVector(&handle, 1));
+ return isolate->Throw(*result);
}
}
Object* result;
- { MaybeObject* maybe_result =
- Heap::AllocateWithContext(Top::context(),
- JSObject::cast(js_object),
- is_catch_context);
+ { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
+ isolate->context(), JSObject::cast(js_object), is_catch_context);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Context* context = Context::cast(result);
- Top::set_context(context);
+ isolate->set_context(context);
return result;
}
-static MaybeObject* Runtime_PushContext(Arguments args) {
+static MaybeObject* Runtime_PushContext(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- return PushContextHelper(args[0], false);
+ return PushContextHelper(isolate, args[0], false);
}
-static MaybeObject* Runtime_PushCatchContext(Arguments args) {
+static MaybeObject* Runtime_PushCatchContext(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
- return PushContextHelper(args[0], true);
+ return PushContextHelper(isolate, args[0], true);
}
-static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DeleteContextSlot(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(Context, context, 0);
@@ -7396,12 +7775,12 @@ static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
// If the slot was not found the result is true.
if (holder.is_null()) {
- return Heap::true_value();
+ return isolate->heap()->true_value();
}
// If the slot was found in a context, it should be DONT_DELETE.
if (holder->IsContext()) {
- return Heap::false_value();
+ return isolate->heap()->false_value();
}
// The slot was found in a JSObject, either a context extension object,
@@ -7449,17 +7828,19 @@ static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
#endif
-static inline MaybeObject* Unhole(MaybeObject* x,
+static inline MaybeObject* Unhole(Heap* heap,
+ MaybeObject* x,
PropertyAttributes attributes) {
ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
USE(attributes);
- return x->IsTheHole() ? Heap::undefined_value() : x;
+ return x->IsTheHole() ? heap->undefined_value() : x;
}
-static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
+static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
+ JSObject* holder) {
ASSERT(!holder->IsGlobalObject());
- Context* top = Top::context();
+ Context* top = isolate->context();
// Get the context extension function.
JSFunction* context_extension_function =
top->global_context()->context_extension_function();
@@ -7476,12 +7857,14 @@ static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
}
-static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
- HandleScope scope;
+static ObjectPair LoadContextSlotHelper(Arguments args,
+ Isolate* isolate,
+ bool throw_error) {
+ HandleScope scope(isolate);
ASSERT_EQ(2, args.length());
if (!args[0]->IsContext() || !args[1]->IsString()) {
- return MakePair(Top::ThrowIllegalOperation(), NULL);
+ return MakePair(isolate->ThrowIllegalOperation(), NULL);
}
Handle<Context> context = args.at<Context>(0);
Handle<String> name = args.at<String>(1);
@@ -7498,11 +7881,12 @@ static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
// If the "property" we were looking for is a local variable or an
// argument in a context, the receiver is the global object; see
// ECMA-262, 3rd., 10.1.6 and 10.2.3.
- JSObject* receiver = Top::context()->global()->global_receiver();
+ JSObject* receiver =
+ isolate->context()->global()->global_receiver();
MaybeObject* value = (holder->IsContext())
? Context::cast(*holder)->get(index)
: JSObject::cast(*holder)->GetElement(index);
- return MakePair(Unhole(value, attributes), receiver);
+ return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
}
// If the holder is found, we read the property from it.
@@ -7513,9 +7897,9 @@ static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
if (object->IsGlobalObject()) {
receiver = GlobalObject::cast(object)->global_receiver();
} else if (context->is_exception_holder(*holder)) {
- receiver = Top::context()->global()->global_receiver();
+ receiver = isolate->context()->global()->global_receiver();
} else {
- receiver = ComputeReceiverForNonGlobal(object);
+ receiver = ComputeReceiverForNonGlobal(isolate, object);
}
// No need to unhole the value here. This is taken care of by the
// GetProperty function.
@@ -7526,30 +7910,36 @@ static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
if (throw_error) {
// The property doesn't exist - throw exception.
Handle<Object> reference_error =
- Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
- return MakePair(Top::Throw(*reference_error), NULL);
+ isolate->factory()->NewReferenceError("not_defined",
+ HandleVector(&name, 1));
+ return MakePair(isolate->Throw(*reference_error), NULL);
} else {
// The property doesn't exist - return undefined
- return MakePair(Heap::undefined_value(), Heap::undefined_value());
+ return MakePair(isolate->heap()->undefined_value(),
+ isolate->heap()->undefined_value());
}
}
-static ObjectPair Runtime_LoadContextSlot(Arguments args) {
- return LoadContextSlotHelper(args, true);
+static ObjectPair Runtime_LoadContextSlot(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ return LoadContextSlotHelper(args, isolate, true);
}
-static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
- return LoadContextSlotHelper(args, false);
+static ObjectPair Runtime_LoadContextSlotNoReferenceError(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ return LoadContextSlotHelper(args, isolate, false);
}
-static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_StoreContextSlot(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 4);
- Handle<Object> value(args[0]);
+ Handle<Object> value(args[0], isolate);
CONVERT_ARG_CHECKED(Context, context, 1);
CONVERT_ARG_CHECKED(String, name, 2);
CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
@@ -7571,16 +7961,16 @@ static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
} else if (strict_mode == kStrictMode) {
// Setting read only property in strict mode.
Handle<Object> error =
- Factory::NewTypeError("strict_cannot_assign",
- HandleVector(&name, 1));
- return Top::Throw(*error);
+ isolate->factory()->NewTypeError("strict_cannot_assign",
+ HandleVector(&name, 1));
+ return isolate->Throw(*error);
}
} else {
ASSERT((attributes & READ_ONLY) == 0);
Handle<Object> result =
SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
if (result.is_null()) {
- ASSERT(Top::has_pending_exception());
+ ASSERT(isolate->has_pending_exception());
return Failure::Exception();
}
}
@@ -7598,7 +7988,7 @@ static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
// The property was not found. It needs to be stored in the global context.
ASSERT(attributes == ABSENT);
attributes = NONE;
- context_ext = Handle<JSObject>(Top::context()->global());
+ context_ext = Handle<JSObject>(isolate->context()->global());
}
// Set the property, but ignore if read_only variable on the context
@@ -7606,62 +7996,66 @@ static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
if ((attributes & READ_ONLY) == 0 ||
(context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
RETURN_IF_EMPTY_HANDLE(
+ isolate,
SetProperty(context_ext, name, value, NONE, strict_mode));
} else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
// Setting read only property in strict mode.
Handle<Object> error =
- Factory::NewTypeError("strict_cannot_assign", HandleVector(&name, 1));
- return Top::Throw(*error);
+ isolate->factory()->NewTypeError(
+ "strict_cannot_assign", HandleVector(&name, 1));
+ return isolate->Throw(*error);
}
return *value;
}
-static MaybeObject* Runtime_Throw(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_Throw(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
- return Top::Throw(args[0]);
+ return isolate->Throw(args[0]);
}
-static MaybeObject* Runtime_ReThrow(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_ReThrow(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
- return Top::ReThrow(args[0]);
+ return isolate->ReThrow(args[0]);
}
-static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
+static MaybeObject* Runtime_PromoteScheduledException(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT_EQ(0, args.length());
- return Top::PromoteScheduledException();
+ return isolate->PromoteScheduledException();
}
-static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_ThrowReferenceError(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
- Handle<Object> name(args[0]);
+ Handle<Object> name(args[0], isolate);
Handle<Object> reference_error =
- Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
- return Top::Throw(*reference_error);
-}
-
-
-static MaybeObject* Runtime_StackOverflow(Arguments args) {
- NoHandleAllocation na;
- return Top::StackOverflow();
+ isolate->factory()->NewReferenceError("not_defined",
+ HandleVector(&name, 1));
+ return isolate->Throw(*reference_error);
}
-static MaybeObject* Runtime_StackGuard(Arguments args) {
+static MaybeObject* Runtime_StackGuard(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 0);
// First check if this is a real stack overflow.
- if (StackGuard::IsStackOverflow()) {
- return Runtime_StackOverflow(args);
+ if (isolate->stack_guard()->IsStackOverflow()) {
+ NoHandleAllocation na;
+ return isolate->StackOverflow();
}
return Execution::HandleStackGuardInterrupt();
@@ -7738,7 +8132,7 @@ static void PrintTransition(Object* result) {
// supplied parameters, not all parameters required)
PrintF("(this=");
PrintObject(frame->receiver());
- const int length = frame->GetProvidedParametersCount();
+ const int length = frame->ComputeParametersCount();
for (int i = 0; i < length; i++) {
PrintF(", ");
PrintObject(frame->GetParameter(i));
@@ -7754,22 +8148,25 @@ static void PrintTransition(Object* result) {
}
-static MaybeObject* Runtime_TraceEnter(Arguments args) {
+static MaybeObject* Runtime_TraceEnter(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 0);
NoHandleAllocation ha;
PrintTransition(NULL);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_TraceExit(Arguments args) {
+static MaybeObject* Runtime_TraceExit(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
PrintTransition(args[0]);
return args[0]; // return TOS
}
-static MaybeObject* Runtime_DebugPrint(Arguments args) {
+static MaybeObject* Runtime_DebugPrint(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -7800,15 +8197,17 @@ static MaybeObject* Runtime_DebugPrint(Arguments args) {
}
-static MaybeObject* Runtime_DebugTrace(Arguments args) {
+static MaybeObject* Runtime_DebugTrace(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 0);
NoHandleAllocation ha;
- Top::PrintStack();
- return Heap::undefined_value();
+ isolate->PrintStack();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
+static MaybeObject* Runtime_DateCurrentTime(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 0);
@@ -7817,12 +8216,13 @@ static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
// time is milliseconds. Therefore, we floor the result of getting
// the OS time.
double millis = floor(OS::TimeCurrentMillis());
- return Heap::NumberFromDouble(millis);
+ return isolate->heap()->NumberFromDouble(millis);
}
-static MaybeObject* Runtime_DateParseString(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DateParseString(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(String, str, 0);
@@ -7846,109 +8246,119 @@ static MaybeObject* Runtime_DateParseString(Arguments args) {
if (result) {
return *output;
} else {
- return Heap::null_value();
+ return isolate->heap()->null_value();
}
}
-static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
+static MaybeObject* Runtime_DateLocalTimezone(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_DOUBLE_CHECKED(x, args[0]);
const char* zone = OS::LocalTimezone(x);
- return Heap::AllocateStringFromUtf8(CStrVector(zone));
+ return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
}
-static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
+static MaybeObject* Runtime_DateLocalTimeOffset(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 0);
- return Heap::NumberFromDouble(OS::LocalTimeOffset());
+ return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
}
-static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
+static MaybeObject* Runtime_DateDaylightSavingsOffset(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
+ return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
}
-static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
+static MaybeObject* Runtime_GlobalReceiver(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
Object* global = args[0];
- if (!global->IsJSGlobalObject()) return Heap::null_value();
+ if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
return JSGlobalObject::cast(global)->global_receiver();
}
-static MaybeObject* Runtime_ParseJson(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_ParseJson(RUNTIME_CALLING_CONVENTION) {
+ HandleScope scope(isolate);
ASSERT_EQ(1, args.length());
CONVERT_ARG_CHECKED(String, source, 0);
Handle<Object> result = JsonParser::Parse(source);
if (result.is_null()) {
// Syntax error or stack overflow in scanner.
- ASSERT(Top::has_pending_exception());
+ ASSERT(isolate->has_pending_exception());
return Failure::Exception();
}
return *result;
}
-static MaybeObject* Runtime_CompileString(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_CompileString(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT_EQ(1, args.length());
CONVERT_ARG_CHECKED(String, source, 0);
// Compile source string in the global context.
- Handle<Context> context(Top::context()->global_context());
+ Handle<Context> context(isolate->context()->global_context());
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
context,
true,
kNonStrictMode);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> fun =
- Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
+ context,
+ NOT_TENURED);
return *fun;
}
-static ObjectPair CompileGlobalEval(Handle<String> source,
+static ObjectPair CompileGlobalEval(Isolate* isolate,
+ Handle<String> source,
Handle<Object> receiver,
- StrictModeFlag mode) {
+ StrictModeFlag strict_mode) {
// Deal with a normal eval call with a string argument. Compile it
// and return the compiled function bound in the local context.
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
source,
- Handle<Context>(Top::context()),
- Top::context()->IsGlobalContext(),
- mode);
+ Handle<Context>(isolate->context()),
+ isolate->context()->IsGlobalContext(),
+ strict_mode);
if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
- Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
- shared,
- Handle<Context>(Top::context()),
- NOT_TENURED);
+ Handle<JSFunction> compiled =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ shared, Handle<Context>(isolate->context()), NOT_TENURED);
return MakePair(*compiled, *receiver);
}
-static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
+static ObjectPair Runtime_ResolvePossiblyDirectEval(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 4);
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<Object> callee = args.at<Object>(0);
Handle<Object> receiver; // Will be overwritten.
// Compute the calling context.
- Handle<Context> context = Handle<Context>(Top::context());
+ Handle<Context> context = Handle<Context>(isolate->context(), isolate);
#ifdef DEBUG
- // Make sure Top::context() agrees with the old code that traversed
+ // Make sure Isolate::context() agrees with the old code that traversed
// the stack frames to compute the context.
StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
@@ -7960,25 +8370,28 @@ static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
int index = -1;
PropertyAttributes attributes = ABSENT;
while (true) {
- receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
+ receiver = context->Lookup(isolate->factory()->eval_symbol(),
+ FOLLOW_PROTOTYPE_CHAIN,
&index, &attributes);
// Stop search when eval is found or when the global context is
// reached.
if (attributes != ABSENT || context->IsGlobalContext()) break;
if (context->is_function_context()) {
- context = Handle<Context>(Context::cast(context->closure()->context()));
+ context = Handle<Context>(Context::cast(context->closure()->context()),
+ isolate);
} else {
- context = Handle<Context>(context->previous());
+ context = Handle<Context>(context->previous(), isolate);
}
}
// If eval could not be resolved, it has been deleted and we need to
// throw a reference error.
if (attributes == ABSENT) {
- Handle<Object> name = Factory::eval_symbol();
+ Handle<Object> name = isolate->factory()->eval_symbol();
Handle<Object> reference_error =
- Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
- return MakePair(Top::Throw(*reference_error), NULL);
+ isolate->factory()->NewReferenceError("not_defined",
+ HandleVector(&name, 1));
+ return MakePair(isolate->Throw(*reference_error), NULL);
}
if (!context->IsGlobalContext()) {
@@ -7986,67 +8399,80 @@ static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
// with the given arguments. This is not necessarily the global eval.
if (receiver->IsContext()) {
context = Handle<Context>::cast(receiver);
- receiver = Handle<Object>(context->get(index));
+ receiver = Handle<Object>(context->get(index), isolate);
} else if (receiver->IsJSContextExtensionObject()) {
- receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
+ receiver = Handle<JSObject>(
+ isolate->context()->global()->global_receiver(), isolate);
}
return MakePair(*callee, *receiver);
}
// 'eval' is bound in the global context, but it may have been overwritten.
// Compare it to the builtin 'GlobalEval' function to make sure.
- if (*callee != Top::global_context()->global_eval_fun() ||
+ if (*callee != isolate->global_context()->global_eval_fun() ||
!args[1]->IsString()) {
- return MakePair(*callee, Top::context()->global()->global_receiver());
+ return MakePair(*callee,
+ isolate->context()->global()->global_receiver());
}
ASSERT(args[3]->IsSmi());
- return CompileGlobalEval(args.at<String>(1),
+ return CompileGlobalEval(isolate,
+ args.at<String>(1),
args.at<Object>(2),
static_cast<StrictModeFlag>(
Smi::cast(args[3])->value()));
}
-static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
+static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 4);
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<Object> callee = args.at<Object>(0);
// 'eval' is bound in the global context, but it may have been overwritten.
// Compare it to the builtin 'GlobalEval' function to make sure.
- if (*callee != Top::global_context()->global_eval_fun() ||
+ if (*callee != isolate->global_context()->global_eval_fun() ||
!args[1]->IsString()) {
- return MakePair(*callee, Top::context()->global()->global_receiver());
+ return MakePair(*callee,
+ isolate->context()->global()->global_receiver());
}
ASSERT(args[3]->IsSmi());
- return CompileGlobalEval(args.at<String>(1),
+ return CompileGlobalEval(isolate,
+ args.at<String>(1),
args.at<Object>(2),
static_cast<StrictModeFlag>(
Smi::cast(args[3])->value()));
}
-static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
+static MaybeObject* Runtime_SetNewFunctionAttributes(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
// This utility adjusts the property attributes for newly created Function
// object ("new Function(...)") by changing the map.
// All it does is changing the prototype property to enumerable
// as specified in ECMA262, 15.3.5.2.
- HandleScope scope;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, func, 0);
- ASSERT(func->map()->instance_type() ==
- Top::function_instance_map()->instance_type());
- ASSERT(func->map()->instance_size() ==
- Top::function_instance_map()->instance_size());
- func->set_map(*Top::function_instance_map());
+
+ Handle<Map> map = func->shared()->strict_mode()
+ ? isolate->strict_mode_function_instance_map()
+ : isolate->function_instance_map();
+
+ ASSERT(func->map()->instance_type() == map->instance_type());
+ ASSERT(func->map()->instance_size() == map->instance_size());
+ func->set_map(*map);
return *func;
}
-static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
+static MaybeObject* Runtime_AllocateInNewSpace(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
// Allocate a block of memory in NewSpace (filled with a filler).
// Use as fallback for allocation in generated code when NewSpace
// is full.
@@ -8055,13 +8481,13 @@ static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
int size = size_smi->value();
RUNTIME_ASSERT(IsAligned(size, kPointerSize));
RUNTIME_ASSERT(size > 0);
- static const int kMinFreeNewSpaceAfterGC =
- Heap::InitialSemiSpaceSize() * 3/4;
+ Heap* heap = isolate->heap();
+ const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
Object* allocation;
- { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
+ { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
if (maybe_allocation->ToObject(&allocation)) {
- Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
+ heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
}
return maybe_allocation;
}
@@ -8071,7 +8497,8 @@ static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
// Push an object unto an array of objects if it is not already in the
// array. Returns true if the element was pushed on the stack and
// false otherwise.
-static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
+static MaybeObject* Runtime_PushIfAbsent(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSArray, array, args[0]);
CONVERT_CHECKED(JSObject, element, args[1]);
@@ -8079,7 +8506,7 @@ static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
int length = Smi::cast(array->length())->value();
FixedArray* elements = FixedArray::cast(array->elements());
for (int i = 0; i < length; i++) {
- if (elements->get(i) == element) return Heap::false_value();
+ if (elements->get(i) == element) return isolate->heap()->false_value();
}
Object* obj;
// Strict not needed. Used for cycle detection in Array join implementation.
@@ -8087,7 +8514,7 @@ static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
kNonStrictMode);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- return Heap::true_value();
+ return isolate->heap()->true_value();
}
@@ -8104,9 +8531,12 @@ static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
*/
class ArrayConcatVisitor {
public:
- ArrayConcatVisitor(Handle<FixedArray> storage,
+ ArrayConcatVisitor(Isolate* isolate,
+ Handle<FixedArray> storage,
bool fast_elements) :
- storage_(Handle<FixedArray>::cast(GlobalHandles::Create(*storage))),
+ isolate_(isolate),
+ storage_(Handle<FixedArray>::cast(
+ isolate->global_handles()->Create(*storage))),
index_offset_(0u),
fast_elements_(fast_elements) { }
@@ -8133,7 +8563,7 @@ class ArrayConcatVisitor {
ASSERT(!fast_elements_);
Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
Handle<NumberDictionary> result =
- Factory::DictionaryAtNumberPut(dict, index, elm);
+ isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
if (!result.is_identical_to(dict)) {
// Dictionary needed to grow.
clear_storage();
@@ -8150,14 +8580,14 @@ class ArrayConcatVisitor {
}
Handle<JSArray> ToArray() {
- Handle<JSArray> array = Factory::NewJSArray(0);
+ Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
Handle<Object> length =
- Factory::NewNumber(static_cast<double>(index_offset_));
+ isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
Handle<Map> map;
if (fast_elements_) {
- map = Factory::GetFastElementsMap(Handle<Map>(array->map()));
+ map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
} else {
- map = Factory::GetSlowElementsMap(Handle<Map>(array->map()));
+ map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
}
array->set_map(*map);
array->set_length(*length);
@@ -8171,14 +8601,14 @@ class ArrayConcatVisitor {
ASSERT(fast_elements_);
Handle<FixedArray> current_storage(*storage_);
Handle<NumberDictionary> slow_storage(
- Factory::NewNumberDictionary(current_storage->length()));
+ isolate_->factory()->NewNumberDictionary(current_storage->length()));
uint32_t current_length = static_cast<uint32_t>(current_storage->length());
for (uint32_t i = 0; i < current_length; i++) {
HandleScope loop_scope;
Handle<Object> element(current_storage->get(i));
if (!element->IsTheHole()) {
Handle<NumberDictionary> new_storage =
- Factory::DictionaryAtNumberPut(slow_storage, i, element);
+ isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
if (!new_storage.is_identical_to(slow_storage)) {
slow_storage = loop_scope.CloseAndEscape(new_storage);
}
@@ -8190,13 +8620,16 @@ class ArrayConcatVisitor {
}
inline void clear_storage() {
- GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
+ isolate_->global_handles()->Destroy(
+ Handle<Object>::cast(storage_).location());
}
inline void set_storage(FixedArray* storage) {
- storage_ = Handle<FixedArray>::cast(GlobalHandles::Create(storage));
+ storage_ = Handle<FixedArray>::cast(
+ isolate_->global_handles()->Create(storage));
}
+ Isolate* isolate_;
Handle<FixedArray> storage_; // Always a global handle.
// Index after last seen index. Always less than or equal to
// JSObject::kMaxElementCount.
@@ -8244,7 +8677,8 @@ static uint32_t EstimateElementCount(Handle<JSArray> array) {
template<class ExternalArrayClass, class ElementType>
-static void IterateExternalArrayElements(Handle<JSObject> receiver,
+static void IterateExternalArrayElements(Isolate* isolate,
+ Handle<JSObject> receiver,
bool elements_are_ints,
bool elements_are_guaranteed_smis,
ArrayConcatVisitor* visitor) {
@@ -8269,15 +8703,15 @@ static void IterateExternalArrayElements(Handle<JSObject> receiver,
visitor->visit(j, e);
} else {
Handle<Object> e =
- Factory::NewNumber(static_cast<ElementType>(val));
+ isolate->factory()->NewNumber(static_cast<ElementType>(val));
visitor->visit(j, e);
}
}
}
} else {
for (uint32_t j = 0; j < len; j++) {
- HandleScope loop_scope;
- Handle<Object> e = Factory::NewNumber(array->get(j));
+ HandleScope loop_scope(isolate);
+ Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
visitor->visit(j, e);
}
}
@@ -8327,9 +8761,9 @@ static void CollectElementIndices(Handle<JSObject> object,
default: {
int dense_elements_length;
switch (kind) {
- case JSObject::PIXEL_ELEMENTS: {
+ case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
dense_elements_length =
- PixelArray::cast(object->elements())->length();
+ ExternalPixelArray::cast(object->elements())->length();
break;
}
case JSObject::EXTERNAL_BYTE_ELEMENTS: {
@@ -8406,7 +8840,8 @@ static void CollectElementIndices(Handle<JSObject> object,
* length.
* Returns false if any access threw an exception, otherwise true.
*/
-static bool IterateElements(Handle<JSArray> receiver,
+static bool IterateElements(Isolate* isolate,
+ Handle<JSArray> receiver,
ArrayConcatVisitor* visitor) {
uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
switch (receiver->GetElementsKind()) {
@@ -8417,8 +8852,8 @@ static bool IterateElements(Handle<JSArray> receiver,
int fast_length = static_cast<int>(length);
ASSERT(fast_length <= elements->length());
for (int j = 0; j < fast_length; j++) {
- HandleScope loop_scope;
- Handle<Object> element_value(elements->get(j));
+ HandleScope loop_scope(isolate);
+ Handle<Object> element_value(elements->get(j), isolate);
if (!element_value->IsTheHole()) {
visitor->visit(j, element_value);
} else if (receiver->HasElement(j)) {
@@ -8453,8 +8888,9 @@ static bool IterateElements(Handle<JSArray> receiver,
}
break;
}
- case JSObject::PIXEL_ELEMENTS: {
- Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
+ case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
+ receiver->elements()));
for (uint32_t j = 0; j < length; j++) {
Handle<Smi> e(Smi::FromInt(pixels->get(j)));
visitor->visit(j, e);
@@ -8463,37 +8899,37 @@ static bool IterateElements(Handle<JSArray> receiver,
}
case JSObject::EXTERNAL_BYTE_ELEMENTS: {
IterateExternalArrayElements<ExternalByteArray, int8_t>(
- receiver, true, true, visitor);
+ isolate, receiver, true, true, visitor);
break;
}
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
- receiver, true, true, visitor);
+ isolate, receiver, true, true, visitor);
break;
}
case JSObject::EXTERNAL_SHORT_ELEMENTS: {
IterateExternalArrayElements<ExternalShortArray, int16_t>(
- receiver, true, true, visitor);
+ isolate, receiver, true, true, visitor);
break;
}
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
- receiver, true, true, visitor);
+ isolate, receiver, true, true, visitor);
break;
}
case JSObject::EXTERNAL_INT_ELEMENTS: {
IterateExternalArrayElements<ExternalIntArray, int32_t>(
- receiver, true, false, visitor);
+ isolate, receiver, true, false, visitor);
break;
}
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
- receiver, true, false, visitor);
+ isolate, receiver, true, false, visitor);
break;
}
case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
IterateExternalArrayElements<ExternalFloatArray, float>(
- receiver, false, false, visitor);
+ isolate, receiver, false, false, visitor);
break;
}
default:
@@ -8511,9 +8947,10 @@ static bool IterateElements(Handle<JSArray> receiver,
* TODO(581): Fix non-compliance for very large concatenations and update to
* following the ECMAScript 5 specification.
*/
-static MaybeObject* Runtime_ArrayConcat(Arguments args) {
+static MaybeObject* Runtime_ArrayConcat(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
- HandleScope handle_scope;
+ HandleScope handle_scope(isolate);
CONVERT_ARG_CHECKED(JSArray, arguments, 0);
int argument_count = static_cast<int>(arguments->length()->Number());
@@ -8568,22 +9005,23 @@ static MaybeObject* Runtime_ArrayConcat(Arguments args) {
if (fast_case) {
// The backing storage array must have non-existing elements to
// preserve holes across concat operations.
- storage = Factory::NewFixedArrayWithHoles(estimate_result_length);
+ storage = isolate->factory()->NewFixedArrayWithHoles(
+ estimate_result_length);
} else {
// TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
uint32_t at_least_space_for = estimate_nof_elements +
(estimate_nof_elements >> 2);
storage = Handle<FixedArray>::cast(
- Factory::NewNumberDictionary(at_least_space_for));
+ isolate->factory()->NewNumberDictionary(at_least_space_for));
}
- ArrayConcatVisitor visitor(storage, fast_case);
+ ArrayConcatVisitor visitor(isolate, storage, fast_case);
for (int i = 0; i < argument_count; i++) {
Handle<Object> obj(elements->get(i));
if (obj->IsJSArray()) {
Handle<JSArray> array = Handle<JSArray>::cast(obj);
- if (!IterateElements(array, &visitor)) {
+ if (!IterateElements(isolate, array, &visitor)) {
return Failure::Exception();
}
} else {
@@ -8598,7 +9036,8 @@ static MaybeObject* Runtime_ArrayConcat(Arguments args) {
// This will not allocate (flatten the string), but it may run
// very slowly for very deeply nested ConsStrings. For debugging use only.
-static MaybeObject* Runtime_GlobalPrint(Arguments args) {
+static MaybeObject* Runtime_GlobalPrint(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -8616,7 +9055,8 @@ static MaybeObject* Runtime_GlobalPrint(Arguments args) {
// and are followed by non-existing element. Does not change the length
// property.
// Returns the number of non-undefined elements collected.
-static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
+static MaybeObject* Runtime_RemoveArrayHoles(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSObject, object, args[0]);
CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
@@ -8625,14 +9065,15 @@ static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
// Move contents of argument 0 (an array) to argument 1 (an array)
-static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
+static MaybeObject* Runtime_MoveArrayContents(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSArray, from, args[0]);
CONVERT_CHECKED(JSArray, to, args[1]);
HeapObject* new_elements = from->elements();
MaybeObject* maybe_new_map;
- if (new_elements->map() == Heap::fixed_array_map() ||
- new_elements->map() == Heap::fixed_cow_array_map()) {
+ if (new_elements->map() == isolate->heap()->fixed_array_map() ||
+ new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
maybe_new_map = to->map()->GetFastElementsMap();
} else {
maybe_new_map = to->map()->GetSlowElementsMap();
@@ -8652,7 +9093,9 @@ static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
// How many elements does this object/array have?
-static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
+static MaybeObject* Runtime_EstimateNumberOfElements(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSObject, object, args[0]);
HeapObject* elements = object->elements();
@@ -8666,8 +9109,9 @@ static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
}
-static MaybeObject* Runtime_SwapElements(Arguments args) {
- HandleScope handle_scope;
+static MaybeObject* Runtime_SwapElements(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope handle_scope(isolate);
ASSERT_EQ(3, args.length());
@@ -8678,19 +9122,21 @@ static MaybeObject* Runtime_SwapElements(Arguments args) {
uint32_t index1, index2;
if (!key1->ToArrayIndex(&index1)
|| !key2->ToArrayIndex(&index2)) {
- return Top::ThrowIllegalOperation();
+ return isolate->ThrowIllegalOperation();
}
Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
Handle<Object> tmp1 = GetElement(jsobject, index1);
- RETURN_IF_EMPTY_HANDLE(tmp1);
+ RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
Handle<Object> tmp2 = GetElement(jsobject, index2);
- RETURN_IF_EMPTY_HANDLE(tmp2);
+ RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
- RETURN_IF_EMPTY_HANDLE(SetElement(jsobject, index1, tmp2, kStrictMode));
- RETURN_IF_EMPTY_HANDLE(SetElement(jsobject, index2, tmp1, kStrictMode));
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ SetElement(jsobject, index1, tmp2, kStrictMode));
+ RETURN_IF_EMPTY_HANDLE(isolate,
+ SetElement(jsobject, index2, tmp1, kStrictMode));
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
@@ -8699,9 +9145,10 @@ static MaybeObject* Runtime_SwapElements(Arguments args) {
// intervals (pair of a negative integer (-start-1) followed by a
// positive (length)) or undefined values.
// Intervals can span over some keys that are not in the object.
-static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
+static MaybeObject* Runtime_GetArrayKeys(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSObject, array, 0);
CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
if (array->elements()->IsDictionary()) {
@@ -8717,19 +9164,19 @@ static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
keys->set_undefined(i);
}
}
- return *Factory::NewJSArrayWithElements(keys);
+ return *isolate->factory()->NewJSArrayWithElements(keys);
} else {
ASSERT(array->HasFastElements());
- Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
+ Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
// -1 means start of array.
single_interval->set(0, Smi::FromInt(-1));
uint32_t actual_length =
static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
uint32_t min_length = actual_length < length ? actual_length : length;
Handle<Object> length_object =
- Factory::NewNumber(static_cast<double>(min_length));
+ isolate->factory()->NewNumber(static_cast<double>(min_length));
single_interval->set(1, *length_object);
- return *Factory::NewJSArrayWithElements(single_interval);
+ return *isolate->factory()->NewJSArrayWithElements(single_interval);
}
}
@@ -8739,7 +9186,8 @@ static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
// to the way accessors are implemented, it is set for both the getter
// and setter on the first call to DefineAccessor and ignored on
// subsequent calls.
-static MaybeObject* Runtime_DefineAccessor(Arguments args) {
+static MaybeObject* Runtime_DefineAccessor(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
// Compute attributes.
PropertyAttributes attributes = NONE;
@@ -8759,7 +9207,8 @@ static MaybeObject* Runtime_DefineAccessor(Arguments args) {
}
-static MaybeObject* Runtime_LookupAccessor(Arguments args) {
+static MaybeObject* Runtime_LookupAccessor(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 3);
CONVERT_CHECKED(JSObject, obj, args[0]);
CONVERT_CHECKED(String, name, args[1]);
@@ -8769,7 +9218,8 @@ static MaybeObject* Runtime_LookupAccessor(Arguments args) {
#ifdef ENABLE_DEBUGGER_SUPPORT
-static MaybeObject* Runtime_DebugBreak(Arguments args) {
+static MaybeObject* Runtime_DebugBreak(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 0);
return Execution::DebugBreakHelper();
}
@@ -8791,27 +9241,31 @@ static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
// args[0]: debug event listener function to set or null or undefined for
// clearing the event listener function
// args[1]: object supplied during callback
-static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
+static MaybeObject* Runtime_SetDebugEventListener(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
RUNTIME_ASSERT(args[0]->IsJSFunction() ||
args[0]->IsUndefined() ||
args[0]->IsNull());
Handle<Object> callback = args.at<Object>(0);
Handle<Object> data = args.at<Object>(1);
- Debugger::SetEventListener(callback, data);
+ isolate->debugger()->SetEventListener(callback, data);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_Break(Arguments args) {
+static MaybeObject* Runtime_Break(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 0);
- StackGuard::DebugBreak();
- return Heap::undefined_value();
+ isolate->stack_guard()->DebugBreak();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
+static MaybeObject* DebugLookupResultValue(Heap* heap,
+ Object* receiver,
+ String* name,
LookupResult* result,
bool* caught_exception) {
Object* value;
@@ -8819,7 +9273,7 @@ static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
case NORMAL:
value = result->holder()->GetNormalizedProperty(result);
if (value->IsTheHole()) {
- return Heap::undefined_value();
+ return heap->undefined_value();
}
return value;
case FIELD:
@@ -8827,7 +9281,7 @@ static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
JSObject::cast(
result->holder())->FastPropertyAt(result->GetFieldIndex());
if (value->IsTheHole()) {
- return Heap::undefined_value();
+ return heap->undefined_value();
}
return value;
case CONSTANT_FUNCTION:
@@ -8840,8 +9294,8 @@ static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
if (!maybe_value->ToObject(&value)) {
if (maybe_value->IsRetryAfterGC()) return maybe_value;
ASSERT(maybe_value->IsException());
- maybe_value = Top::pending_exception();
- Top::clear_pending_exception();
+ maybe_value = heap->isolate()->pending_exception();
+ heap->isolate()->clear_pending_exception();
if (caught_exception != NULL) {
*caught_exception = true;
}
@@ -8849,19 +9303,20 @@ static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
}
return value;
} else {
- return Heap::undefined_value();
+ return heap->undefined_value();
}
}
case INTERCEPTOR:
case MAP_TRANSITION:
+ case EXTERNAL_ARRAY_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
- return Heap::undefined_value();
+ return heap->undefined_value();
default:
UNREACHABLE();
}
UNREACHABLE();
- return Heap::undefined_value();
+ return heap->undefined_value();
}
@@ -8877,8 +9332,10 @@ static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
// 4: Setter function if defined
// Items 2-4 are only filled if the property has either a getter or a setter
// defined through __defineGetter__ and/or __defineSetter__.
-static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DebugGetPropertyDetails(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
@@ -8891,9 +9348,9 @@ static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
// into the embedding application can occour, and the embedding application
// could have the assumption that its own global context is the current
// context and not some internal debugger context.
- SaveContext save;
- if (Debug::InDebugger()) {
- Top::set_context(*Debug::debugger_entry()->GetContext());
+ SaveContext save(isolate);
+ if (isolate->debug()->InDebugger()) {
+ isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
}
// Skip the global proxy as it has no properties and always delegates to the
@@ -8907,17 +9364,17 @@ static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
// if so.
uint32_t index;
if (name->AsArrayIndex(&index)) {
- Handle<FixedArray> details = Factory::NewFixedArray(2);
+ Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
Object* element_or_char;
{ MaybeObject* maybe_element_or_char =
- Runtime::GetElementOrCharAt(obj, index);
+ Runtime::GetElementOrCharAt(isolate, obj, index);
if (!maybe_element_or_char->ToObject(&element_or_char)) {
return maybe_element_or_char;
}
}
details->set(0, element_or_char);
details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
- return *Factory::NewJSArrayWithElements(details);
+ return *isolate->factory()->NewJSArrayWithElements(details);
}
// Find the number of objects making up this.
@@ -8935,7 +9392,8 @@ static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
PropertyType result_type = result.type();
Handle<Object> result_callback_obj;
if (result_type == CALLBACKS) {
- result_callback_obj = Handle<Object>(result.GetCallbackObject());
+ result_callback_obj = Handle<Object>(result.GetCallbackObject(),
+ isolate);
}
Smi* property_details = result.GetPropertyDetails().AsSmi();
// DebugLookupResultValue can cause GC so details from LookupResult needs
@@ -8943,40 +9401,42 @@ static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
bool caught_exception = false;
Object* raw_value;
{ MaybeObject* maybe_raw_value =
- DebugLookupResultValue(*obj, *name, &result, &caught_exception);
+ DebugLookupResultValue(isolate->heap(), *obj, *name,
+ &result, &caught_exception);
if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
}
- Handle<Object> value(raw_value);
+ Handle<Object> value(raw_value, isolate);
// If the callback object is a fixed array then it contains JavaScript
// getter and/or setter.
bool hasJavaScriptAccessors = result_type == CALLBACKS &&
result_callback_obj->IsFixedArray();
Handle<FixedArray> details =
- Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
+ isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
details->set(0, *value);
details->set(1, property_details);
if (hasJavaScriptAccessors) {
details->set(2,
- caught_exception ? Heap::true_value()
- : Heap::false_value());
+ caught_exception ? isolate->heap()->true_value()
+ : isolate->heap()->false_value());
details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
}
- return *Factory::NewJSArrayWithElements(details);
+ return *isolate->factory()->NewJSArrayWithElements(details);
}
if (i < length - 1) {
jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
}
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DebugGetProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
@@ -8986,15 +9446,17 @@ static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
LookupResult result;
obj->Lookup(*name, &result);
if (result.IsProperty()) {
- return DebugLookupResultValue(*obj, *name, &result, NULL);
+ return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// Return the property type calculated from the property details.
// args[0]: smi with property details.
-static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
+static MaybeObject* Runtime_DebugPropertyTypeFromDetails(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(Smi, details, args[0]);
PropertyType type = PropertyDetails(details).type();
@@ -9004,7 +9466,9 @@ static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
// Return the property attribute calculated from the property details.
// args[0]: smi with property details.
-static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
+static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(Smi, details, args[0]);
PropertyAttributes attributes = PropertyDetails(details).attributes();
@@ -9014,7 +9478,9 @@ static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
// Return the property insertion index calculated from the property details.
// args[0]: smi with property details.
-static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
+static MaybeObject* Runtime_DebugPropertyIndexFromDetails(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(Smi, details, args[0]);
int index = PropertyDetails(details).index();
@@ -9025,8 +9491,10 @@ static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
// Return property value from named interceptor.
// args[0]: object
// args[1]: property name
-static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSObject, obj, 0);
RUNTIME_ASSERT(obj->HasNamedInterceptor());
@@ -9041,8 +9509,9 @@ static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
// args[0]: object
// args[1]: index
static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
- Arguments args) {
- HandleScope scope;
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSObject, obj, 0);
RUNTIME_ASSERT(obj->HasIndexedInterceptor());
@@ -9052,31 +9521,35 @@ static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
}
-static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
+static MaybeObject* Runtime_CheckExecutionState(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() >= 1);
CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
// Check that the break id is valid.
- if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
- return Top::Throw(Heap::illegal_execution_state_symbol());
+ if (isolate->debug()->break_id() == 0 ||
+ break_id != isolate->debug()->break_id()) {
+ return isolate->Throw(
+ isolate->heap()->illegal_execution_state_symbol());
}
- return Heap::true_value();
+ return isolate->heap()->true_value();
}
-static MaybeObject* Runtime_GetFrameCount(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetFrameCount(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
// Check arguments.
Object* result;
- { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
+ { MaybeObject* maybe_result = Runtime_CheckExecutionState(args, isolate);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
// Count all frames which are relevant to debugging stack trace.
int n = 0;
- StackFrame::Id id = Debug::break_frame_id();
+ StackFrame::Id id = isolate->debug()->break_frame_id();
if (id == StackFrame::NO_ID) {
// If there is no JavaScript stack frame count is 0.
return Smi::FromInt(0);
@@ -9114,22 +9587,24 @@ static const int kFrameDetailsFirstDynamicIndex = 9;
// Arguments name, value
// Locals name, value
// Return value if any
-static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetFrameDetails(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
// Check arguments.
Object* check;
- { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
+ { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
if (!maybe_check->ToObject(&check)) return maybe_check;
}
CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+ Heap* heap = isolate->heap();
// Find the relevant frame with the requested index.
- StackFrame::Id id = Debug::break_frame_id();
+ StackFrame::Id id = isolate->debug()->break_frame_id();
if (id == StackFrame::NO_ID) {
// If there are no JavaScript stack frames return undefined.
- return Heap::undefined_value();
+ return heap->undefined_value();
}
int count = 0;
JavaScriptFrameIterator it(id);
@@ -9137,24 +9612,25 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
if (count == index) break;
count++;
}
- if (it.done()) return Heap::undefined_value();
+ if (it.done()) return heap->undefined_value();
bool is_optimized_frame =
- it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
+ it.frame()->LookupCode(isolate)->kind() == Code::OPTIMIZED_FUNCTION;
// Traverse the saved contexts chain to find the active context for the
// selected frame.
- SaveContext* save = Top::save_context();
+ SaveContext* save = isolate->save_context();
while (save != NULL && !save->below(it.frame())) {
save = save->prev();
}
ASSERT(save != NULL);
// Get the frame id.
- Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
+ Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
// Find source position.
- int position = it.frame()->code()->SourcePosition(it.frame()->pc());
+ int position =
+ it.frame()->LookupCode(isolate)->SourcePosition(it.frame()->pc());
// Check for constructor frame.
bool constructor = it.frame()->IsConstructor();
@@ -9172,7 +9648,8 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
// TODO(1240907): Hide compiler-introduced stack variables
// (e.g. .result)? For users of the debugger, they will probably be
// confusing.
- Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
+ Handle<FixedArray> locals =
+ isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
// Fill in the names of the locals.
for (int i = 0; i < info.NumberOfLocals(); i++) {
@@ -9187,7 +9664,7 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
//
// TODO(1140): We should be able to get the correct values
// for locals in optimized frames.
- locals->set(i * 2 + 1, Heap::undefined_value());
+ locals->set(i * 2 + 1, isolate->heap()->undefined_value());
} else if (i < info.number_of_stack_slots()) {
// Get the value from the stack.
locals->set(i * 2 + 1, it.frame()->GetExpression(i));
@@ -9208,12 +9685,12 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
// frame or if the frame is optimized it cannot be at a return.
bool at_return = false;
if (!is_optimized_frame && index == 0) {
- at_return = Debug::IsBreakAtReturn(it.frame());
+ at_return = isolate->debug()->IsBreakAtReturn(it.frame());
}
// If positioned just before return find the value to be returned and add it
// to the frame information.
- Handle<Object> return_value = Factory::undefined_value();
+ Handle<Object> return_value = isolate->factory()->undefined_value();
if (at_return) {
StackFrameIterator it2;
Address internal_frame_sp = NULL;
@@ -9229,7 +9706,8 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
// entering the debug break exit frame.
if (internal_frame_sp != NULL) {
return_value =
- Handle<Object>(Memory::Object_at(internal_frame_sp));
+ Handle<Object>(Memory::Object_at(internal_frame_sp),
+ isolate);
break;
}
}
@@ -9251,15 +9729,15 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
// Find the number of arguments to fill. At least fill the number of
// parameters for the function and fill more if more parameters are provided.
int argument_count = info.number_of_parameters();
- if (argument_count < it.frame()->GetProvidedParametersCount()) {
- argument_count = it.frame()->GetProvidedParametersCount();
+ if (argument_count < it.frame()->ComputeParametersCount()) {
+ argument_count = it.frame()->ComputeParametersCount();
}
// Calculate the size of the result.
int details_size = kFrameDetailsFirstDynamicIndex +
2 * (argument_count + info.NumberOfLocals()) +
(at_return ? 1 : 0);
- Handle<FixedArray> details = Factory::NewFixedArray(details_size);
+ Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
// Add the frame id.
details->set(kFrameDetailsFrameIdIndex, *frame_id);
@@ -9278,18 +9756,19 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
if (position != RelocInfo::kNoPosition) {
details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
} else {
- details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
+ details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
}
// Add the constructor information.
- details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
+ details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
// Add the at return information.
- details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
+ details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
// Add information on whether this frame is invoked in the debugger context.
details->set(kFrameDetailsDebuggerFrameIndex,
- Heap::ToBoolean(*save->context() == *Debug::debug_context()));
+ heap->ToBoolean(*save->context() ==
+ *isolate->debug()->debug_context()));
// Fill the dynamic part.
int details_index = kFrameDetailsFirstDynamicIndex;
@@ -9300,7 +9779,7 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
if (i < info.number_of_parameters()) {
details->set(details_index++, *info.parameter_name(i));
} else {
- details->set(details_index++, Heap::undefined_value());
+ details->set(details_index++, heap->undefined_value());
}
// Parameter value. If we are inspecting an optimized frame, use
@@ -9309,10 +9788,10 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
// TODO(3141533): We should be able to get the actual parameter
// value for optimized frames.
if (!is_optimized_frame &&
- (i < it.frame()->GetProvidedParametersCount())) {
+ (i < it.frame()->ComputeParametersCount())) {
details->set(details_index++, it.frame()->GetParameter(i));
} else {
- details->set(details_index++, Heap::undefined_value());
+ details->set(details_index++, heap->undefined_value());
}
}
@@ -9329,7 +9808,7 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
// Add the receiver (same as in function frame).
// THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
// THE FRAME ITERATOR TO WRAP THE RECEIVER.
- Handle<Object> receiver(it.frame()->receiver());
+ Handle<Object> receiver(it.frame()->receiver(), isolate);
if (!receiver->IsJSObject()) {
// If the receiver is NOT a JSObject we have hit an optimization
// where a value object is not converted into a wrapped JS objects.
@@ -9339,17 +9818,19 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
it.Advance();
Handle<Context> calling_frames_global_context(
Context::cast(Context::cast(it.frame()->context())->global_context()));
- receiver = Factory::ToObject(receiver, calling_frames_global_context);
+ receiver =
+ isolate->factory()->ToObject(receiver, calling_frames_global_context);
}
details->set(kFrameDetailsReceiverIndex, *receiver);
ASSERT_EQ(details_size, details_index);
- return *Factory::NewJSArrayWithElements(details);
+ return *isolate->factory()->NewJSArrayWithElements(details);
}
// Copy all the context locals into an object used to materialize a scope.
static bool CopyContextLocalsToScopeObject(
+ Isolate* isolate,
Handle<SerializedScopeInfo> serialized_scope_info,
ScopeInfo<>& scope_info,
Handle<Context> context,
@@ -9362,11 +9843,13 @@ static bool CopyContextLocalsToScopeObject(
*scope_info.context_slot_name(i), NULL);
// Don't include the arguments shadow (.arguments) context variable.
- if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
+ if (*scope_info.context_slot_name(i) !=
+ isolate->heap()->arguments_shadow_symbol()) {
RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
SetProperty(scope_object,
scope_info.context_slot_name(i),
- Handle<Object>(context->get(context_index)),
+ Handle<Object>(context->get(context_index), isolate),
NONE,
kNonStrictMode),
false);
@@ -9379,7 +9862,8 @@ static bool CopyContextLocalsToScopeObject(
// Create a plain JSObject which materializes the local scope for the specified
// frame.
-static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
+static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
+ JavaScriptFrame* frame) {
Handle<JSFunction> function(JSFunction::cast(frame->function()));
Handle<SharedFunctionInfo> shared(function->shared());
Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
@@ -9387,14 +9871,16 @@ static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
// Allocate and initialize a JSObject with all the arguments, stack locals
// heap locals and extension properties of the debugged function.
- Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
+ Handle<JSObject> local_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
// First fill all parameters.
for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
SetProperty(local_scope,
scope_info.parameter_name(i),
- Handle<Object>(frame->GetParameter(i)),
+ Handle<Object>(frame->GetParameter(i), isolate),
NONE,
kNonStrictMode),
Handle<JSObject>());
@@ -9403,9 +9889,10 @@ static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
// Second fill all stack locals.
for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
SetProperty(local_scope,
scope_info.stack_slot_name(i),
- Handle<Object>(frame->GetExpression(i)),
+ Handle<Object>(frame->GetExpression(i), isolate),
NONE,
kNonStrictMode),
Handle<JSObject>());
@@ -9414,7 +9901,8 @@ static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
// Third fill all context locals.
Handle<Context> frame_context(Context::cast(frame->context()));
Handle<Context> function_context(frame_context->fcontext());
- if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
+ if (!CopyContextLocalsToScopeObject(isolate,
+ serialized_scope_info, scope_info,
function_context, local_scope)) {
return Handle<JSObject>();
}
@@ -9431,6 +9919,7 @@ static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
ASSERT(keys->get(i)->IsString());
Handle<String> key(String::cast(keys->get(i)));
RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
SetProperty(local_scope,
key,
GetProperty(ext, key),
@@ -9446,7 +9935,8 @@ static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
// Create a plain JSObject which materializes the closure content for the
// context.
-static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
+static Handle<JSObject> MaterializeClosure(Isolate* isolate,
+ Handle<Context> context) {
ASSERT(context->is_function_context());
Handle<SharedFunctionInfo> shared(context->closure()->shared());
@@ -9455,12 +9945,13 @@ static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
// Allocate and initialize a JSObject with all the content of theis function
// closure.
- Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
+ Handle<JSObject> closure_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
// Check whether the arguments shadow object exists.
int arguments_shadow_index =
- shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
- NULL);
+ shared->scope_info()->ContextSlotIndex(
+ isolate->heap()->arguments_shadow_symbol(), NULL);
if (arguments_shadow_index >= 0) {
// In this case all the arguments are available in the arguments shadow
// object.
@@ -9470,9 +9961,10 @@ static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
// We don't expect exception-throwing getters on the arguments shadow.
Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
SetProperty(closure_scope,
scope_info.parameter_name(i),
- Handle<Object>(element),
+ Handle<Object>(element, isolate),
NONE,
kNonStrictMode),
Handle<JSObject>());
@@ -9480,7 +9972,8 @@ static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
}
// Fill all context locals to the context extension.
- if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
+ if (!CopyContextLocalsToScopeObject(isolate,
+ serialized_scope_info, scope_info,
context, closure_scope)) {
return Handle<JSObject>();
}
@@ -9494,7 +9987,8 @@ static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
// Names of variables introduced by eval are strings.
ASSERT(keys->get(i)->IsString());
Handle<String> key(String::cast(keys->get(i)));
- RETURN_IF_EMPTY_HANDLE_VALUE(
+ RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
SetProperty(closure_scope,
key,
GetProperty(ext, key),
@@ -9525,8 +10019,9 @@ class ScopeIterator {
ScopeTypeCatch
};
- explicit ScopeIterator(JavaScriptFrame* frame)
- : frame_(frame),
+ ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
+ : isolate_(isolate),
+ frame_(frame),
function_(JSFunction::cast(frame->function())),
context_(Context::cast(frame->context())),
local_done_(false),
@@ -9539,7 +10034,7 @@ class ScopeIterator {
// Checking for the existence of .result seems fragile, but the scope info
// saved with the code object does not otherwise have that information.
int index = function_->shared()->scope_info()->
- StackSlotIndex(Heap::result_symbol());
+ StackSlotIndex(isolate_->heap()->result_symbol());
at_local_ = index < 0;
} else if (context_->is_function_context()) {
at_local_ = true;
@@ -9617,7 +10112,7 @@ class ScopeIterator {
break;
case ScopeIterator::ScopeTypeLocal:
// Materialize the content of the local scope into a JSObject.
- return MaterializeLocalScope(frame_);
+ return MaterializeLocalScope(isolate_, frame_);
break;
case ScopeIterator::ScopeTypeWith:
case ScopeIterator::ScopeTypeCatch:
@@ -9626,7 +10121,7 @@ class ScopeIterator {
break;
case ScopeIterator::ScopeTypeClosure:
// Materialize the content of the closure scope into a JSObject.
- return MaterializeClosure(CurrentContext());
+ return MaterializeClosure(isolate_, CurrentContext());
break;
}
UNREACHABLE();
@@ -9705,6 +10200,7 @@ class ScopeIterator {
#endif
private:
+ Isolate* isolate_;
JavaScriptFrame* frame_;
Handle<JSFunction> function_;
Handle<Context> context_;
@@ -9715,13 +10211,14 @@ class ScopeIterator {
};
-static MaybeObject* Runtime_GetScopeCount(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetScopeCount(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
// Check arguments.
Object* check;
- { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
+ { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
if (!maybe_check->ToObject(&check)) return maybe_check;
}
CONVERT_CHECKED(Smi, wrapped_id, args[1]);
@@ -9733,7 +10230,7 @@ static MaybeObject* Runtime_GetScopeCount(Arguments args) {
// Count the visible scopes.
int n = 0;
- for (ScopeIterator it(frame); !it.Done(); it.Next()) {
+ for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
n++;
}
@@ -9753,13 +10250,14 @@ static const int kScopeDetailsSize = 2;
// The array returned contains the following information:
// 0: Scope type
// 1: Scope object
-static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetScopeDetails(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
// Check arguments.
Object* check;
- { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
+ { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
if (!maybe_check->ToObject(&check)) return maybe_check;
}
CONVERT_CHECKED(Smi, wrapped_id, args[1]);
@@ -9772,57 +10270,60 @@ static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
// Find the requested scope.
int n = 0;
- ScopeIterator it(frame);
+ ScopeIterator it(isolate, frame);
for (; !it.Done() && n < index; it.Next()) {
n++;
}
if (it.Done()) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// Calculate the size of the result.
int details_size = kScopeDetailsSize;
- Handle<FixedArray> details = Factory::NewFixedArray(details_size);
+ Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
// Fill in scope details.
details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
Handle<JSObject> scope_object = it.ScopeObject();
- RETURN_IF_EMPTY_HANDLE(scope_object);
+ RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
details->set(kScopeDetailsObjectIndex, *scope_object);
- return *Factory::NewJSArrayWithElements(details);
+ return *isolate->factory()->NewJSArrayWithElements(details);
}
-static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DebugPrintScopes(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 0);
#ifdef DEBUG
// Print the scopes for the top frame.
StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
- for (ScopeIterator it(frame); !it.Done(); it.Next()) {
+ for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
it.DebugPrint();
}
#endif
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_GetThreadCount(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetThreadCount(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
// Check arguments.
Object* result;
- { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
+ { MaybeObject* maybe_result = Runtime_CheckExecutionState(args, isolate);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
// Count all archived V8 threads.
int n = 0;
- for (ThreadState* thread = ThreadState::FirstInUse();
+ for (ThreadState* thread =
+ isolate->thread_manager()->FirstThreadStateInUse();
thread != NULL;
thread = thread->Next()) {
n++;
@@ -9844,70 +10345,78 @@ static const int kThreadDetailsSize = 2;
// The array returned contains the following information:
// 0: Is current thread?
// 1: Thread id
-static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetThreadDetails(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
// Check arguments.
Object* check;
- { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
+ { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
if (!maybe_check->ToObject(&check)) return maybe_check;
}
CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
// Allocate array for result.
- Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
+ Handle<FixedArray> details =
+ isolate->factory()->NewFixedArray(kThreadDetailsSize);
// Thread index 0 is current thread.
if (index == 0) {
// Fill the details.
- details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
+ details->set(kThreadDetailsCurrentThreadIndex,
+ isolate->heap()->true_value());
details->set(kThreadDetailsThreadIdIndex,
- Smi::FromInt(ThreadManager::CurrentId()));
+ Smi::FromInt(
+ isolate->thread_manager()->CurrentId()));
} else {
// Find the thread with the requested index.
int n = 1;
- ThreadState* thread = ThreadState::FirstInUse();
+ ThreadState* thread =
+ isolate->thread_manager()->FirstThreadStateInUse();
while (index != n && thread != NULL) {
thread = thread->Next();
n++;
}
if (thread == NULL) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// Fill the details.
- details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
+ details->set(kThreadDetailsCurrentThreadIndex,
+ isolate->heap()->false_value());
details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
}
// Convert to JS array and return.
- return *Factory::NewJSArrayWithElements(details);
+ return *isolate->factory()->NewJSArrayWithElements(details);
}
// Sets the disable break state
// args[0]: disable break state
-static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_SetDisableBreak(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
- Debug::set_disable_break(disable_break);
- return Heap::undefined_value();
+ isolate->debug()->set_disable_break(disable_break);
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetBreakLocations(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, fun, 0);
Handle<SharedFunctionInfo> shared(fun->shared());
// Find the number of break points
Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
- if (break_locations->IsUndefined()) return Heap::undefined_value();
+ if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
// Return array as JS array
- return *Factory::NewJSArrayWithElements(
+ return *isolate->factory()->NewJSArrayWithElements(
Handle<FixedArray>::cast(break_locations));
}
@@ -9916,8 +10425,9 @@ static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
// args[0]: function
// args[1]: number: break source position (within the function source)
// args[2]: number: break point object
-static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_SetFunctionBreakPoint(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(JSFunction, fun, 0);
Handle<SharedFunctionInfo> shared(fun->shared());
@@ -9926,13 +10436,15 @@ static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
Handle<Object> break_point_object_arg = args.at<Object>(2);
// Set break point.
- Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
+ isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
+ &source_position);
return Smi::FromInt(source_position);
}
-Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
+Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
+ Handle<Script> script,
int position) {
// Iterate the heap looking for SharedFunctionInfo generated from the
// script. The inner most SharedFunctionInfo containing the source position
@@ -9991,7 +10503,7 @@ Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
}
if (target.is_null()) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// If the candidate found is compiled we are done. NOTE: when lazy
@@ -10015,8 +10527,9 @@ Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
// args[0]: script to set break point in
// args[1]: number: break source position (within the script source)
// args[2]: number: break point object
-static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_SetScriptBreakPoint(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
@@ -10028,7 +10541,7 @@ static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
Handle<Script> script(Script::cast(wrapper->value()));
Object* result = Runtime::FindSharedFunctionInfoInScript(
- script, source_position);
+ isolate, script, source_position);
if (!result->IsUndefined()) {
Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
// Find position within function. The script position might be before the
@@ -10039,33 +10552,35 @@ static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
} else {
position = source_position - shared->start_position();
}
- Debug::SetBreakPoint(shared, break_point_object_arg, &position);
+ isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
position += shared->start_position();
return Smi::FromInt(position);
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// Clear a break point
// args[0]: number: break point object
-static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_ClearBreakPoint(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
Handle<Object> break_point_object_arg = args.at<Object>(0);
// Clear break point.
- Debug::ClearBreakPoint(break_point_object_arg);
+ isolate->debug()->ClearBreakPoint(break_point_object_arg);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// Change the state of break on exceptions.
// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
// args[1]: Boolean indicating on/off.
-static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_ChangeBreakOnException(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
RUNTIME_ASSERT(args[0]->IsNumber());
CONVERT_BOOLEAN_CHECKED(enable, args[1]);
@@ -10075,21 +10590,22 @@ static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
ExceptionBreakType type =
static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
// Update break point state.
- Debug::ChangeBreakOnException(type, enable);
- return Heap::undefined_value();
+ isolate->debug()->ChangeBreakOnException(type, enable);
+ return isolate->heap()->undefined_value();
}
// Returns the state of break on exceptions
// args[0]: boolean indicating uncaught exceptions
-static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_IsBreakOnException(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
RUNTIME_ASSERT(args[0]->IsNumber());
ExceptionBreakType type =
static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
- bool result = Debug::IsBreakOnException(type);
+ bool result = isolate->debug()->IsBreakOnException(type);
return Smi::FromInt(result);
}
@@ -10099,16 +10615,17 @@ static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
// args[1]: step action from the enumeration StepAction
// args[2]: number of times to perform the step, for step out it is the number
// of frames to step down.
-static MaybeObject* Runtime_PrepareStep(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_PrepareStep(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 3);
// Check arguments.
Object* check;
- { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
+ { MaybeObject* maybe_check = Runtime_CheckExecutionState(args, isolate);
if (!maybe_check->ToObject(&check)) return maybe_check;
}
if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
// Get the step action and check validity.
@@ -10118,30 +10635,32 @@ static MaybeObject* Runtime_PrepareStep(Arguments args) {
step_action != StepOut &&
step_action != StepInMin &&
step_action != StepMin) {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
// Get the number of steps.
int step_count = NumberToInt32(args[2]);
if (step_count < 1) {
- return Top::Throw(Heap::illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_symbol());
}
// Clear all current stepping setup.
- Debug::ClearStepping();
+ isolate->debug()->ClearStepping();
// Prepare step.
- Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
- return Heap::undefined_value();
+ isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
+ step_count);
+ return isolate->heap()->undefined_value();
}
// Clear all stepping set by PrepareStep.
-static MaybeObject* Runtime_ClearStepping(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_ClearStepping(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 0);
- Debug::ClearStepping();
- return Heap::undefined_value();
+ isolate->debug()->ClearStepping();
+ return isolate->heap()->undefined_value();
}
@@ -10158,15 +10677,15 @@ static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
Handle<Context> previous(context_chain->previous());
Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
Handle<Context> context = CopyWithContextChain(function_context, previous);
- return Factory::NewWithContext(context,
- extension,
- context_chain->IsCatchContext());
+ return context->GetIsolate()->factory()->NewWithContext(
+ context, extension, context_chain->IsCatchContext());
}
// Helper function to find or create the arguments object for
// Runtime_DebugEvaluate.
-static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
+static Handle<Object> GetArgumentsObject(Isolate* isolate,
+ JavaScriptFrame* frame,
Handle<JSFunction> function,
Handle<SerializedScopeInfo> scope_info,
const ScopeInfo<>* sinfo,
@@ -10176,22 +10695,24 @@ static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
// does not support eval) then create an 'arguments' object.
int index;
if (sinfo->number_of_stack_slots() > 0) {
- index = scope_info->StackSlotIndex(Heap::arguments_symbol());
+ index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
if (index != -1) {
- return Handle<Object>(frame->GetExpression(index));
+ return Handle<Object>(frame->GetExpression(index), isolate);
}
}
if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
- index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
+ index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
+ NULL);
if (index != -1) {
- return Handle<Object>(function_context->get(index));
+ return Handle<Object>(function_context->get(index), isolate);
}
}
- const int length = frame->GetProvidedParametersCount();
- Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
- Handle<FixedArray> array = Factory::NewFixedArray(length);
+ const int length = frame->ComputeParametersCount();
+ Handle<JSObject> arguments =
+ isolate->factory()->NewArgumentsObject(function, length);
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
AssertNoAllocation no_gc;
WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
@@ -10203,6 +10724,10 @@ static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
}
+static const char kSourceStr[] =
+ "(function(arguments,__source__){return eval(__source__);})";
+
+
// Evaluate a piece of JavaScript in the context of a stack frame for
// debugging. This is accomplished by creating a new context which in its
// extension part has all the parameters and locals of the function on the
@@ -10214,14 +10739,16 @@ static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
// stack frame presenting the same view of the values of parameters and
// local variables as if the piece of JavaScript was evaluated at the point
// where the function on the stack frame is currently stopped.
-static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DebugEvaluate(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
// Check the execution state and decode arguments frame and source to be
// evaluated.
ASSERT(args.length() == 5);
Object* check_result;
- { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
+ { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args,
+ isolate);
if (!maybe_check_result->ToObject(&check_result)) {
return maybe_check_result;
}
@@ -10244,13 +10771,13 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
// Traverse the saved contexts chain to find the active context for the
// selected frame.
- SaveContext* save = Top::save_context();
+ SaveContext* save = isolate->save_context();
while (save != NULL && !save->below(frame)) {
save = save->prev();
}
ASSERT(save != NULL);
- SaveContext savex;
- Top::set_context(*(save->context()));
+ SaveContext savex(isolate);
+ isolate->set_context(*(save->context()));
// Create the (empty) function replacing the function on the stack frame for
// the purpose of evaluating in the context created below. It is important
@@ -10259,7 +10786,8 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
// in Context::Lookup, where context slots for parameters and local variables
// are looked at before the extension object.
Handle<JSFunction> go_between =
- Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
+ isolate->factory()->NewFunction(isolate->factory()->empty_string(),
+ isolate->factory()->undefined_value());
go_between->set_context(function->context());
#ifdef DEBUG
ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
@@ -10268,13 +10796,14 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
#endif
// Materialize the content of the local scope into a JSObject.
- Handle<JSObject> local_scope = MaterializeLocalScope(frame);
- RETURN_IF_EMPTY_HANDLE(local_scope);
+ Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
+ RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
// Allocate a new context for the debug evaluation and set the extension
// object build.
Handle<Context> context =
- Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
+ isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
+ go_between);
context->set_extension(*local_scope);
// Copy any with contexts present and chain them in front of this context.
Handle<Context> frame_context(Context::cast(frame->context()));
@@ -10282,7 +10811,7 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
context = CopyWithContextChain(frame_context, context);
if (additional_context->IsJSObject()) {
- context = Factory::NewWithContext(context,
+ context = isolate->factory()->NewWithContext(context,
Handle<JSObject>::cast(additional_context), false);
}
@@ -10291,12 +10820,10 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
// 'arguments'. This it to have access to what would have been 'arguments' in
// the function being debugged.
// function(arguments,__source__) {return eval(__source__);}
- static const char* source_str =
- "(function(arguments,__source__){return eval(__source__);})";
- static const int source_str_length = StrLength(source_str);
+
Handle<String> function_source =
- Factory::NewStringFromAscii(Vector<const char>(source_str,
- source_str_length));
+ isolate->factory()->NewStringFromAscii(
+ Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
// Currently, the eval code will be executed in non-strict mode,
// even in the strict code context.
@@ -10307,17 +10834,18 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
kNonStrictMode);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
- Factory::NewFunctionFromSharedFunctionInfo(shared, context);
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
// Invoke the result of the compilation to get the evaluation function.
bool has_pending_exception;
- Handle<Object> receiver(frame->receiver());
+ Handle<Object> receiver(frame->receiver(), isolate);
Handle<Object> evaluation_function =
Execution::Call(compiled_function, receiver, 0, NULL,
&has_pending_exception);
if (has_pending_exception) return Failure::Exception();
- Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
+ Handle<Object> arguments = GetArgumentsObject(isolate, frame,
+ function, scope_info,
&sinfo, function_context);
// Invoke the evaluation function and return the result.
@@ -10339,14 +10867,16 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
}
-static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DebugEvaluateGlobal(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
// Check the execution state and decode arguments frame and source to be
// evaluated.
ASSERT(args.length() == 4);
Object* check_result;
- { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
+ { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args,
+ isolate);
if (!maybe_check_result->ToObject(&check_result)) {
return maybe_check_result;
}
@@ -10359,28 +10889,30 @@ static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
DisableBreak disable_break_save(disable_break);
// Enter the top context from before the debugger was invoked.
- SaveContext save;
+ SaveContext save(isolate);
SaveContext* top = &save;
- while (top != NULL && *top->context() == *Debug::debug_context()) {
+ while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
top = top->prev();
}
if (top != NULL) {
- Top::set_context(*top->context());
+ isolate->set_context(*top->context());
}
// Get the global context now set to the top context from before the
// debugger was invoked.
- Handle<Context> context = Top::global_context();
+ Handle<Context> context = isolate->global_context();
bool is_global = true;
if (additional_context->IsJSObject()) {
// Create a function context first, than put 'with' context on top of it.
- Handle<JSFunction> go_between = Factory::NewFunction(
- Factory::empty_string(), Factory::undefined_value());
+ Handle<JSFunction> go_between = isolate->factory()->NewFunction(
+ isolate->factory()->empty_string(),
+ isolate->factory()->undefined_value());
go_between->set_context(*context);
context =
- Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
+ isolate->factory()->NewFunctionContext(
+ Context::MIN_CONTEXT_SLOTS, go_between);
context->set_extension(JSObject::cast(*additional_context));
is_global = false;
}
@@ -10392,12 +10924,13 @@ static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
Compiler::CompileEval(source, context, is_global, kNonStrictMode);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
- Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
- context));
+ Handle<JSFunction>(
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
+ context));
// Invoke the result of the compilation to get the evaluation function.
bool has_pending_exception;
- Handle<Object> receiver = Top::global();
+ Handle<Object> receiver = isolate->global();
Handle<Object> result =
Execution::Call(compiled_function, receiver, 0, NULL,
&has_pending_exception);
@@ -10406,12 +10939,13 @@ static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
}
-static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_DebugGetLoadedScripts(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 0);
// Fill the script objects.
- Handle<FixedArray> instances = Debug::GetLoadedScripts();
+ Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
// Convert the script objects to proper JS objects.
for (int i = 0; i < instances->length(); i++) {
@@ -10426,7 +10960,8 @@ static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
}
// Return result as a JS array.
- Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
+ Handle<JSObject> result =
+ isolate->factory()->NewJSObject(isolate->array_function());
Handle<JSArray>::cast(result)->SetContent(*instances);
return *result;
}
@@ -10506,11 +11041,12 @@ static int DebugReferencedBy(JSObject* target,
// args[0]: the object to find references to
// args[1]: constructor function for instances to exclude (Mirror)
// args[2]: the the maximum number of objects to return
-static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
+static MaybeObject* Runtime_DebugReferencedBy(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 3);
// First perform a full GC in order to avoid references from dead objects.
- Heap::CollectAllGarbage(false);
+ isolate->heap()->CollectAllGarbage(false);
// Check parameters.
CONVERT_CHECKED(JSObject, target, args[0]);
@@ -10522,7 +11058,7 @@ static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
// Get the constructor function for context extension and arguments array.
JSObject* arguments_boilerplate =
- Top::context()->global_context()->arguments_boilerplate();
+ isolate->context()->global_context()->arguments_boilerplate();
JSFunction* arguments_function =
JSFunction::cast(arguments_boilerplate->map()->constructor());
@@ -10533,7 +11069,7 @@ static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
// Allocate an array to hold the result.
Object* object;
- { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
+ { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
FixedArray* instances = FixedArray::cast(object);
@@ -10544,8 +11080,8 @@ static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
// Return result as JS array.
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateJSObject(
- Top::context()->global_context()->array_function());
+ { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
+ isolate->context()->global_context()->array_function());
if (!maybe_result->ToObject(&result)) return maybe_result;
}
JSArray::cast(result)->SetContent(instances);
@@ -10586,11 +11122,12 @@ static int DebugConstructedBy(JSFunction* constructor, int max_references,
// Scan the heap for objects constructed by a specific function.
// args[0]: the constructor to find instances of
// args[1]: the the maximum number of objects to return
-static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
+static MaybeObject* Runtime_DebugConstructedBy(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
// First perform a full GC in order to avoid dead objects.
- Heap::CollectAllGarbage(false);
+ isolate->heap()->CollectAllGarbage(false);
// Check parameters.
CONVERT_CHECKED(JSFunction, constructor, args[0]);
@@ -10603,7 +11140,7 @@ static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
// Allocate an array to hold the result.
Object* object;
- { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
+ { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
if (!maybe_object->ToObject(&object)) return maybe_object;
}
FixedArray* instances = FixedArray::cast(object);
@@ -10613,8 +11150,8 @@ static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
// Return result as JS array.
Object* result;
- { MaybeObject* maybe_result = Heap::AllocateJSObject(
- Top::context()->global_context()->array_function());
+ { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
+ isolate->context()->global_context()->array_function());
if (!maybe_result->ToObject(&result)) return maybe_result;
}
JSArray::cast(result)->SetContent(instances);
@@ -10624,7 +11161,8 @@ static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
// Find the effective prototype object as returned by __proto__.
// args[0]: the object to find the prototype for.
-static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
+static MaybeObject* Runtime_DebugGetPrototype(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSObject, obj, args[0]);
@@ -10634,16 +11172,19 @@ static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
}
-static MaybeObject* Runtime_SystemBreak(Arguments args) {
+static MaybeObject* Runtime_SystemBreak(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 0);
CPU::DebugBreak();
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
+static MaybeObject* Runtime_DebugDisassembleFunction(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef DEBUG
- HandleScope scope;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
// Get the function and make sure it is compiled.
CONVERT_ARG_CHECKED(JSFunction, func, 0);
@@ -10653,13 +11194,15 @@ static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
}
func->code()->PrintLn();
#endif // DEBUG
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
+static MaybeObject* Runtime_DebugDisassembleConstructor(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef DEBUG
- HandleScope scope;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
// Get the function and make sure it is compiled.
CONVERT_ARG_CHECKED(JSFunction, func, 0);
@@ -10669,11 +11212,13 @@ static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
}
shared->construct_stub()->PrintLn();
#endif // DEBUG
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
+static MaybeObject* Runtime_FunctionGetInferredName(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -10683,7 +11228,7 @@ static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
static int FindSharedFunctionInfosForScript(Script* script,
- FixedArray* buffer) {
+ FixedArray* buffer) {
AssertNoAllocation no_allocations;
int counter = 0;
@@ -10710,9 +11255,10 @@ static int FindSharedFunctionInfosForScript(Script* script,
// to this script. Returns JSArray of SharedFunctionInfo wrapped
// in OpaqueReferences.
static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
- Arguments args) {
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_CHECKED(JSValue, script_value, args[0]);
Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
@@ -10720,14 +11266,14 @@ static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
const int kBufferSize = 32;
Handle<FixedArray> array;
- array = Factory::NewFixedArray(kBufferSize);
+ array = isolate->factory()->NewFixedArray(kBufferSize);
int number = FindSharedFunctionInfosForScript(*script, *array);
if (number > kBufferSize) {
- array = Factory::NewFixedArray(number);
+ array = isolate->factory()->NewFixedArray(number);
FindSharedFunctionInfosForScript(*script, *array);
}
- Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
+ Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
result->set_length(Smi::FromInt(number));
LiveEdit::WrapSharedFunctionInfos(result);
@@ -10742,16 +11288,18 @@ static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
// Returns a JSArray of compilation infos. The array is ordered so that
// each function with all its descendant is always stored in a continues range
// with the function itself going first. The root function is a script function.
-static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
+static MaybeObject* Runtime_LiveEditGatherCompileInfo(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_CHECKED(JSValue, script, args[0]);
CONVERT_ARG_CHECKED(String, source, 1);
Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
- if (Top::has_pending_exception()) {
+ if (isolate->has_pending_exception()) {
return Failure::Exception();
}
@@ -10761,12 +11309,13 @@ static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
// Changes the source of the script to a new_source.
// If old_script_name is provided (i.e. is a String), also creates a copy of
// the script with its original source and sends notification to debugger.
-static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
+static MaybeObject* Runtime_LiveEditReplaceScript(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 3);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_CHECKED(JSValue, original_script_value, args[0]);
CONVERT_ARG_CHECKED(String, new_source, 1);
- Handle<Object> old_script_name(args[2]);
+ Handle<Object> old_script_name(args[2], isolate);
CONVERT_CHECKED(Script, original_script_pointer,
original_script_value->value());
@@ -10780,23 +11329,27 @@ static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
Handle<Script> script_handle(Script::cast(old_script));
return *(GetScriptWrapper(script_handle));
} else {
- return Heap::null_value();
+ return isolate->heap()->null_value();
}
}
-static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
+static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 1);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
return LiveEdit::FunctionSourceUpdated(shared_info);
}
// Replaces code of SharedFunctionInfo with a new one.
-static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
+static MaybeObject* Runtime_LiveEditReplaceFunctionCode(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
@@ -10804,17 +11357,19 @@ static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
}
// Connects SharedFunctionInfo to another script.
-static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
+static MaybeObject* Runtime_LiveEditFunctionSetScript(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
- Handle<Object> function_object(args[0]);
- Handle<Object> script_object(args[1]);
+ HandleScope scope(isolate);
+ Handle<Object> function_object(args[0], isolate);
+ Handle<Object> script_object(args[1], isolate);
if (function_object->IsJSValue()) {
Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
if (script_object->IsJSValue()) {
CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
- script_object = Handle<Object>(script);
+ script_object = Handle<Object>(script, isolate);
}
LiveEdit::SetFunctionScript(function_wrapper, script_object);
@@ -10823,15 +11378,17 @@ static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
// and we check it in this function.
}
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// In a code of a parent function replaces original function as embedded object
// with a substitution one.
-static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
+static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 3);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
@@ -10840,7 +11397,7 @@ static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
subst_wrapper);
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
@@ -10849,9 +11406,11 @@ static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
// array of groups of 3 numbers:
// (change_begin, change_end, change_end_new_position).
// Each group describes a change in text; groups are sorted by change_begin.
-static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
+static MaybeObject* Runtime_LiveEditPatchFunctionPositions(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
@@ -10863,9 +11422,11 @@ static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
// checks that none of them have activations on stacks (of any thread).
// Returns array of the same length with corresponding results of
// LiveEdit::FunctionPatchabilityStatus type.
-static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
+static MaybeObject* Runtime_LiveEditCheckAndDropActivations(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
@@ -10875,9 +11436,10 @@ static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
// Compares 2 strings line-by-line, then token-wise and returns diff in form
// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
// of diff chunks.
-static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
+static MaybeObject* Runtime_LiveEditCompareStrings(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(String, s1, 0);
CONVERT_ARG_CHECKED(String, s2, 1);
@@ -10885,20 +11447,21 @@ static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
}
-
// A testing entry. Returns statement position which is the closest to
// source_position.
-static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
+static MaybeObject* Runtime_GetFunctionCodePositionFromSource(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
- Handle<Code> code(function->code());
+ Handle<Code> code(function->code(), isolate);
if (code->kind() != Code::FUNCTION &&
code->kind() != Code::OPTIMIZED_FUNCTION) {
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
@@ -10925,9 +11488,10 @@ static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
// Calls specified function with or without entering the debugger.
// This is used in unit tests to run code as if debugger is entered or simply
// to have a stack with C++ frame in the middle.
-static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
+static MaybeObject* Runtime_ExecuteInDebugContext(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
- HandleScope scope;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
@@ -10935,11 +11499,11 @@ static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
bool pending_exception;
{
if (without_debugger) {
- result = Execution::Call(function, Top::global(), 0, NULL,
+ result = Execution::Call(function, isolate->global(), 0, NULL,
&pending_exception);
} else {
EnterDebugger enter_debugger;
- result = Execution::Call(function, Top::global(), 0, NULL,
+ result = Execution::Call(function, isolate->global(), 0, NULL,
&pending_exception);
}
}
@@ -10952,61 +11516,68 @@ static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
// Sets a v8 flag.
-static MaybeObject* Runtime_SetFlags(Arguments args) {
+static MaybeObject* Runtime_SetFlags(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
CONVERT_CHECKED(String, arg, args[0]);
SmartPointer<char> flags =
arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
FlagList::SetFlagsFromString(*flags, StrLength(*flags));
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
// Performs a GC.
// Presently, it only does a full GC.
-static MaybeObject* Runtime_CollectGarbage(Arguments args) {
- Heap::CollectAllGarbage(true);
- return Heap::undefined_value();
+static MaybeObject* Runtime_CollectGarbage(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ isolate->heap()->CollectAllGarbage(true);
+ return isolate->heap()->undefined_value();
}
// Gets the current heap usage.
-static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
- int usage = static_cast<int>(Heap::SizeOfObjects());
+static MaybeObject* Runtime_GetHeapUsage(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
if (!Smi::IsValid(usage)) {
- return *Factory::NewNumberFromInt(usage);
+ return *isolate->factory()->NewNumberFromInt(usage);
}
return Smi::FromInt(usage);
}
// Captures a live object list from the present heap.
-static MaybeObject* Runtime_HasLOLEnabled(Arguments args) {
+static MaybeObject* Runtime_HasLOLEnabled(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
- return Heap::true_value();
+ return isolate->heap()->true_value();
#else
- return Heap::false_value();
+ return isolate->heap()->false_value();
#endif
}
// Captures a live object list from the present heap.
-static MaybeObject* Runtime_CaptureLOL(Arguments args) {
+static MaybeObject* Runtime_CaptureLOL(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
return LiveObjectList::Capture();
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
// Deletes the specified live object list.
-static MaybeObject* Runtime_DeleteLOL(Arguments args) {
+static MaybeObject* Runtime_DeleteLOL(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
CONVERT_SMI_CHECKED(id, args[0]);
bool success = LiveObjectList::Delete(id);
- return success ? Heap::true_value() : Heap::false_value();
+ return success ? isolate->heap()->true_value() :
+ isolate->heap()->false_value();
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
@@ -11016,7 +11587,8 @@ static MaybeObject* Runtime_DeleteLOL(Arguments args) {
// specified by id1 and id2.
// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
// dumped.
-static MaybeObject* Runtime_DumpLOL(Arguments args) {
+static MaybeObject* Runtime_DumpLOL(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
CONVERT_SMI_CHECKED(id1, args[0]);
@@ -11027,40 +11599,43 @@ static MaybeObject* Runtime_DumpLOL(Arguments args) {
EnterDebugger enter_debugger;
return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
// Gets the specified object as requested by the debugger.
// This is only used for obj ids shown in live object lists.
-static MaybeObject* Runtime_GetLOLObj(Arguments args) {
+static MaybeObject* Runtime_GetLOLObj(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
CONVERT_SMI_CHECKED(obj_id, args[0]);
Object* result = LiveObjectList::GetObj(obj_id);
return result;
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
// Gets the obj id for the specified address if valid.
// This is only used for obj ids shown in live object lists.
-static MaybeObject* Runtime_GetLOLObjId(Arguments args) {
+static MaybeObject* Runtime_GetLOLObjId(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
CONVERT_ARG_CHECKED(String, address, 0);
Object* result = LiveObjectList::GetObjId(address);
return result;
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
// Gets the retainers that references the specified object alive.
-static MaybeObject* Runtime_GetLOLObjRetainers(Arguments args) {
+static MaybeObject* Runtime_GetLOLObjRetainers(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
CONVERT_SMI_CHECKED(obj_id, args[0]);
@@ -11094,13 +11669,14 @@ static MaybeObject* Runtime_GetLOLObjRetainers(Arguments args) {
limit,
filter_obj);
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
// Gets the reference path between 2 objects.
-static MaybeObject* Runtime_GetLOLPath(Arguments args) {
+static MaybeObject* Runtime_GetLOLPath(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
CONVERT_SMI_CHECKED(obj_id1, args[0]);
@@ -11116,45 +11692,48 @@ static MaybeObject* Runtime_GetLOLPath(Arguments args) {
LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
return result;
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
// Generates the response to a debugger request for a list of all
// previously captured live object lists.
-static MaybeObject* Runtime_InfoLOL(Arguments args) {
+static MaybeObject* Runtime_InfoLOL(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
CONVERT_SMI_CHECKED(start, args[0]);
CONVERT_SMI_CHECKED(count, args[1]);
return LiveObjectList::Info(start, count);
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
// Gets a dump of the specified object as requested by the debugger.
// This is only used for obj ids shown in live object lists.
-static MaybeObject* Runtime_PrintLOLObj(Arguments args) {
+static MaybeObject* Runtime_PrintLOLObj(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
CONVERT_SMI_CHECKED(obj_id, args[0]);
Object* result = LiveObjectList::PrintObj(obj_id);
return result;
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
// Resets and releases all previously captured live object lists.
-static MaybeObject* Runtime_ResetLOL(Arguments args) {
+static MaybeObject* Runtime_ResetLOL(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
LiveObjectList::Reset();
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
@@ -11164,7 +11743,8 @@ static MaybeObject* Runtime_ResetLOL(Arguments args) {
// specified by id1 and id2.
// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
// summarized.
-static MaybeObject* Runtime_SummarizeLOL(Arguments args) {
+static MaybeObject* Runtime_SummarizeLOL(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
#ifdef LIVE_OBJECT_LIST
HandleScope scope;
CONVERT_SMI_CHECKED(id1, args[0]);
@@ -11174,7 +11754,7 @@ static MaybeObject* Runtime_SummarizeLOL(Arguments args) {
EnterDebugger enter_debugger;
return LiveObjectList::Summarize(id1, id2, filter_obj);
#else
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
#endif
}
@@ -11182,25 +11762,27 @@ static MaybeObject* Runtime_SummarizeLOL(Arguments args) {
#ifdef ENABLE_LOGGING_AND_PROFILING
-static MaybeObject* Runtime_ProfilerResume(Arguments args) {
+static MaybeObject* Runtime_ProfilerResume(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(Smi, smi_modules, args[0]);
CONVERT_CHECKED(Smi, smi_tag, args[1]);
v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_ProfilerPause(Arguments args) {
+static MaybeObject* Runtime_ProfilerPause(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(Smi, smi_modules, args[0]);
CONVERT_CHECKED(Smi, smi_tag, args[1]);
v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
- return Heap::undefined_value();
+ return isolate->heap()->undefined_value();
}
#endif // ENABLE_LOGGING_AND_PROFILING
@@ -11230,7 +11812,7 @@ static Handle<Object> Runtime_GetScriptFromScriptName(
}
// If no script with the requested script data is found return undefined.
- if (script.is_null()) return Factory::undefined_value();
+ if (script.is_null()) return FACTORY->undefined_value();
// Return the script found.
return GetScriptWrapper(script);
@@ -11240,8 +11822,9 @@ static Handle<Object> Runtime_GetScriptFromScriptName(
// Get the script object from script data. NOTE: Regarding performance
// see the NOTE for GetScriptFromScriptData.
// args[0]: script data for the script to find the source for
-static MaybeObject* Runtime_GetScript(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_GetScript(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
@@ -11285,17 +11868,19 @@ static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
// Collect the raw data for a stack trace. Returns an array of 4
// element segments each containing a receiver, function, code and
// native code offset.
-static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
+static MaybeObject* Runtime_CollectStackTrace(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT_EQ(args.length(), 2);
Handle<Object> caller = args.at<Object>(0);
CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
- HandleScope scope;
+ HandleScope scope(isolate);
+ Factory* factory = isolate->factory();
limit = Max(limit, 0); // Ensure that limit is not negative.
int initial_size = Min(limit, 10);
Handle<FixedArray> elements =
- Factory::NewFixedArrayWithHoles(initial_size * 4);
+ factory->NewFixedArrayWithHoles(initial_size * 4);
StackFrameIterator iter;
// If the caller parameter is a function we skip frames until we're
@@ -11314,7 +11899,7 @@ static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
if (cursor + 4 > elements->length()) {
int new_capacity = JSObject::NewElementsCapacity(elements->length());
Handle<FixedArray> new_elements =
- Factory::NewFixedArrayWithHoles(new_capacity);
+ factory->NewFixedArrayWithHoles(new_capacity);
for (int i = 0; i < cursor; i++) {
new_elements->set(i, elements->get(i));
}
@@ -11334,36 +11919,40 @@ static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
}
iter.Advance();
}
- Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
+ Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
result->set_length(Smi::FromInt(cursor));
return *result;
}
// Returns V8 version as a string.
-static MaybeObject* Runtime_GetV8Version(Arguments args) {
+static MaybeObject* Runtime_GetV8Version(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT_EQ(args.length(), 0);
NoHandleAllocation ha;
const char* version_string = v8::V8::GetVersion();
- return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
+ return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
+ NOT_TENURED);
}
-static MaybeObject* Runtime_Abort(Arguments args) {
+static MaybeObject* Runtime_Abort(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
Smi::cast(args[1])->value());
- Top::PrintStack();
+ isolate->PrintStack();
OS::Abort();
UNREACHABLE();
return NULL;
}
-static MaybeObject* Runtime_GetFromCache(Arguments args) {
+static MaybeObject* Runtime_GetFromCache(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
// This is only called from codegen, so checks might be more lax.
CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
Object* key = args[1];
@@ -11397,7 +11986,7 @@ static MaybeObject* Runtime_GetFromCache(Arguments args) {
}
// There is no value in the cache. Invoke the function and cache result.
- HandleScope scope;
+ HandleScope scope(isolate);
Handle<JSFunctionResultCache> cache_handle(cache);
Handle<Object> key_handle(key);
@@ -11406,7 +11995,7 @@ static MaybeObject* Runtime_GetFromCache(Arguments args) {
Handle<JSFunction> factory(JSFunction::cast(
cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
// TODO(antonm): consider passing a receiver when constructing a cache.
- Handle<Object> receiver(Top::global_context()->global());
+ Handle<Object> receiver(isolate->global_context()->global());
// This handle is nor shared, nor used later, so it's safe.
Object** argv[] = { key_handle.location() };
bool pending_exception = false;
@@ -11455,39 +12044,46 @@ static MaybeObject* Runtime_GetFromCache(Arguments args) {
}
-static MaybeObject* Runtime_NewMessageObject(Arguments args) {
- HandleScope scope;
+static MaybeObject* Runtime_NewMessageObject(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
+ HandleScope scope(isolate);
CONVERT_ARG_CHECKED(String, type, 0);
CONVERT_ARG_CHECKED(JSArray, arguments, 1);
- return *Factory::NewJSMessageObject(type,
- arguments,
- 0,
- 0,
- Factory::undefined_value(),
- Factory::undefined_value(),
- Factory::undefined_value());
+ return *isolate->factory()->NewJSMessageObject(
+ type,
+ arguments,
+ 0,
+ 0,
+ isolate->factory()->undefined_value(),
+ isolate->factory()->undefined_value(),
+ isolate->factory()->undefined_value());
}
-static MaybeObject* Runtime_MessageGetType(Arguments args) {
+static MaybeObject* Runtime_MessageGetType(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
CONVERT_CHECKED(JSMessageObject, message, args[0]);
return message->type();
}
-static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
+static MaybeObject* Runtime_MessageGetArguments(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
CONVERT_CHECKED(JSMessageObject, message, args[0]);
return message->arguments();
}
-static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
+static MaybeObject* Runtime_MessageGetStartPosition(
+ RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
CONVERT_CHECKED(JSMessageObject, message, args[0]);
return Smi::FromInt(message->start_position());
}
-static MaybeObject* Runtime_MessageGetScript(Arguments args) {
+static MaybeObject* Runtime_MessageGetScript(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
CONVERT_CHECKED(JSMessageObject, message, args[0]);
return message->script();
}
@@ -11496,7 +12092,8 @@ static MaybeObject* Runtime_MessageGetScript(Arguments args) {
#ifdef DEBUG
// ListNatives is ONLY used by the fuzz-natives.js in debug mode
// Exclude the code in release mode.
-static MaybeObject* Runtime_ListNatives(Arguments args) {
+static MaybeObject* Runtime_ListNatives(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 0);
HandleScope scope;
#define COUNT_ENTRY(Name, argc, ressize) + 1
@@ -11505,7 +12102,8 @@ static MaybeObject* Runtime_ListNatives(Arguments args) {
INLINE_FUNCTION_LIST(COUNT_ENTRY)
INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
#undef COUNT_ENTRY
- Handle<FixedArray> elements = Factory::NewFixedArray(entry_count);
+ Factory* factory = isolate->factory();
+ Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
int index = 0;
bool inline_runtime_functions = false;
#define ADD_ENTRY(Name, argc, ressize) \
@@ -11514,16 +12112,16 @@ static MaybeObject* Runtime_ListNatives(Arguments args) {
Handle<String> name; \
/* Inline runtime functions have an underscore in front of the name. */ \
if (inline_runtime_functions) { \
- name = Factory::NewStringFromAscii( \
+ name = factory->NewStringFromAscii( \
Vector<const char>("_" #Name, StrLength("_" #Name))); \
} else { \
- name = Factory::NewStringFromAscii( \
+ name = factory->NewStringFromAscii( \
Vector<const char>(#Name, StrLength(#Name))); \
} \
- Handle<FixedArray> pair_elements = Factory::NewFixedArray(2); \
+ Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
pair_elements->set(0, *name); \
pair_elements->set(1, Smi::FromInt(argc)); \
- Handle<JSArray> pair = Factory::NewJSArrayWithElements(pair_elements); \
+ Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
elements->set(index++, *pair); \
}
inline_runtime_functions = false;
@@ -11533,23 +12131,24 @@ static MaybeObject* Runtime_ListNatives(Arguments args) {
INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
#undef ADD_ENTRY
ASSERT_EQ(index, entry_count);
- Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
+ Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
return *result;
}
#endif
-static MaybeObject* Runtime_Log(Arguments args) {
+static MaybeObject* Runtime_Log(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 2);
CONVERT_CHECKED(String, format, args[0]);
CONVERT_CHECKED(JSArray, elms, args[1]);
Vector<const char> chars = format->ToAsciiVector();
- Logger::LogRuntime(chars, elms);
- return Heap::undefined_value();
+ LOGGER->LogRuntime(chars, elms);
+ return isolate->heap()->undefined_value();
}
-static MaybeObject* Runtime_IS_VAR(Arguments args) {
+static MaybeObject* Runtime_IS_VAR(RUNTIME_CALLING_CONVENTION) {
UNREACHABLE(); // implemented as macro in the parser
return NULL;
}
@@ -11567,20 +12166,22 @@ static MaybeObject* Runtime_IS_VAR(Arguments args) {
{ Runtime::kInline##name, Runtime::INLINE, \
"_" #name, NULL, number_of_args, result_size },
-Runtime::Function kIntrinsicFunctions[] = {
+static const Runtime::Function kIntrinsicFunctions[] = {
RUNTIME_FUNCTION_LIST(F)
INLINE_FUNCTION_LIST(I)
INLINE_RUNTIME_FUNCTION_LIST(I)
};
-MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
+MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
+ Object* dictionary) {
+ ASSERT(Isolate::Current()->heap() == heap);
ASSERT(dictionary != NULL);
ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
for (int i = 0; i < kNumFunctions; ++i) {
Object* name_symbol;
{ MaybeObject* maybe_name_symbol =
- Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
+ heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
}
StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
@@ -11599,10 +12200,11 @@ MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
}
-Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
- int entry = Heap::intrinsic_function_names()->FindEntry(*name);
+const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
+ Heap* heap = name->GetHeap();
+ int entry = heap->intrinsic_function_names()->FindEntry(*name);
if (entry != kNotFound) {
- Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
+ Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
int function_index = Smi::cast(smi_index)->value();
return &(kIntrinsicFunctions[function_index]);
}
@@ -11610,22 +12212,23 @@ Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
}
-Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
+const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
return &(kIntrinsicFunctions[static_cast<int>(id)]);
}
void Runtime::PerformGC(Object* result) {
+ Isolate* isolate = Isolate::Current();
Failure* failure = Failure::cast(result);
if (failure->IsRetryAfterGC()) {
// Try to do a garbage collection; ignore it if it fails. The C
// entry stub will throw an out-of-memory exception in that case.
- Heap::CollectGarbage(failure->allocation_space());
+ isolate->heap()->CollectGarbage(failure->allocation_space());
} else {
// Handle last resort GC and make sure to allow future allocations
// to grow the heap without causing GCs (if possible).
- Counters::gc_last_resort_from_js.Increment();
- Heap::CollectAllGarbage(false);
+ isolate->counters()->gc_last_resort_from_js()->Increment();
+ isolate->heap()->CollectAllGarbage(false);
}
}
diff --git a/src/runtime.h b/src/runtime.h
index 8e73d5c4..58062ca4 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -28,6 +28,8 @@
#ifndef V8_RUNTIME_H_
#define V8_RUNTIME_H_
+#include "zone.h"
+
namespace v8 {
namespace internal {
@@ -412,7 +414,6 @@ namespace internal {
#define RUNTIME_FUNCTION_LIST_DEBUG(F)
#endif
-
// ----------------------------------------------------------------------------
// RUNTIME_FUNCTION_LIST defines all runtime functions accessed
// either directly by id (via the code generator), or indirectly
@@ -482,6 +483,57 @@ namespace internal {
//---------------------------------------------------------------------------
// Runtime provides access to all C++ runtime functions.
+class RuntimeState {
+ public:
+
+ StaticResource<StringInputBuffer>* string_input_buffer() {
+ return &string_input_buffer_;
+ }
+ unibrow::Mapping<unibrow::ToUppercase, 128>* to_upper_mapping() {
+ return &to_upper_mapping_;
+ }
+ unibrow::Mapping<unibrow::ToLowercase, 128>* to_lower_mapping() {
+ return &to_lower_mapping_;
+ }
+ StringInputBuffer* string_input_buffer_compare_bufx() {
+ return &string_input_buffer_compare_bufx_;
+ }
+ StringInputBuffer* string_input_buffer_compare_bufy() {
+ return &string_input_buffer_compare_bufy_;
+ }
+ StringInputBuffer* string_locale_compare_buf1() {
+ return &string_locale_compare_buf1_;
+ }
+ StringInputBuffer* string_locale_compare_buf2() {
+ return &string_locale_compare_buf2_;
+ }
+ int* smi_lexicographic_compare_x_elms() {
+ return smi_lexicographic_compare_x_elms_;
+ }
+ int* smi_lexicographic_compare_y_elms() {
+ return smi_lexicographic_compare_y_elms_;
+ }
+
+ private:
+ RuntimeState() {}
+ // Non-reentrant string buffer for efficient general use in the runtime.
+ StaticResource<StringInputBuffer> string_input_buffer_;
+ unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping_;
+ unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping_;
+ StringInputBuffer string_input_buffer_compare_bufx_;
+ StringInputBuffer string_input_buffer_compare_bufy_;
+ StringInputBuffer string_locale_compare_buf1_;
+ StringInputBuffer string_locale_compare_buf2_;
+ int smi_lexicographic_compare_x_elms_[10];
+ int smi_lexicographic_compare_y_elms_[10];
+
+ friend class Isolate;
+ friend class Runtime;
+
+ DISALLOW_COPY_AND_ASSIGN(RuntimeState);
+};
+
+
class Runtime : public AllStatic {
public:
enum FunctionId {
@@ -525,30 +577,35 @@ class Runtime : public AllStatic {
// retried with a new, empty StringDictionary, not with the same one.
// Alternatively, heap initialization can be completely restarted.
MUST_USE_RESULT static MaybeObject* InitializeIntrinsicFunctionNames(
- Object* dictionary);
+ Heap* heap, Object* dictionary);
// Get the intrinsic function with the given name, which must be a symbol.
- static Function* FunctionForSymbol(Handle<String> name);
+ static const Function* FunctionForSymbol(Handle<String> name);
// Get the intrinsic function with the given FunctionId.
- static Function* FunctionForId(FunctionId id);
+ static const Function* FunctionForId(FunctionId id);
// General-purpose helper functions for runtime system.
- static int StringMatch(Handle<String> sub, Handle<String> pat, int index);
+ static int StringMatch(Isolate* isolate,
+ Handle<String> sub,
+ Handle<String> pat,
+ int index);
- static bool IsUpperCaseChar(uint16_t ch);
+ static bool IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch);
// TODO(1240886): The following three methods are *not* handle safe,
// but accept handle arguments. This seems fragile.
// Support getting the characters in a string using [] notation as
// in Firefox/SpiderMonkey, Safari and Opera.
- MUST_USE_RESULT static MaybeObject* GetElementOrCharAt(Handle<Object> object,
+ MUST_USE_RESULT static MaybeObject* GetElementOrCharAt(Isolate* isolate,
+ Handle<Object> object,
uint32_t index);
MUST_USE_RESULT static MaybeObject* GetElement(Handle<Object> object,
uint32_t index);
MUST_USE_RESULT static MaybeObject* SetObjectProperty(
+ Isolate* isolate,
Handle<Object> object,
Handle<Object> key,
Handle<Object> value,
@@ -556,27 +613,31 @@ class Runtime : public AllStatic {
StrictModeFlag strict_mode);
MUST_USE_RESULT static MaybeObject* ForceSetObjectProperty(
+ Isolate* isolate,
Handle<JSObject> object,
Handle<Object> key,
Handle<Object> value,
PropertyAttributes attr);
MUST_USE_RESULT static MaybeObject* ForceDeleteObjectProperty(
+ Isolate* isolate,
Handle<JSObject> object,
Handle<Object> key);
- MUST_USE_RESULT static MaybeObject* GetObjectProperty(Handle<Object> object,
- Handle<Object> key);
+ MUST_USE_RESULT static MaybeObject* GetObjectProperty(
+ Isolate* isolate,
+ Handle<Object> object,
+ Handle<Object> key);
// This function is used in FunctionNameUsing* tests.
- static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
+ static Object* FindSharedFunctionInfoInScript(Isolate* isolate,
+ Handle<Script> script,
int position);
// Helper functions used stubs.
static void PerformGC(Object* result);
};
-
} } // namespace v8::internal
#endif // V8_RUNTIME_H_
diff --git a/src/safepoint-table.cc b/src/safepoint-table.cc
index d2ec54c3..28cf6e64 100644
--- a/src/safepoint-table.cc
+++ b/src/safepoint-table.cc
@@ -25,11 +25,14 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "v8.h"
+
#include "safepoint-table.h"
#include "deoptimizer.h"
#include "disasm.h"
#include "macro-assembler.h"
+#include "zone-inl.h"
namespace v8 {
namespace internal {
diff --git a/src/safepoint-table.h b/src/safepoint-table.h
index 8803d06f..084a0b4f 100644
--- a/src/safepoint-table.h
+++ b/src/safepoint-table.h
@@ -28,11 +28,9 @@
#ifndef V8_SAFEPOINT_TABLE_H_
#define V8_SAFEPOINT_TABLE_H_
-#include "v8.h"
-
#include "heap.h"
+#include "v8memory.h"
#include "zone.h"
-#include "zone-inl.h"
namespace v8 {
namespace internal {
@@ -228,6 +226,14 @@ class SafepointTableBuilder BASE_EMBEDDED {
deoptimization_info_[index].pc_after_gap = pc;
}
+ // Get the end pc offset of the last safepoint, including the code generated
+ // until the end of the gap following it.
+ unsigned GetPcAfterGap() {
+ int index = deoptimization_info_.length();
+ if (index == 0) return 0;
+ return deoptimization_info_[index - 1].pc_after_gap;
+ }
+
// Emit the safepoint table after the body. The number of bits per
// entry must be enough to hold all the pointer indexes.
void Emit(Assembler* assembler, int bits_per_entry);
diff --git a/src/scanner-base.cc b/src/scanner-base.cc
index 80bca4e2..2066b5a1 100644
--- a/src/scanner-base.cc
+++ b/src/scanner-base.cc
@@ -35,16 +35,6 @@ namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
-// Character predicates
-
-unibrow::Predicate<IdentifierStart, 128> ScannerConstants::kIsIdentifierStart;
-unibrow::Predicate<IdentifierPart, 128> ScannerConstants::kIsIdentifierPart;
-unibrow::Predicate<unibrow::WhiteSpace, 128> ScannerConstants::kIsWhiteSpace;
-unibrow::Predicate<unibrow::LineTerminator, 128>
- ScannerConstants::kIsLineTerminator;
-
-StaticResource<ScannerConstants::Utf8Decoder> ScannerConstants::utf8_decoder_;
-
// Compound predicates.
bool ScannerConstants::IsIdentifier(unibrow::CharacterStream* buffer) {
@@ -64,8 +54,10 @@ bool ScannerConstants::IsIdentifier(unibrow::CharacterStream* buffer) {
// ----------------------------------------------------------------------------
// Scanner
-Scanner::Scanner()
- : octal_pos_(kNoOctalLocation) { }
+Scanner::Scanner(ScannerConstants* scanner_constants)
+ : scanner_constants_(scanner_constants),
+ octal_pos_(kNoOctalLocation) {
+}
uc32 Scanner::ScanHexEscape(uc32 c, int length) {
@@ -122,7 +114,8 @@ uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
// ----------------------------------------------------------------------------
// JavaScriptScanner
-JavaScriptScanner::JavaScriptScanner() : Scanner() {}
+JavaScriptScanner::JavaScriptScanner(ScannerConstants* scanner_contants)
+ : Scanner(scanner_contants) { }
Token::Value JavaScriptScanner::Next() {
@@ -151,9 +144,9 @@ bool JavaScriptScanner::SkipWhiteSpace() {
while (true) {
// We treat byte-order marks (BOMs) as whitespace for better
// compatibility with Spidermonkey and other JavaScript engines.
- while (ScannerConstants::kIsWhiteSpace.get(c0_) || IsByteOrderMark(c0_)) {
+ while (scanner_constants_->IsWhiteSpace(c0_) || IsByteOrderMark(c0_)) {
// IsWhiteSpace() includes line terminators!
- if (ScannerConstants::kIsLineTerminator.get(c0_)) {
+ if (scanner_constants_->IsLineTerminator(c0_)) {
// Ignore line terminators, but remember them. This is necessary
// for automatic semicolon insertion.
has_line_terminator_before_next_ = true;
@@ -193,7 +186,7 @@ Token::Value JavaScriptScanner::SkipSingleLineComment() {
// separately by the lexical grammar and becomes part of the
// stream of input elements for the syntactic grammar (see
// ECMA-262, section 7.4, page 12).
- while (c0_ >= 0 && !ScannerConstants::kIsLineTerminator.get(c0_)) {
+ while (c0_ >= 0 && !scanner_constants_->IsLineTerminator(c0_)) {
Advance();
}
@@ -458,7 +451,7 @@ void JavaScriptScanner::Scan() {
break;
default:
- if (ScannerConstants::kIsIdentifierStart.get(c0_)) {
+ if (scanner_constants_->IsIdentifierStart(c0_)) {
token = ScanIdentifierOrKeyword();
} else if (IsDecimalDigit(c0_)) {
token = ScanNumber(false);
@@ -506,7 +499,7 @@ void JavaScriptScanner::ScanEscape() {
Advance();
// Skip escaped newlines.
- if (ScannerConstants::kIsLineTerminator.get(c)) {
+ if (scanner_constants_->IsLineTerminator(c)) {
// Allow CR+LF newlines in multiline string literals.
if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
// Allow LF+CR newlines in multiline string literals.
@@ -549,7 +542,7 @@ Token::Value JavaScriptScanner::ScanString() {
LiteralScope literal(this);
while (c0_ != quote && c0_ >= 0
- && !ScannerConstants::kIsLineTerminator.get(c0_)) {
+ && !scanner_constants_->IsLineTerminator(c0_)) {
uc32 c = c0_;
Advance();
if (c == '\\') {
@@ -648,7 +641,7 @@ Token::Value JavaScriptScanner::ScanNumber(bool seen_period) {
// not be an identifier start or a decimal digit; see ECMA-262
// section 7.8.3, page 17 (note that we read only one decimal digit
// if the value is 0).
- if (IsDecimalDigit(c0_) || ScannerConstants::kIsIdentifierStart.get(c0_))
+ if (IsDecimalDigit(c0_) || scanner_constants_->IsIdentifierStart(c0_))
return Token::ILLEGAL;
literal.Complete();
@@ -670,14 +663,14 @@ uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() {
Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
- ASSERT(ScannerConstants::kIsIdentifierStart.get(c0_));
+ ASSERT(scanner_constants_->IsIdentifierStart(c0_));
LiteralScope literal(this);
KeywordMatcher keyword_match;
// Scan identifier start character.
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier start characters.
- if (!ScannerConstants::kIsIdentifierStart.get(c)) return Token::ILLEGAL;
+ if (!scanner_constants_->IsIdentifierStart(c)) return Token::ILLEGAL;
AddLiteralChar(c);
return ScanIdentifierSuffix(&literal);
}
@@ -690,7 +683,7 @@ Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
}
// Scan the rest of the identifier characters.
- while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
+ while (scanner_constants_->IsIdentifierPart(c0_)) {
if (c0_ != '\\') {
uc32 next_char = c0_;
Advance();
@@ -708,11 +701,11 @@ Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
Token::Value JavaScriptScanner::ScanIdentifierSuffix(LiteralScope* literal) {
// Scan the rest of the identifier characters.
- while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
+ while (scanner_constants_->IsIdentifierPart(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier part characters.
- if (!ScannerConstants::kIsIdentifierPart.get(c)) return Token::ILLEGAL;
+ if (!scanner_constants_->IsIdentifierPart(c)) return Token::ILLEGAL;
AddLiteralChar(c);
} else {
AddLiteralChar(c0_);
@@ -742,10 +735,10 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
AddLiteralChar('=');
while (c0_ != '/' || in_character_class) {
- if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
+ if (scanner_constants_->IsLineTerminator(c0_) || c0_ < 0) return false;
if (c0_ == '\\') { // Escape sequence.
AddLiteralCharAdvance();
- if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
+ if (scanner_constants_->IsLineTerminator(c0_) || c0_ < 0) return false;
AddLiteralCharAdvance();
// If the escape allows more characters, i.e., \x??, \u????, or \c?,
// only "safe" characters are allowed (letters, digits, underscore),
@@ -771,7 +764,7 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
bool JavaScriptScanner::ScanRegExpFlags() {
// Scan regular expression flags.
LiteralScope literal(this);
- while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
+ while (scanner_constants_->IsIdentifierPart(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
if (c != static_cast<uc32>(unibrow::Utf8::kBadChar)) {
diff --git a/src/scanner-base.h b/src/scanner-base.h
index f5fe7f7c..552f3873 100644
--- a/src/scanner-base.h
+++ b/src/scanner-base.h
@@ -119,26 +119,33 @@ class UC16CharacterStream {
};
+class ScannerConstants {
// ---------------------------------------------------------------------
// Constants used by scanners.
-
-class ScannerConstants : AllStatic {
public:
+ ScannerConstants() {}
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
- static StaticResource<Utf8Decoder>* utf8_decoder() {
+ StaticResource<Utf8Decoder>* utf8_decoder() {
return &utf8_decoder_;
}
- static unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
- static unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
- static unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
- static unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
+ bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); }
+ bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); }
+ bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); }
+ bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); }
- static bool IsIdentifier(unibrow::CharacterStream* buffer);
+ bool IsIdentifier(unibrow::CharacterStream* buffer);
private:
- static StaticResource<Utf8Decoder> utf8_decoder_;
+
+ unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
+ unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
+ unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
+ unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
+ StaticResource<Utf8Decoder> utf8_decoder_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScannerConstants);
};
// ----------------------------------------------------------------------------
@@ -238,6 +245,8 @@ class LiteralBuffer {
bool is_ascii_;
int position_;
Vector<byte> backing_store_;
+
+ DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
};
@@ -263,7 +272,7 @@ class Scanner {
bool complete_;
};
- Scanner();
+ explicit Scanner(ScannerConstants* scanner_contants);
// Returns the current token again.
Token::Value current_token() { return current_.token; }
@@ -418,6 +427,8 @@ class Scanner {
return source_->pos() - kCharacterLookaheadBufferSize;
}
+ ScannerConstants* scanner_constants_;
+
// Buffers collecting literal strings, numbers, etc.
LiteralBuffer literal_buffer1_;
LiteralBuffer literal_buffer2_;
@@ -462,7 +473,7 @@ class JavaScriptScanner : public Scanner {
bool complete_;
};
- JavaScriptScanner();
+ explicit JavaScriptScanner(ScannerConstants* scanner_contants);
// Returns the next token.
Token::Value Next();
diff --git a/src/scanner.cc b/src/scanner.cc
index d54d9f91..d9c2188c 100755
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -328,8 +328,6 @@ void Scanner::LiteralScope::Complete() {
// ----------------------------------------------------------------------------
// V8JavaScriptScanner
-V8JavaScriptScanner::V8JavaScriptScanner() : JavaScriptScanner() { }
-
void V8JavaScriptScanner::Initialize(UC16CharacterStream* source) {
source_ = source;
@@ -347,7 +345,8 @@ void V8JavaScriptScanner::Initialize(UC16CharacterStream* source) {
// ----------------------------------------------------------------------------
// JsonScanner
-JsonScanner::JsonScanner() : Scanner() { }
+JsonScanner::JsonScanner(ScannerConstants* scanner_constants)
+ : Scanner(scanner_constants) { }
void JsonScanner::Initialize(UC16CharacterStream* source) {
@@ -576,11 +575,10 @@ Token::Value JsonScanner::ScanJsonIdentifier(const char* text,
Advance();
text++;
}
- if (ScannerConstants::kIsIdentifierPart.get(c0_)) return Token::ILLEGAL;
+ if (scanner_constants_->IsIdentifierPart(c0_)) return Token::ILLEGAL;
literal.Complete();
return token;
}
-
} } // namespace v8::internal
diff --git a/src/scanner.h b/src/scanner.h
index cf2084f5..776ba535 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -134,14 +134,16 @@ class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream {
class V8JavaScriptScanner : public JavaScriptScanner {
public:
- V8JavaScriptScanner();
+ explicit V8JavaScriptScanner(ScannerConstants* scanner_constants)
+ : JavaScriptScanner(scanner_constants) {}
+
void Initialize(UC16CharacterStream* source);
};
class JsonScanner : public Scanner {
public:
- JsonScanner();
+ explicit JsonScanner(ScannerConstants* scanner_constants);
void Initialize(UC16CharacterStream* source);
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index e06235af..58e2ad28 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -50,7 +50,7 @@ static int CompareLocal(Variable* const* v, Variable* const* w) {
template<class Allocator>
ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
- : function_name_(Factory::empty_symbol()),
+ : function_name_(FACTORY->empty_symbol()),
calls_eval_(scope->calls_eval()),
parameters_(scope->num_parameters()),
stack_slots_(scope->num_stack_slots()),
@@ -141,7 +141,7 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
context_slots_.length());
ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length());
- context_slots_.Add(Factory::empty_symbol());
+ context_slots_.Add(FACTORY->empty_symbol());
context_modes_.Add(Variable::INTERNAL);
}
}
@@ -238,7 +238,7 @@ static Object** ReadList(Object** p,
template<class Allocator>
ScopeInfo<Allocator>::ScopeInfo(SerializedScopeInfo* data)
- : function_name_(Factory::empty_symbol()),
+ : function_name_(FACTORY->empty_symbol()),
parameters_(4),
stack_slots_(8),
context_slots_(8),
@@ -309,7 +309,7 @@ Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
stack_slots_.length();
Handle<SerializedScopeInfo> data(
- SerializedScopeInfo::cast(*Factory::NewFixedArray(length, TENURED)));
+ SerializedScopeInfo::cast(*FACTORY->NewFixedArray(length, TENURED)));
AssertNoAllocation nogc;
Object** p0 = data->data_start();
@@ -357,7 +357,7 @@ Handle<SerializedScopeInfo> SerializedScopeInfo::Create(Scope* scope) {
SerializedScopeInfo* SerializedScopeInfo::Empty() {
- return reinterpret_cast<SerializedScopeInfo*>(Heap::empty_fixed_array());
+ return reinterpret_cast<SerializedScopeInfo*>(HEAP->empty_fixed_array());
}
@@ -448,7 +448,8 @@ int SerializedScopeInfo::StackSlotIndex(String* name) {
int SerializedScopeInfo::ContextSlotIndex(String* name, Variable::Mode* mode) {
ASSERT(name->IsSymbol());
- int result = ContextSlotCache::Lookup(this, name, mode);
+ Isolate* isolate = GetIsolate();
+ int result = isolate->context_slot_cache()->Lookup(this, name, mode);
if (result != ContextSlotCache::kNotFound) return result;
if (length() > 0) {
// Slots start after length entry.
@@ -465,13 +466,13 @@ int SerializedScopeInfo::ContextSlotIndex(String* name, Variable::Mode* mode) {
Variable::Mode mode_value = static_cast<Variable::Mode>(v);
if (mode != NULL) *mode = mode_value;
result = static_cast<int>((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS;
- ContextSlotCache::Update(this, name, mode_value, result);
+ isolate->context_slot_cache()->Update(this, name, mode_value, result);
return result;
}
p += 2;
}
}
- ContextSlotCache::Update(this, name, Variable::INTERNAL, -1);
+ isolate->context_slot_cache()->Update(this, name, Variable::INTERNAL, -1);
return -1;
}
@@ -547,7 +548,7 @@ void ContextSlotCache::Update(Object* data,
int slot_index) {
String* symbol;
ASSERT(slot_index > kNotFound);
- if (Heap::LookupSymbolIfExists(name, &symbol)) {
+ if (HEAP->LookupSymbolIfExists(name, &symbol)) {
int index = Hash(data, symbol);
Key& key = keys_[index];
key.data = data;
@@ -566,12 +567,6 @@ void ContextSlotCache::Clear() {
}
-ContextSlotCache::Key ContextSlotCache::keys_[ContextSlotCache::kLength];
-
-
-uint32_t ContextSlotCache::values_[ContextSlotCache::kLength];
-
-
#ifdef DEBUG
void ContextSlotCache::ValidateEntry(Object* data,
@@ -579,7 +574,7 @@ void ContextSlotCache::ValidateEntry(Object* data,
Variable::Mode mode,
int slot_index) {
String* symbol;
- if (Heap::LookupSymbolIfExists(name, &symbol)) {
+ if (HEAP->LookupSymbolIfExists(name, &symbol)) {
int index = Hash(data, name);
Key& key = keys_[index];
ASSERT(key.data == data);
diff --git a/src/scopeinfo.h b/src/scopeinfo.h
index dd49a4e0..cc9f8165 100644
--- a/src/scopeinfo.h
+++ b/src/scopeinfo.h
@@ -114,7 +114,7 @@ class SerializedScopeInfo : public FixedArray {
// Does this scope have an arguments shadow?
bool HasArgumentsShadow() {
- return StackSlotIndex(Heap::arguments_shadow_symbol()) >= 0;
+ return StackSlotIndex(GetHeap()->arguments_shadow_symbol()) >= 0;
}
// Return the number of stack slots for code.
@@ -173,28 +173,36 @@ class ContextSlotCache {
public:
// Lookup context slot index for (data, name).
// If absent, kNotFound is returned.
- static int Lookup(Object* data,
- String* name,
- Variable::Mode* mode);
+ int Lookup(Object* data,
+ String* name,
+ Variable::Mode* mode);
// Update an element in the cache.
- static void Update(Object* data,
- String* name,
- Variable::Mode mode,
- int slot_index);
+ void Update(Object* data,
+ String* name,
+ Variable::Mode mode,
+ int slot_index);
// Clear the cache.
- static void Clear();
+ void Clear();
static const int kNotFound = -2;
private:
+ ContextSlotCache() {
+ for (int i = 0; i < kLength; ++i) {
+ keys_[i].data = NULL;
+ keys_[i].name = NULL;
+ values_[i] = kNotFound;
+ }
+ }
+
inline static int Hash(Object* data, String* name);
#ifdef DEBUG
- static void ValidateEntry(Object* data,
- String* name,
- Variable::Mode mode,
- int slot_index);
+ void ValidateEntry(Object* data,
+ String* name,
+ Variable::Mode mode,
+ int slot_index);
#endif
static const int kLength = 256;
@@ -228,8 +236,11 @@ class ContextSlotCache {
uint32_t value_;
};
- static Key keys_[kLength];
- static uint32_t values_[kLength];
+ Key keys_[kLength];
+ uint32_t values_[kLength];
+
+ friend class Isolate;
+ DISALLOW_COPY_AND_ASSIGN(ContextSlotCache);
};
diff --git a/src/scopes.cc b/src/scopes.cc
index fd573b03..f4bcaa8f 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -40,12 +40,14 @@ namespace internal {
// ----------------------------------------------------------------------------
// A Zone allocator for use with LocalsMap.
+// TODO(isolates): It is probably worth it to change the Allocator class to
+// take a pointer to an isolate.
class ZoneAllocator: public Allocator {
public:
/* nothing to do */
virtual ~ZoneAllocator() {}
- virtual void* New(size_t size) { return Zone::New(static_cast<int>(size)); }
+ virtual void* New(size_t size) { return ZONE->New(static_cast<int>(size)); }
/* ignored - Zone is freed in one fell swoop */
virtual void Delete(void* p) {}
@@ -148,26 +150,30 @@ Scope::Scope(Scope* inner_scope, SerializedScopeInfo* scope_info)
unresolved_(16),
decls_(4) {
ASSERT(scope_info != NULL);
- SetDefaults(FUNCTION_SCOPE, inner_scope->outer_scope(), scope_info);
+ SetDefaults(FUNCTION_SCOPE, NULL, scope_info);
ASSERT(resolved());
- InsertAfterScope(inner_scope);
if (scope_info->HasHeapAllocatedLocals()) {
num_heap_slots_ = scope_info_->NumberOfContextSlots();
}
+ AddInnerScope(inner_scope);
+
// This scope's arguments shadow (if present) is context-allocated if an inner
// scope accesses this one's parameters. Allocate the arguments_shadow_
// variable if necessary.
+ Isolate* isolate = Isolate::Current();
Variable::Mode mode;
int arguments_shadow_index =
- scope_info_->ContextSlotIndex(Heap::arguments_shadow_symbol(), &mode);
+ scope_info_->ContextSlotIndex(
+ isolate->heap()->arguments_shadow_symbol(), &mode);
if (arguments_shadow_index >= 0) {
ASSERT(mode == Variable::INTERNAL);
- arguments_shadow_ = new Variable(this,
- Factory::arguments_shadow_symbol(),
- Variable::INTERNAL,
- true,
- Variable::ARGUMENTS);
+ arguments_shadow_ = new Variable(
+ this,
+ isolate->factory()->arguments_shadow_symbol(),
+ Variable::INTERNAL,
+ true,
+ Variable::ARGUMENTS);
arguments_shadow_->set_rewrite(
new Slot(arguments_shadow_, Slot::CONTEXT, arguments_shadow_index));
arguments_shadow_->set_is_used(true);
@@ -175,34 +181,44 @@ Scope::Scope(Scope* inner_scope, SerializedScopeInfo* scope_info)
}
+Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
+ Scope* global_scope) {
+ ASSERT(!info->closure().is_null());
+ // If we have a serialized scope info, reuse it.
+ Scope* innermost_scope = NULL;
+ Scope* scope = NULL;
+
+ SerializedScopeInfo* scope_info = info->closure()->shared()->scope_info();
+ if (scope_info != SerializedScopeInfo::Empty()) {
+ JSFunction* current = *info->closure();
+ do {
+ current = current->context()->closure();
+ SerializedScopeInfo* scope_info = current->shared()->scope_info();
+ if (scope_info != SerializedScopeInfo::Empty()) {
+ scope = new Scope(scope, scope_info);
+ if (innermost_scope == NULL) innermost_scope = scope;
+ } else {
+ ASSERT(current->context()->IsGlobalContext());
+ }
+ } while (!current->context()->IsGlobalContext());
+ }
+
+ global_scope->AddInnerScope(scope);
+ if (innermost_scope == NULL) innermost_scope = global_scope;
+
+ return innermost_scope;
+}
+
bool Scope::Analyze(CompilationInfo* info) {
ASSERT(info->function() != NULL);
Scope* top = info->function()->scope();
- // If we have a serialized scope info, reuse it.
- if (!info->closure().is_null()) {
- SerializedScopeInfo* scope_info = info->closure()->shared()->scope_info();
- if (scope_info != SerializedScopeInfo::Empty()) {
- Scope* scope = top;
- JSFunction* current = *info->closure();
- do {
- current = current->context()->closure();
- SerializedScopeInfo* scope_info = current->shared()->scope_info();
- if (scope_info != SerializedScopeInfo::Empty()) {
- scope = new Scope(scope, scope_info);
- } else {
- ASSERT(current->context()->IsGlobalContext());
- }
- } while (!current->context()->IsGlobalContext());
- }
- }
-
while (top->outer_scope() != NULL) top = top->outer_scope();
top->AllocateVariables(info->calling_context());
#ifdef DEBUG
- if (Bootstrapper::IsActive()
+ if (info->isolate()->bootstrapper()->IsActive()
? FLAG_print_builtin_scopes
: FLAG_print_scopes) {
info->function()->scope()->Print();
@@ -234,7 +250,7 @@ void Scope::Initialize(bool inside_with) {
// such parameter is 'this' which is passed on the stack when
// invoking scripts
Variable* var =
- variables_.Declare(this, Factory::this_symbol(), Variable::VAR,
+ variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR,
false, Variable::THIS);
var->set_rewrite(new Slot(var, Slot::PARAMETER, -1));
receiver_ = var;
@@ -243,7 +259,7 @@ void Scope::Initialize(bool inside_with) {
// Declare 'arguments' variable which exists in all functions.
// Note that it might never be accessed, in which case it won't be
// allocated during variable allocation.
- variables_.Declare(this, Factory::arguments_symbol(), Variable::VAR,
+ variables_.Declare(this, FACTORY->arguments_symbol(), Variable::VAR,
true, Variable::ARGUMENTS);
}
}
@@ -258,7 +274,7 @@ Variable* Scope::LocalLookup(Handle<String> name) {
// We should never lookup 'arguments' in this scope
// as it is implicitly present in any scope.
- ASSERT(*name != *Factory::arguments_symbol());
+ ASSERT(*name != *FACTORY->arguments_symbol());
// Assert that there is no local slot with the given name.
ASSERT(scope_info_->StackSlotIndex(*name) < 0);
@@ -857,7 +873,7 @@ bool Scope::MustAllocateInContext(Variable* var) {
bool Scope::HasArgumentsParameter() {
for (int i = 0; i < params_.length(); i++) {
- if (params_[i]->name().is_identical_to(Factory::arguments_symbol()))
+ if (params_[i]->name().is_identical_to(FACTORY->arguments_symbol()))
return true;
}
return false;
@@ -876,8 +892,13 @@ void Scope::AllocateHeapSlot(Variable* var) {
void Scope::AllocateParameterLocals() {
ASSERT(is_function_scope());
- Variable* arguments = LocalLookup(Factory::arguments_symbol());
+ Variable* arguments = LocalLookup(FACTORY->arguments_symbol());
ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
+
+ // Parameters are rewritten to arguments[i] if 'arguments' is used in
+ // a non-strict mode function. Strict mode code doesn't alias arguments.
+ bool rewrite_parameters = false;
+
if (MustAllocate(arguments) && !HasArgumentsParameter()) {
// 'arguments' is used. Unless there is also a parameter called
// 'arguments', we must be conservative and access all parameters via
@@ -909,6 +930,13 @@ void Scope::AllocateParameterLocals() {
// allocate the arguments object by setting 'arguments_'.
arguments_ = arguments;
+ // In strict mode 'arguments' does not alias formal parameters.
+ // Therefore in strict mode we allocate parameters as if 'arguments'
+ // were not used.
+ rewrite_parameters = !is_strict_mode();
+ }
+
+ if (rewrite_parameters) {
// We also need the '.arguments' shadow variable. Declare it and create
// and bind the corresponding proxy. It's ok to declare it only now
// because it's a local variable that is allocated after the parameters
@@ -919,7 +947,7 @@ void Scope::AllocateParameterLocals() {
// variable may be allocated in the heap-allocated context (temporaries
// are never allocated in the context).
arguments_shadow_ = new Variable(this,
- Factory::arguments_shadow_symbol(),
+ FACTORY->arguments_shadow_symbol(),
Variable::INTERNAL,
true,
Variable::ARGUMENTS);
@@ -985,7 +1013,7 @@ void Scope::AllocateParameterLocals() {
void Scope::AllocateNonParameterLocal(Variable* var) {
ASSERT(var->scope() == this);
ASSERT(var->rewrite() == NULL ||
- (!var->IsVariable(Factory::result_symbol())) ||
+ (!var->IsVariable(FACTORY->result_symbol())) ||
(var->AsSlot() == NULL || var->AsSlot()->type() != Slot::LOCAL));
if (var->rewrite() == NULL && MustAllocate(var)) {
if (MustAllocateInContext(var)) {
diff --git a/src/scopes.h b/src/scopes.h
index a9220eb8..24622b4b 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -104,6 +104,9 @@ class Scope: public ZoneObject {
// doesn't re-allocate variables repeatedly.
static bool Analyze(CompilationInfo* info);
+ static Scope* DeserializeScopeChain(CompilationInfo* info,
+ Scope* innermost_scope);
+
// The scope name is only used for printing/debugging.
void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; }
@@ -193,6 +196,10 @@ class Scope: public ZoneObject {
// Inform the scope that the corresponding code contains an eval call.
void RecordEvalCall() { scope_calls_eval_ = true; }
+ // Enable strict mode for the scope (unless disabled by a global flag).
+ void EnableStrictMode() {
+ strict_mode_ = FLAG_strict_mode;
+ }
// ---------------------------------------------------------------------------
// Predicates.
@@ -201,6 +208,7 @@ class Scope: public ZoneObject {
bool is_eval_scope() const { return type_ == EVAL_SCOPE; }
bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
+ bool is_strict_mode() const { return strict_mode_; }
// Information about which scopes calls eval.
bool calls_eval() const { return scope_calls_eval_; }
@@ -220,7 +228,7 @@ class Scope: public ZoneObject {
// A new variable proxy corresponding to the (function) receiver.
VariableProxy* receiver() const {
VariableProxy* proxy =
- new VariableProxy(Factory::this_symbol(), true, false);
+ new VariableProxy(FACTORY->this_symbol(), true, false);
proxy->BindTo(receiver_);
return proxy;
}
@@ -313,14 +321,6 @@ class Scope: public ZoneObject {
explicit Scope(Type type);
- void InsertAfterScope(Scope* scope) {
- inner_scopes_.Add(scope);
- outer_scope_ = scope->outer_scope_;
- outer_scope_->inner_scopes_.RemoveElement(scope);
- outer_scope_->inner_scopes_.Add(this);
- scope->outer_scope_ = this;
- }
-
// Scope tree.
Scope* outer_scope_; // the immediately enclosing outer scope, or NULL
ZoneList<Scope*> inner_scopes_; // the immediately enclosed inner scopes
@@ -363,6 +363,7 @@ class Scope: public ZoneObject {
bool scope_inside_with_; // this scope is inside a 'with' of some outer scope
bool scope_contains_with_; // this scope contains a 'with' statement
bool scope_calls_eval_; // this scope contains an 'eval' call
+ bool strict_mode_; // this scope is a strict mode scope
// Computed via PropagateScopeInfo.
bool outer_scope_calls_eval_;
@@ -413,12 +414,19 @@ class Scope: public ZoneObject {
private:
Scope(Scope* inner_scope, SerializedScopeInfo* scope_info);
+ void AddInnerScope(Scope* inner_scope) {
+ if (inner_scope != NULL) {
+ inner_scopes_.Add(inner_scope);
+ inner_scope->outer_scope_ = this;
+ }
+ }
+
void SetDefaults(Type type,
Scope* outer_scope,
SerializedScopeInfo* scope_info) {
outer_scope_ = outer_scope;
type_ = type;
- scope_name_ = Factory::empty_symbol();
+ scope_name_ = FACTORY->empty_symbol();
dynamics_ = NULL;
receiver_ = NULL;
function_ = NULL;
@@ -428,6 +436,8 @@ class Scope: public ZoneObject {
scope_inside_with_ = false;
scope_contains_with_ = false;
scope_calls_eval_ = false;
+ // Inherit the strict mode from the parent scope.
+ strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_;
outer_scope_calls_eval_ = false;
inner_scope_calls_eval_ = false;
outer_scope_is_eval_scope_ = false;
diff --git a/src/serialize.cc b/src/serialize.cc
index f8e98d33..12e9613e 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -38,7 +38,6 @@
#include "serialize.h"
#include "stub-cache.h"
#include "v8threads.h"
-#include "top.h"
#include "bootstrapper.h"
namespace v8 {
@@ -68,9 +67,14 @@ static int* GetInternalPointer(StatsCounter* counter) {
// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
class ExternalReferenceTable {
public:
- static ExternalReferenceTable* instance() {
- if (!instance_) instance_ = new ExternalReferenceTable();
- return instance_;
+ static ExternalReferenceTable* instance(Isolate* isolate) {
+ ExternalReferenceTable* external_reference_table =
+ isolate->external_reference_table();
+ if (external_reference_table == NULL) {
+ external_reference_table = new ExternalReferenceTable(isolate);
+ isolate->set_external_reference_table(external_reference_table);
+ }
+ return external_reference_table;
}
int size() const { return refs_.length(); }
@@ -84,9 +88,9 @@ class ExternalReferenceTable {
int max_id(int code) { return max_id_[code]; }
private:
- static ExternalReferenceTable* instance_;
-
- ExternalReferenceTable() : refs_(64) { PopulateTable(); }
+ explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) {
+ PopulateTable(isolate);
+ }
~ExternalReferenceTable() { }
struct ExternalReferenceEntry {
@@ -95,10 +99,13 @@ class ExternalReferenceTable {
const char* name;
};
- void PopulateTable();
+ void PopulateTable(Isolate* isolate);
// For a few types of references, we can get their address from their id.
- void AddFromId(TypeCode type, uint16_t id, const char* name);
+ void AddFromId(TypeCode type,
+ uint16_t id,
+ const char* name,
+ Isolate* isolate);
// For other types of references, the caller will figure out the address.
void Add(Address address, TypeCode type, uint16_t id, const char* name);
@@ -108,31 +115,30 @@ class ExternalReferenceTable {
};
-ExternalReferenceTable* ExternalReferenceTable::instance_ = NULL;
-
-
void ExternalReferenceTable::AddFromId(TypeCode type,
uint16_t id,
- const char* name) {
+ const char* name,
+ Isolate* isolate) {
Address address;
switch (type) {
case C_BUILTIN: {
- ExternalReference ref(static_cast<Builtins::CFunctionId>(id));
+ ExternalReference ref(static_cast<Builtins::CFunctionId>(id), isolate);
address = ref.address();
break;
}
case BUILTIN: {
- ExternalReference ref(static_cast<Builtins::Name>(id));
+ ExternalReference ref(static_cast<Builtins::Name>(id), isolate);
address = ref.address();
break;
}
case RUNTIME_FUNCTION: {
- ExternalReference ref(static_cast<Runtime::FunctionId>(id));
+ ExternalReference ref(static_cast<Runtime::FunctionId>(id), isolate);
address = ref.address();
break;
}
case IC_UTILITY: {
- ExternalReference ref(IC_Utility(static_cast<IC::UtilityId>(id)));
+ ExternalReference ref(IC_Utility(static_cast<IC::UtilityId>(id)),
+ isolate);
address = ref.address();
break;
}
@@ -159,7 +165,7 @@ void ExternalReferenceTable::Add(Address address,
}
-void ExternalReferenceTable::PopulateTable() {
+void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
for (int type_code = 0; type_code < kTypeCodeCount; type_code++) {
max_id_[type_code] = 0;
}
@@ -190,7 +196,7 @@ void ExternalReferenceTable::PopulateTable() {
#define DEF_ENTRY_C(name, ignored) \
{ BUILTIN, \
- Builtins::name, \
+ Builtins::k##name, \
"Builtins::" #name },
#define DEF_ENTRY_A(name, kind, state, extra) DEF_ENTRY_C(name, ignored)
@@ -220,24 +226,27 @@ void ExternalReferenceTable::PopulateTable() {
}; // end of ref_table[].
for (size_t i = 0; i < ARRAY_SIZE(ref_table); ++i) {
- AddFromId(ref_table[i].type, ref_table[i].id, ref_table[i].name);
+ AddFromId(ref_table[i].type,
+ ref_table[i].id,
+ ref_table[i].name,
+ isolate);
}
#ifdef ENABLE_DEBUGGER_SUPPORT
// Debug addresses
- Add(Debug_Address(Debug::k_after_break_target_address).address(),
+ Add(Debug_Address(Debug::k_after_break_target_address).address(isolate),
DEBUG_ADDRESS,
Debug::k_after_break_target_address << kDebugIdShift,
"Debug::after_break_target_address()");
- Add(Debug_Address(Debug::k_debug_break_slot_address).address(),
+ Add(Debug_Address(Debug::k_debug_break_slot_address).address(isolate),
DEBUG_ADDRESS,
Debug::k_debug_break_slot_address << kDebugIdShift,
"Debug::debug_break_slot_address()");
- Add(Debug_Address(Debug::k_debug_break_return_address).address(),
+ Add(Debug_Address(Debug::k_debug_break_return_address).address(isolate),
DEBUG_ADDRESS,
Debug::k_debug_break_return_address << kDebugIdShift,
"Debug::debug_break_return_address()");
- Add(Debug_Address(Debug::k_restarter_frame_function_pointer).address(),
+ Add(Debug_Address(Debug::k_restarter_frame_function_pointer).address(isolate),
DEBUG_ADDRESS,
Debug::k_restarter_frame_function_pointer << kDebugIdShift,
"Debug::restarter_frame_function_pointer_address()");
@@ -245,14 +254,14 @@ void ExternalReferenceTable::PopulateTable() {
// Stat counters
struct StatsRefTableEntry {
- StatsCounter* counter;
+ StatsCounter* (Counters::*counter)();
uint16_t id;
const char* name;
};
- static const StatsRefTableEntry stats_ref_table[] = {
+ const StatsRefTableEntry stats_ref_table[] = {
#define COUNTER_ENTRY(name, caption) \
- { &Counters::name, \
+ { &Counters::name, \
Counters::k_##name, \
"Counters::" #name },
@@ -261,33 +270,28 @@ void ExternalReferenceTable::PopulateTable() {
#undef COUNTER_ENTRY
}; // end of stats_ref_table[].
+ Counters* counters = isolate->counters();
for (size_t i = 0; i < ARRAY_SIZE(stats_ref_table); ++i) {
- Add(reinterpret_cast<Address>(
- GetInternalPointer(stats_ref_table[i].counter)),
+ Add(reinterpret_cast<Address>(GetInternalPointer(
+ (counters->*(stats_ref_table[i].counter))())),
STATS_COUNTER,
stats_ref_table[i].id,
stats_ref_table[i].name);
}
// Top addresses
- const char* top_address_format = "Top::%s";
const char* AddressNames[] = {
-#define C(name) #name,
- TOP_ADDRESS_LIST(C)
- TOP_ADDRESS_LIST_PROF(C)
+#define C(name) "Isolate::" #name,
+ ISOLATE_ADDRESS_LIST(C)
+ ISOLATE_ADDRESS_LIST_PROF(C)
NULL
#undef C
};
- int top_format_length = StrLength(top_address_format) - 2;
- for (uint16_t i = 0; i < Top::k_top_address_count; ++i) {
- const char* address_name = AddressNames[i];
- Vector<char> name =
- Vector<char>::New(top_format_length + StrLength(address_name) + 1);
- const char* chars = name.start();
- OS::SNPrintF(name, top_address_format, address_name);
- Add(Top::get_address_from_id((Top::AddressId)i), TOP_ADDRESS, i, chars);
+ for (uint16_t i = 0; i < Isolate::k_isolate_address_count; ++i) {
+ Add(isolate->get_address_from_id((Isolate::AddressId)i),
+ TOP_ADDRESS, i, AddressNames[i]);
}
// Accessors
@@ -300,143 +304,145 @@ void ExternalReferenceTable::PopulateTable() {
ACCESSOR_DESCRIPTOR_LIST(ACCESSOR_DESCRIPTOR_DECLARATION)
#undef ACCESSOR_DESCRIPTOR_DECLARATION
+ StubCache* stub_cache = isolate->stub_cache();
+
// Stub cache tables
- Add(SCTableReference::keyReference(StubCache::kPrimary).address(),
+ Add(stub_cache->key_reference(StubCache::kPrimary).address(),
STUB_CACHE_TABLE,
1,
"StubCache::primary_->key");
- Add(SCTableReference::valueReference(StubCache::kPrimary).address(),
+ Add(stub_cache->value_reference(StubCache::kPrimary).address(),
STUB_CACHE_TABLE,
2,
"StubCache::primary_->value");
- Add(SCTableReference::keyReference(StubCache::kSecondary).address(),
+ Add(stub_cache->key_reference(StubCache::kSecondary).address(),
STUB_CACHE_TABLE,
3,
"StubCache::secondary_->key");
- Add(SCTableReference::valueReference(StubCache::kSecondary).address(),
+ Add(stub_cache->value_reference(StubCache::kSecondary).address(),
STUB_CACHE_TABLE,
4,
"StubCache::secondary_->value");
// Runtime entries
- Add(ExternalReference::perform_gc_function().address(),
+ Add(ExternalReference::perform_gc_function(isolate).address(),
RUNTIME_ENTRY,
1,
"Runtime::PerformGC");
- Add(ExternalReference::fill_heap_number_with_random_function().address(),
+ Add(ExternalReference::fill_heap_number_with_random_function(
+ isolate).address(),
RUNTIME_ENTRY,
2,
"V8::FillHeapNumberWithRandom");
-
- Add(ExternalReference::random_uint32_function().address(),
+ Add(ExternalReference::random_uint32_function(isolate).address(),
RUNTIME_ENTRY,
3,
"V8::Random");
-
- Add(ExternalReference::delete_handle_scope_extensions().address(),
+ Add(ExternalReference::delete_handle_scope_extensions(isolate).address(),
RUNTIME_ENTRY,
4,
"HandleScope::DeleteExtensions");
// Miscellaneous
- Add(ExternalReference::the_hole_value_location().address(),
+ Add(ExternalReference::the_hole_value_location(isolate).address(),
UNCLASSIFIED,
2,
"Factory::the_hole_value().location()");
- Add(ExternalReference::roots_address().address(),
+ Add(ExternalReference::roots_address(isolate).address(),
UNCLASSIFIED,
3,
"Heap::roots_address()");
- Add(ExternalReference::address_of_stack_limit().address(),
+ Add(ExternalReference::address_of_stack_limit(isolate).address(),
UNCLASSIFIED,
4,
"StackGuard::address_of_jslimit()");
- Add(ExternalReference::address_of_real_stack_limit().address(),
+ Add(ExternalReference::address_of_real_stack_limit(isolate).address(),
UNCLASSIFIED,
5,
"StackGuard::address_of_real_jslimit()");
#ifndef V8_INTERPRETED_REGEXP
- Add(ExternalReference::address_of_regexp_stack_limit().address(),
+ Add(ExternalReference::address_of_regexp_stack_limit(isolate).address(),
UNCLASSIFIED,
6,
"RegExpStack::limit_address()");
- Add(ExternalReference::address_of_regexp_stack_memory_address().address(),
+ Add(ExternalReference::address_of_regexp_stack_memory_address(
+ isolate).address(),
UNCLASSIFIED,
7,
"RegExpStack::memory_address()");
- Add(ExternalReference::address_of_regexp_stack_memory_size().address(),
+ Add(ExternalReference::address_of_regexp_stack_memory_size(isolate).address(),
UNCLASSIFIED,
8,
"RegExpStack::memory_size()");
- Add(ExternalReference::address_of_static_offsets_vector().address(),
+ Add(ExternalReference::address_of_static_offsets_vector(isolate).address(),
UNCLASSIFIED,
9,
"OffsetsVector::static_offsets_vector");
#endif // V8_INTERPRETED_REGEXP
- Add(ExternalReference::new_space_start().address(),
+ Add(ExternalReference::new_space_start(isolate).address(),
UNCLASSIFIED,
10,
"Heap::NewSpaceStart()");
- Add(ExternalReference::new_space_mask().address(),
+ Add(ExternalReference::new_space_mask(isolate).address(),
UNCLASSIFIED,
11,
"Heap::NewSpaceMask()");
- Add(ExternalReference::heap_always_allocate_scope_depth().address(),
+ Add(ExternalReference::heap_always_allocate_scope_depth(isolate).address(),
UNCLASSIFIED,
12,
"Heap::always_allocate_scope_depth()");
- Add(ExternalReference::new_space_allocation_limit_address().address(),
+ Add(ExternalReference::new_space_allocation_limit_address(isolate).address(),
UNCLASSIFIED,
13,
"Heap::NewSpaceAllocationLimitAddress()");
- Add(ExternalReference::new_space_allocation_top_address().address(),
+ Add(ExternalReference::new_space_allocation_top_address(isolate).address(),
UNCLASSIFIED,
14,
"Heap::NewSpaceAllocationTopAddress()");
#ifdef ENABLE_DEBUGGER_SUPPORT
- Add(ExternalReference::debug_break().address(),
+ Add(ExternalReference::debug_break(isolate).address(),
UNCLASSIFIED,
15,
"Debug::Break()");
- Add(ExternalReference::debug_step_in_fp_address().address(),
+ Add(ExternalReference::debug_step_in_fp_address(isolate).address(),
UNCLASSIFIED,
16,
"Debug::step_in_fp_addr()");
#endif
- Add(ExternalReference::double_fp_operation(Token::ADD).address(),
+ Add(ExternalReference::double_fp_operation(Token::ADD, isolate).address(),
UNCLASSIFIED,
17,
"add_two_doubles");
- Add(ExternalReference::double_fp_operation(Token::SUB).address(),
+ Add(ExternalReference::double_fp_operation(Token::SUB, isolate).address(),
UNCLASSIFIED,
18,
"sub_two_doubles");
- Add(ExternalReference::double_fp_operation(Token::MUL).address(),
+ Add(ExternalReference::double_fp_operation(Token::MUL, isolate).address(),
UNCLASSIFIED,
19,
"mul_two_doubles");
- Add(ExternalReference::double_fp_operation(Token::DIV).address(),
+ Add(ExternalReference::double_fp_operation(Token::DIV, isolate).address(),
UNCLASSIFIED,
20,
"div_two_doubles");
- Add(ExternalReference::double_fp_operation(Token::MOD).address(),
+ Add(ExternalReference::double_fp_operation(Token::MOD, isolate).address(),
UNCLASSIFIED,
21,
"mod_two_doubles");
- Add(ExternalReference::compare_doubles().address(),
+ Add(ExternalReference::compare_doubles(isolate).address(),
UNCLASSIFIED,
22,
"compare_doubles");
#ifndef V8_INTERPRETED_REGEXP
- Add(ExternalReference::re_case_insensitive_compare_uc16().address(),
+ Add(ExternalReference::re_case_insensitive_compare_uc16(isolate).address(),
UNCLASSIFIED,
23,
"NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()");
- Add(ExternalReference::re_check_stack_guard_state().address(),
+ Add(ExternalReference::re_check_stack_guard_state(isolate).address(),
UNCLASSIFIED,
24,
"RegExpMacroAssembler*::CheckStackGuardState()");
- Add(ExternalReference::re_grow_stack().address(),
+ Add(ExternalReference::re_grow_stack(isolate).address(),
UNCLASSIFIED,
25,
"NativeRegExpMacroAssembler::GrowStack()");
@@ -446,15 +452,15 @@ void ExternalReferenceTable::PopulateTable() {
"NativeRegExpMacroAssembler::word_character_map");
#endif // V8_INTERPRETED_REGEXP
// Keyed lookup cache.
- Add(ExternalReference::keyed_lookup_cache_keys().address(),
+ Add(ExternalReference::keyed_lookup_cache_keys(isolate).address(),
UNCLASSIFIED,
27,
"KeyedLookupCache::keys()");
- Add(ExternalReference::keyed_lookup_cache_field_offsets().address(),
+ Add(ExternalReference::keyed_lookup_cache_field_offsets(isolate).address(),
UNCLASSIFIED,
28,
"KeyedLookupCache::field_offsets()");
- Add(ExternalReference::transcendental_cache_array_address().address(),
+ Add(ExternalReference::transcendental_cache_array_address(isolate).address(),
UNCLASSIFIED,
29,
"TranscendentalCache::caches()");
@@ -470,11 +476,11 @@ void ExternalReferenceTable::PopulateTable() {
UNCLASSIFIED,
32,
"HandleScope::level");
- Add(ExternalReference::new_deoptimizer_function().address(),
+ Add(ExternalReference::new_deoptimizer_function(isolate).address(),
UNCLASSIFIED,
33,
"Deoptimizer::New()");
- Add(ExternalReference::compute_output_frames_function().address(),
+ Add(ExternalReference::compute_output_frames_function(isolate).address(),
UNCLASSIFIED,
34,
"Deoptimizer::ComputeOutputFrames()");
@@ -486,33 +492,38 @@ void ExternalReferenceTable::PopulateTable() {
UNCLASSIFIED,
36,
"LDoubleConstant::one_half");
- Add(ExternalReference::address_of_minus_zero().address(),
+ Add(ExternalReference::isolate_address().address(),
UNCLASSIFIED,
37,
+ "isolate");
+ Add(ExternalReference::address_of_minus_zero().address(),
+ UNCLASSIFIED,
+ 38,
"LDoubleConstant::minus_zero");
Add(ExternalReference::address_of_negative_infinity().address(),
UNCLASSIFIED,
- 38,
+ 39,
"LDoubleConstant::negative_infinity");
- Add(ExternalReference::power_double_double_function().address(),
+ Add(ExternalReference::power_double_double_function(isolate).address(),
UNCLASSIFIED,
- 39,
+ 40,
"power_double_double_function");
- Add(ExternalReference::power_double_int_function().address(),
+ Add(ExternalReference::power_double_int_function(isolate).address(),
UNCLASSIFIED,
- 40,
+ 41,
"power_double_int_function");
- Add(ExternalReference::arguments_marker_location().address(),
+ Add(ExternalReference::arguments_marker_location(isolate).address(),
UNCLASSIFIED,
- 41,
+ 42,
"Factory::arguments_marker().location()");
}
ExternalReferenceEncoder::ExternalReferenceEncoder()
- : encodings_(Match) {
+ : encodings_(Match),
+ isolate_(Isolate::Current()) {
ExternalReferenceTable* external_references =
- ExternalReferenceTable::instance();
+ ExternalReferenceTable::instance(isolate_);
for (int i = 0; i < external_references->size(); ++i) {
Put(external_references->address(i), i);
}
@@ -522,20 +533,22 @@ ExternalReferenceEncoder::ExternalReferenceEncoder()
uint32_t ExternalReferenceEncoder::Encode(Address key) const {
int index = IndexOf(key);
ASSERT(key == NULL || index >= 0);
- return index >=0 ? ExternalReferenceTable::instance()->code(index) : 0;
+ return index >=0 ?
+ ExternalReferenceTable::instance(isolate_)->code(index) : 0;
}
const char* ExternalReferenceEncoder::NameOfAddress(Address key) const {
int index = IndexOf(key);
- return index >=0 ? ExternalReferenceTable::instance()->name(index) : NULL;
+ return index >= 0 ?
+ ExternalReferenceTable::instance(isolate_)->name(index) : NULL;
}
int ExternalReferenceEncoder::IndexOf(Address key) const {
if (key == NULL) return -1;
HashMap::Entry* entry =
- const_cast<HashMap &>(encodings_).Lookup(key, Hash(key), false);
+ const_cast<HashMap&>(encodings_).Lookup(key, Hash(key), false);
return entry == NULL
? -1
: static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
@@ -549,9 +562,10 @@ void ExternalReferenceEncoder::Put(Address key, int index) {
ExternalReferenceDecoder::ExternalReferenceDecoder()
- : encodings_(NewArray<Address*>(kTypeCodeCount)) {
+ : encodings_(NewArray<Address*>(kTypeCodeCount)),
+ isolate_(Isolate::Current()) {
ExternalReferenceTable* external_references =
- ExternalReferenceTable::instance();
+ ExternalReferenceTable::instance(isolate_);
for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
int max = external_references->max_id(type) + 1;
encodings_[type] = NewArray<Address>(max + 1);
@@ -572,10 +586,12 @@ ExternalReferenceDecoder::~ExternalReferenceDecoder() {
bool Serializer::serialization_enabled_ = false;
bool Serializer::too_late_to_enable_now_ = false;
-ExternalReferenceDecoder* Deserializer::external_reference_decoder_ = NULL;
-Deserializer::Deserializer(SnapshotByteSource* source) : source_(source) {
+Deserializer::Deserializer(SnapshotByteSource* source)
+ : isolate_(NULL),
+ source_(source),
+ external_reference_decoder_(NULL) {
}
@@ -601,7 +617,6 @@ Address Deserializer::Allocate(int space_index, Space* space, int size) {
high_water_[space_index] = address + size;
} else {
ASSERT(SpaceIsLarge(space_index));
- ASSERT(size > Page::kPageSize - Page::kObjectStartOffset);
LargeObjectSpace* lo_space = reinterpret_cast<LargeObjectSpace*>(space);
Object* new_allocation;
if (space_index == kLargeData) {
@@ -655,27 +670,31 @@ HeapObject* Deserializer::GetAddressFromStart(int space) {
void Deserializer::Deserialize() {
+ isolate_ = Isolate::Current();
// Don't GC while deserializing - just expand the heap.
AlwaysAllocateScope always_allocate;
// Don't use the free lists while deserializing.
LinearAllocationScope allocate_linearly;
// No active threads.
- ASSERT_EQ(NULL, ThreadState::FirstInUse());
+ ASSERT_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse());
// No active handles.
- ASSERT(HandleScopeImplementer::instance()->blocks()->is_empty());
+ ASSERT(isolate_->handle_scope_implementer()->blocks()->is_empty());
// Make sure the entire partial snapshot cache is traversed, filling it with
// valid object pointers.
- partial_snapshot_cache_length_ = kPartialSnapshotCacheCapacity;
+ isolate_->set_serialize_partial_snapshot_cache_length(
+ Isolate::kPartialSnapshotCacheCapacity);
ASSERT_EQ(NULL, external_reference_decoder_);
external_reference_decoder_ = new ExternalReferenceDecoder();
- Heap::IterateStrongRoots(this, VISIT_ONLY_STRONG);
- Heap::IterateWeakRoots(this, VISIT_ALL);
+ isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
+ isolate_->heap()->IterateWeakRoots(this, VISIT_ALL);
- Heap::set_global_contexts_list(Heap::undefined_value());
+ isolate_->heap()->set_global_contexts_list(
+ isolate_->heap()->undefined_value());
}
void Deserializer::DeserializePartial(Object** root) {
+ isolate_ = Isolate::Current();
// Don't GC while deserializing - just expand the heap.
AlwaysAllocateScope always_allocate;
// Don't use the free lists while deserializing.
@@ -689,7 +708,7 @@ void Deserializer::DeserializePartial(Object** root) {
Deserializer::~Deserializer() {
ASSERT(source_->AtEOF());
- if (external_reference_decoder_ != NULL) {
+ if (external_reference_decoder_) {
delete external_reference_decoder_;
external_reference_decoder_ = NULL;
}
@@ -720,9 +739,14 @@ void Deserializer::ReadObject(int space_number,
Object** current = reinterpret_cast<Object**>(address);
Object** limit = current + (size >> kPointerSizeLog2);
if (FLAG_log_snapshot_positions) {
- LOG(SnapshotPositionEvent(address, source_->position()));
+ LOG(isolate_, SnapshotPositionEvent(address, source_->position()));
}
ReadChunk(current, limit, space_number, address);
+#ifdef DEBUG
+ bool is_codespace = (space == HEAP->code_space()) ||
+ ((space == HEAP->lo_space()) && (space_number == kLargeCode));
+ ASSERT(HeapObject::FromAddress(address)->IsCode() == is_codespace);
+#endif
}
@@ -732,20 +756,20 @@ void Deserializer::ReadObject(int space_number,
#define ASSIGN_DEST_SPACE(space_number) \
Space* dest_space; \
if (space_number == NEW_SPACE) { \
- dest_space = Heap::new_space(); \
+ dest_space = isolate->heap()->new_space(); \
} else if (space_number == OLD_POINTER_SPACE) { \
- dest_space = Heap::old_pointer_space(); \
+ dest_space = isolate->heap()->old_pointer_space(); \
} else if (space_number == OLD_DATA_SPACE) { \
- dest_space = Heap::old_data_space(); \
+ dest_space = isolate->heap()->old_data_space(); \
} else if (space_number == CODE_SPACE) { \
- dest_space = Heap::code_space(); \
+ dest_space = isolate->heap()->code_space(); \
} else if (space_number == MAP_SPACE) { \
- dest_space = Heap::map_space(); \
+ dest_space = isolate->heap()->map_space(); \
} else if (space_number == CELL_SPACE) { \
- dest_space = Heap::cell_space(); \
+ dest_space = isolate->heap()->cell_space(); \
} else { \
ASSERT(space_number >= LO_SPACE); \
- dest_space = Heap::lo_space(); \
+ dest_space = isolate->heap()->lo_space(); \
}
@@ -756,6 +780,7 @@ void Deserializer::ReadChunk(Object** current,
Object** limit,
int source_space,
Address address) {
+ Isolate* const isolate = isolate_;
while (current < limit) {
int data = source_->Get();
switch (data) {
@@ -784,14 +809,15 @@ void Deserializer::ReadChunk(Object** current,
ReadObject(space_number, dest_space, &new_object); \
} else if (where == kRootArray) { \
int root_id = source_->GetInt(); \
- new_object = Heap::roots_address()[root_id]; \
+ new_object = isolate->heap()->roots_address()[root_id]; \
} else if (where == kPartialSnapshotCache) { \
int cache_index = source_->GetInt(); \
- new_object = partial_snapshot_cache_[cache_index]; \
+ new_object = isolate->serialize_partial_snapshot_cache() \
+ [cache_index]; \
} else if (where == kExternalReference) { \
int reference_id = source_->GetInt(); \
- Address address = \
- external_reference_decoder_->Decode(reference_id); \
+ Address address = external_reference_decoder_-> \
+ Decode(reference_id); \
new_object = reinterpret_cast<Object*>(address); \
} else if (where == kBackref) { \
emit_write_barrier = \
@@ -829,7 +855,7 @@ void Deserializer::ReadChunk(Object** current,
} \
} \
if (emit_write_barrier) { \
- Heap::RecordWrite(address, static_cast<int>( \
+ isolate->heap()->RecordWrite(address, static_cast<int>( \
reinterpret_cast<Address>(current) - address)); \
} \
if (!current_was_incremented) { \
@@ -878,7 +904,7 @@ void Deserializer::ReadChunk(Object** current,
CASE_STATEMENT(where, how, within, CODE_SPACE) \
CASE_BODY(where, how, within, CODE_SPACE, kUnknownOffsetFromStart) \
CASE_STATEMENT(where, how, within, kLargeCode) \
- CASE_BODY(where, how, within, LO_SPACE, kUnknownOffsetFromStart)
+ CASE_BODY(where, how, within, kLargeCode, kUnknownOffsetFromStart)
#define EMIT_COMMON_REFERENCE_PATTERNS(pseudo_space_number, \
space_number, \
@@ -993,7 +1019,8 @@ void Deserializer::ReadChunk(Object** current,
int index = source_->Get();
Vector<const char> source_vector = Natives::GetScriptSource(index);
NativesExternalStringResource* resource =
- new NativesExternalStringResource(source_vector.start());
+ new NativesExternalStringResource(
+ isolate->bootstrapper(), source_vector.start());
*current++ = reinterpret_cast<Object*>(resource);
break;
}
@@ -1058,6 +1085,9 @@ Serializer::Serializer(SnapshotByteSink* sink)
current_root_index_(0),
external_reference_encoder_(new ExternalReferenceEncoder),
large_object_total_(0) {
+ // The serializer is meant to be used only to generate initial heap images
+ // from a context in which there is only one isolate.
+ ASSERT(Isolate::Current()->IsDefaultIsolate());
for (int i = 0; i <= LAST_SPACE; i++) {
fullness_[i] = 0;
}
@@ -1070,35 +1100,40 @@ Serializer::~Serializer() {
void StartupSerializer::SerializeStrongReferences() {
+ Isolate* isolate = Isolate::Current();
// No active threads.
- CHECK_EQ(NULL, ThreadState::FirstInUse());
+ CHECK_EQ(NULL, Isolate::Current()->thread_manager()->FirstThreadStateInUse());
// No active or weak handles.
- CHECK(HandleScopeImplementer::instance()->blocks()->is_empty());
- CHECK_EQ(0, GlobalHandles::NumberOfWeakHandles());
+ CHECK(isolate->handle_scope_implementer()->blocks()->is_empty());
+ CHECK_EQ(0, isolate->global_handles()->NumberOfWeakHandles());
// We don't support serializing installed extensions.
- for (RegisteredExtension* ext = RegisteredExtension::first_extension();
+ for (RegisteredExtension* ext = v8::RegisteredExtension::first_extension();
ext != NULL;
ext = ext->next()) {
CHECK_NE(v8::INSTALLED, ext->state());
}
- Heap::IterateStrongRoots(this, VISIT_ONLY_STRONG);
+ HEAP->IterateStrongRoots(this, VISIT_ONLY_STRONG);
}
void PartialSerializer::Serialize(Object** object) {
this->VisitPointer(object);
+ Isolate* isolate = Isolate::Current();
// After we have done the partial serialization the partial snapshot cache
// will contain some references needed to decode the partial snapshot. We
// fill it up with undefineds so it has a predictable length so the
// deserialization code doesn't need to know the length.
- for (int index = partial_snapshot_cache_length_;
- index < kPartialSnapshotCacheCapacity;
+ for (int index = isolate->serialize_partial_snapshot_cache_length();
+ index < Isolate::kPartialSnapshotCacheCapacity;
index++) {
- partial_snapshot_cache_[index] = Heap::undefined_value();
- startup_serializer_->VisitPointer(&partial_snapshot_cache_[index]);
+ isolate->serialize_partial_snapshot_cache()[index] =
+ isolate->heap()->undefined_value();
+ startup_serializer_->VisitPointer(
+ &isolate->serialize_partial_snapshot_cache()[index]);
}
- partial_snapshot_cache_length_ = kPartialSnapshotCacheCapacity;
+ isolate->set_serialize_partial_snapshot_cache_length(
+ Isolate::kPartialSnapshotCacheCapacity);
}
@@ -1117,11 +1152,6 @@ void Serializer::VisitPointers(Object** start, Object** end) {
}
-Object* SerializerDeserializer::partial_snapshot_cache_[
- kPartialSnapshotCacheCapacity];
-int SerializerDeserializer::partial_snapshot_cache_length_ = 0;
-
-
// This ensures that the partial snapshot cache keeps things alive during GC and
// tracks their movement. When it is called during serialization of the startup
// snapshot the partial snapshot is empty, so nothing happens. When the partial
@@ -1131,9 +1161,11 @@ int SerializerDeserializer::partial_snapshot_cache_length_ = 0;
// deserialization we therefore need to visit the cache array. This fills it up
// with pointers to deserialized objects.
void SerializerDeserializer::Iterate(ObjectVisitor* visitor) {
+ Isolate* isolate = Isolate::Current();
visitor->VisitPointers(
- &partial_snapshot_cache_[0],
- &partial_snapshot_cache_[partial_snapshot_cache_length_]);
+ isolate->serialize_partial_snapshot_cache(),
+ &isolate->serialize_partial_snapshot_cache()[
+ isolate->serialize_partial_snapshot_cache_length()]);
}
@@ -1141,33 +1173,39 @@ void SerializerDeserializer::Iterate(ObjectVisitor* visitor) {
// the root iteration code (above) will iterate over array elements, writing the
// references to deserialized objects in them.
void SerializerDeserializer::SetSnapshotCacheSize(int size) {
- partial_snapshot_cache_length_ = size;
+ Isolate::Current()->set_serialize_partial_snapshot_cache_length(size);
}
int PartialSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
- for (int i = 0; i < partial_snapshot_cache_length_; i++) {
- Object* entry = partial_snapshot_cache_[i];
+ Isolate* isolate = Isolate::Current();
+
+ for (int i = 0;
+ i < isolate->serialize_partial_snapshot_cache_length();
+ i++) {
+ Object* entry = isolate->serialize_partial_snapshot_cache()[i];
if (entry == heap_object) return i;
}
// We didn't find the object in the cache. So we add it to the cache and
// then visit the pointer so that it becomes part of the startup snapshot
// and we can refer to it from the partial snapshot.
- int length = partial_snapshot_cache_length_;
- CHECK(length < kPartialSnapshotCacheCapacity);
- partial_snapshot_cache_[length] = heap_object;
- startup_serializer_->VisitPointer(&partial_snapshot_cache_[length]);
+ int length = isolate->serialize_partial_snapshot_cache_length();
+ CHECK(length < Isolate::kPartialSnapshotCacheCapacity);
+ isolate->serialize_partial_snapshot_cache()[length] = heap_object;
+ startup_serializer_->VisitPointer(
+ &isolate->serialize_partial_snapshot_cache()[length]);
// We don't recurse from the startup snapshot generator into the partial
// snapshot generator.
- ASSERT(length == partial_snapshot_cache_length_);
- return partial_snapshot_cache_length_++;
+ ASSERT(length == isolate->serialize_partial_snapshot_cache_length());
+ isolate->set_serialize_partial_snapshot_cache_length(length + 1);
+ return length;
}
int PartialSerializer::RootIndex(HeapObject* heap_object) {
for (int i = 0; i < Heap::kRootListLength; i++) {
- Object* root = Heap::roots_address()[i];
+ Object* root = HEAP->roots_address()[i];
if (root == heap_object) return i;
}
return kInvalidRootIndex;
@@ -1250,13 +1288,13 @@ void StartupSerializer::SerializeObject(
void StartupSerializer::SerializeWeakReferences() {
- for (int i = partial_snapshot_cache_length_;
- i < kPartialSnapshotCacheCapacity;
+ for (int i = Isolate::Current()->serialize_partial_snapshot_cache_length();
+ i < Isolate::kPartialSnapshotCacheCapacity;
i++) {
sink_->Put(kRootArray + kPlain + kStartOfObject, "RootSerialization");
sink_->PutInt(Heap::kUndefinedValueRootIndex, "root_index");
}
- Heap::IterateWeakRoots(this, VISIT_ALL);
+ HEAP->IterateWeakRoots(this, VISIT_ALL);
}
@@ -1317,7 +1355,8 @@ void Serializer::ObjectSerializer::Serialize() {
"ObjectSerialization");
sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
- LOG(SnapshotPositionEvent(object_->address(), sink_->Position()));
+ LOG(i::Isolate::Current(),
+ SnapshotPositionEvent(object_->address(), sink_->Position()));
// Mark this object as already serialized.
bool start_new_page;
@@ -1418,7 +1457,7 @@ void Serializer::ObjectSerializer::VisitExternalAsciiString(
Address references_start = reinterpret_cast<Address>(resource_pointer);
OutputRawData(references_start);
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
- Object* source = Heap::natives_source_cache()->get(i);
+ Object* source = HEAP->natives_source_cache()->get(i);
if (!source->IsUndefined()) {
ExternalAsciiString* string = ExternalAsciiString::cast(source);
typedef v8::String::ExternalAsciiStringResource Resource;
@@ -1468,7 +1507,7 @@ void Serializer::ObjectSerializer::OutputRawData(Address up_to) {
int Serializer::SpaceOfObject(HeapObject* object) {
for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
AllocationSpace s = static_cast<AllocationSpace>(i);
- if (Heap::InSpace(object, s)) {
+ if (HEAP->InSpace(object, s)) {
if (i == LO_SPACE) {
if (object->IsCode()) {
return kLargeCode;
@@ -1489,7 +1528,7 @@ int Serializer::SpaceOfObject(HeapObject* object) {
int Serializer::SpaceOfAlreadySerializedObject(HeapObject* object) {
for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
AllocationSpace s = static_cast<AllocationSpace>(i);
- if (Heap::InSpace(object, s)) {
+ if (HEAP->InSpace(object, s)) {
return i;
}
}
diff --git a/src/serialize.h b/src/serialize.h
index e80c302d..07c0a255 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -79,6 +79,8 @@ class ExternalReferenceEncoder {
static bool Match(void* key1, void* key2) { return key1 == key2; }
void Put(Address key, int index);
+
+ Isolate* isolate_;
};
@@ -105,6 +107,8 @@ class ExternalReferenceDecoder {
void Put(uint32_t key, Address value) {
*Lookup(key) = value;
}
+
+ Isolate* isolate_;
};
@@ -144,7 +148,7 @@ class SnapshotByteSource {
// This only works for objects in the first page of a space. Don't use this for
// things in newspace since it bypasses the write barrier.
-static const int k64 = (sizeof(uintptr_t) - 4) / 4;
+RLYSTC const int k64 = (sizeof(uintptr_t) - 4) / 4;
#define COMMON_REFERENCE_PATTERNS(f) \
f(kNumberOfSpaces, 2, (11 - k64)) \
@@ -177,8 +181,8 @@ static const int k64 = (sizeof(uintptr_t) - 4) / 4;
// both.
class SerializerDeserializer: public ObjectVisitor {
public:
- static void Iterate(ObjectVisitor* visitor);
- static void SetSnapshotCacheSize(int size);
+ RLYSTC void Iterate(ObjectVisitor* visitor);
+ RLYSTC void SetSnapshotCacheSize(int size);
protected:
// Where the pointed-to object can be found:
@@ -216,40 +220,36 @@ class SerializerDeserializer: public ObjectVisitor {
// Misc.
// Raw data to be copied from the snapshot.
- static const int kRawData = 0x30;
+ RLYSTC const int kRawData = 0x30;
// Some common raw lengths: 0x31-0x3f
// A tag emitted at strategic points in the snapshot to delineate sections.
// If the deserializer does not find these at the expected moments then it
// is an indication that the snapshot and the VM do not fit together.
// Examine the build process for architecture, version or configuration
// mismatches.
- static const int kSynchronize = 0x70;
+ RLYSTC const int kSynchronize = 0x70;
// Used for the source code of the natives, which is in the executable, but
// is referred to from external strings in the snapshot.
- static const int kNativesStringResource = 0x71;
- static const int kNewPage = 0x72;
+ RLYSTC const int kNativesStringResource = 0x71;
+ RLYSTC const int kNewPage = 0x72;
// 0x73-0x7f Free.
// 0xb0-0xbf Free.
// 0xf0-0xff Free.
- static const int kLargeData = LAST_SPACE;
- static const int kLargeCode = kLargeData + 1;
- static const int kLargeFixedArray = kLargeCode + 1;
- static const int kNumberOfSpaces = kLargeFixedArray + 1;
- static const int kAnyOldSpace = -1;
+ RLYSTC const int kLargeData = LAST_SPACE;
+ RLYSTC const int kLargeCode = kLargeData + 1;
+ RLYSTC const int kLargeFixedArray = kLargeCode + 1;
+ RLYSTC const int kNumberOfSpaces = kLargeFixedArray + 1;
+ RLYSTC const int kAnyOldSpace = -1;
// A bitmask for getting the space out of an instruction.
- static const int kSpaceMask = 15;
+ RLYSTC const int kSpaceMask = 15;
- static inline bool SpaceIsLarge(int space) { return space >= kLargeData; }
- static inline bool SpaceIsPaged(int space) {
+ RLYSTC inline bool SpaceIsLarge(int space) { return space >= kLargeData; }
+ RLYSTC inline bool SpaceIsPaged(int space) {
return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE;
}
-
- static int partial_snapshot_cache_length_;
- static const int kPartialSnapshotCacheCapacity = 1400;
- static Object* partial_snapshot_cache_[];
};
@@ -313,6 +313,9 @@ class Deserializer: public SerializerDeserializer {
Address Allocate(int space_number, Space* space, int size);
void ReadObject(int space_number, Space* space, Object** write_back);
+ // Cached current isolate.
+ Isolate* isolate_;
+
// Keep track of the pages in the paged spaces.
// (In large object space we are keeping track of individual objects
// rather than pages.) In new space we just need the address of the
@@ -320,7 +323,6 @@ class Deserializer: public SerializerDeserializer {
List<Address> pages_[SerializerDeserializer::kNumberOfSpaces];
SnapshotByteSource* source_;
- static ExternalReferenceDecoder* external_reference_decoder_;
// This is the address of the next object that will be allocated in each
// space. It is used to calculate the addresses of back-references.
Address high_water_[LAST_SPACE + 1];
@@ -329,6 +331,8 @@ class Deserializer: public SerializerDeserializer {
// START_NEW_PAGE_SERIALIZATION tag.
Address last_object_address_;
+ ExternalReferenceDecoder* external_reference_decoder_;
+
DISALLOW_COPY_AND_ASSIGN(Deserializer);
};
@@ -376,19 +380,19 @@ class SerializationAddressMapper {
}
private:
- static bool SerializationMatchFun(void* key1, void* key2) {
+ RLYSTC bool SerializationMatchFun(void* key1, void* key2) {
return key1 == key2;
}
- static uint32_t Hash(HeapObject* obj) {
+ RLYSTC uint32_t Hash(HeapObject* obj) {
return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
}
- static void* Key(HeapObject* obj) {
+ RLYSTC void* Key(HeapObject* obj) {
return reinterpret_cast<void*>(obj->address());
}
- static void* Value(int v) {
+ RLYSTC void* Value(int v) {
return reinterpret_cast<void*>(v);
}
@@ -398,7 +402,8 @@ class SerializationAddressMapper {
};
-class Serializer : public SerializerDeserializer {
+// There can be only one serializer per V8 process.
+STATIC_CLASS Serializer : public SerializerDeserializer {
public:
explicit Serializer(SnapshotByteSink* sink);
~Serializer();
@@ -410,25 +415,25 @@ class Serializer : public SerializerDeserializer {
return fullness_[space];
}
- static void Enable() {
+ RLYSTC void Enable() {
if (!serialization_enabled_) {
ASSERT(!too_late_to_enable_now_);
}
serialization_enabled_ = true;
}
- static void Disable() { serialization_enabled_ = false; }
+ RLYSTC void Disable() { serialization_enabled_ = false; }
// Call this when you have made use of the fact that there is no serialization
// going on.
- static void TooLateToEnableNow() { too_late_to_enable_now_ = true; }
- static bool enabled() { return serialization_enabled_; }
+ RLYSTC void TooLateToEnableNow() { too_late_to_enable_now_ = true; }
+ RLYSTC bool enabled() { return serialization_enabled_; }
SerializationAddressMapper* address_mapper() { return &address_mapper_; }
#ifdef DEBUG
virtual void Synchronize(const char* tag);
#endif
protected:
- static const int kInvalidRootIndex = -1;
+ RLYSTC const int kInvalidRootIndex = -1;
virtual int RootIndex(HeapObject* heap_object) = 0;
virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0;
@@ -483,11 +488,11 @@ class Serializer : public SerializerDeserializer {
// object space it may return kLargeCode or kLargeFixedArray in order
// to indicate to the deserializer what kind of large object allocation
// to make.
- static int SpaceOfObject(HeapObject* object);
+ RLYSTC int SpaceOfObject(HeapObject* object);
// This just returns the space of the object. It will return LO_SPACE
// for all large objects since you can't check the type of the object
// once the map has been used for the serialization address.
- static int SpaceOfAlreadySerializedObject(HeapObject* object);
+ RLYSTC int SpaceOfAlreadySerializedObject(HeapObject* object);
int Allocate(int space, int size, bool* new_page_started);
int EncodeExternalReference(Address addr) {
return external_reference_encoder_->Encode(addr);
@@ -501,9 +506,9 @@ class Serializer : public SerializerDeserializer {
SnapshotByteSink* sink_;
int current_root_index_;
ExternalReferenceEncoder* external_reference_encoder_;
- static bool serialization_enabled_;
+ RLYSTC bool serialization_enabled_;
// Did we already make use of the fact that serialization was not enabled?
- static bool too_late_to_enable_now_;
+ RLYSTC bool too_late_to_enable_now_;
int large_object_total_;
SerializationAddressMapper address_mapper_;
@@ -539,7 +544,7 @@ class PartialSerializer : public Serializer {
ASSERT(!o->IsScript());
return o->IsString() || o->IsSharedFunctionInfo() ||
o->IsHeapNumber() || o->IsCode() ||
- o->map() == Heap::fixed_cow_array_map();
+ o->map() == HEAP->fixed_cow_array_map();
}
private:
@@ -555,7 +560,7 @@ class StartupSerializer : public Serializer {
// strong roots have been serialized we can create a partial snapshot
// which will repopulate the cache with objects neede by that partial
// snapshot.
- partial_snapshot_cache_length_ = 0;
+ Isolate::Current()->set_serialize_partial_snapshot_cache_length(0);
}
// Serialize the current state of the heap. The order is:
// 1) Strong references.
diff --git a/src/small-pointer-list.h b/src/small-pointer-list.h
new file mode 100644
index 00000000..6291d9ee
--- /dev/null
+++ b/src/small-pointer-list.h
@@ -0,0 +1,163 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SMALL_POINTER_LIST_H_
+#define V8_SMALL_POINTER_LIST_H_
+
+#include "checks.h"
+#include "v8globals.h"
+#include "zone.h"
+
+namespace v8 {
+namespace internal {
+
+// SmallPointerList is a list optimized for storing no or just a
+// single value. When more values are given it falls back to ZoneList.
+//
+// The interface tries to be as close to List from list.h as possible.
+template <typename T>
+class SmallPointerList {
+ public:
+ SmallPointerList() : data_(kEmptyTag) {}
+
+ bool is_empty() const { return length() == 0; }
+
+ int length() const {
+ if ((data_ & kTagMask) == kEmptyTag) return 0;
+ if ((data_ & kTagMask) == kSingletonTag) return 1;
+ return list()->length();
+ }
+
+ void Add(T* pointer) {
+ ASSERT(IsAligned(reinterpret_cast<intptr_t>(pointer), kPointerAlignment));
+ if ((data_ & kTagMask) == kEmptyTag) {
+ data_ = reinterpret_cast<intptr_t>(pointer) | kSingletonTag;
+ return;
+ }
+ if ((data_ & kTagMask) == kSingletonTag) {
+ PointerList* list = new PointerList(2);
+ list->Add(single_value());
+ list->Add(pointer);
+ ASSERT(IsAligned(reinterpret_cast<intptr_t>(list), kPointerAlignment));
+ data_ = reinterpret_cast<intptr_t>(list) | kListTag;
+ return;
+ }
+ list()->Add(pointer);
+ }
+
+ // Note: returns T* and not T*& (unlike List from list.h).
+ // This makes the implementation simpler and more const correct.
+ T* at(int i) const {
+ ASSERT((data_ & kTagMask) != kEmptyTag);
+ if ((data_ & kTagMask) == kSingletonTag) {
+ ASSERT(i == 0);
+ return single_value();
+ }
+ return list()->at(i);
+ }
+
+ // See the note above.
+ T* operator[](int i) const { return at(i); }
+
+ // Remove the given element from the list (if present).
+ void RemoveElement(T* pointer) {
+ if ((data_ & kTagMask) == kEmptyTag) return;
+ if ((data_ & kTagMask) == kSingletonTag) {
+ if (pointer == single_value()) {
+ data_ = kEmptyTag;
+ }
+ return;
+ }
+ list()->RemoveElement(pointer);
+ }
+
+ T* RemoveLast() {
+ ASSERT((data_ & kTagMask) != kEmptyTag);
+ if ((data_ & kTagMask) == kSingletonTag) {
+ T* result = single_value();
+ data_ = kEmptyTag;
+ return result;
+ }
+ return list()->RemoveLast();
+ }
+
+ void Rewind(int pos) {
+ if ((data_ & kTagMask) == kEmptyTag) {
+ ASSERT(pos == 0);
+ return;
+ }
+ if ((data_ & kTagMask) == kSingletonTag) {
+ ASSERT(pos == 0 || pos == 1);
+ if (pos == 0) {
+ data_ = kEmptyTag;
+ }
+ return;
+ }
+ list()->Rewind(pos);
+ }
+
+ int CountOccurrences(T* pointer, int start, int end) const {
+ if ((data_ & kTagMask) == kEmptyTag) return 0;
+ if ((data_ & kTagMask) == kSingletonTag) {
+ if (start == 0 && end >= 0) {
+ return (single_value() == pointer) ? 1 : 0;
+ }
+ return 0;
+ }
+ return list()->CountOccurrences(pointer, start, end);
+ }
+
+ private:
+ typedef ZoneList<T*> PointerList;
+
+ static const intptr_t kEmptyTag = 1;
+ static const intptr_t kSingletonTag = 0;
+ static const intptr_t kListTag = 2;
+ static const intptr_t kTagMask = 3;
+ static const intptr_t kValueMask = ~kTagMask;
+
+ STATIC_ASSERT(kTagMask + 1 <= kPointerAlignment);
+
+ T* single_value() const {
+ ASSERT((data_ & kTagMask) == kSingletonTag);
+ STATIC_ASSERT(kSingletonTag == 0);
+ return reinterpret_cast<T*>(data_);
+ }
+
+ PointerList* list() const {
+ ASSERT((data_ & kTagMask) == kListTag);
+ return reinterpret_cast<PointerList*>(data_ & kValueMask);
+ }
+
+ intptr_t data_;
+
+ DISALLOW_COPY_AND_ASSIGN(SmallPointerList);
+};
+
+} } // namespace v8::internal
+
+#endif // V8_SMALL_POINTER_LIST_H_
diff --git a/src/snapshot-common.cc b/src/snapshot-common.cc
index f1106e13..7f828958 100644
--- a/src/snapshot-common.cc
+++ b/src/snapshot-common.cc
@@ -64,7 +64,7 @@ Handle<Context> Snapshot::NewContextFromSnapshot() {
if (context_size_ == 0) {
return Handle<Context>();
}
- Heap::ReserveSpace(new_space_used_,
+ HEAP->ReserveSpace(new_space_used_,
pointer_space_used_,
data_space_used_,
code_space_used_,
diff --git a/src/snapshot.h b/src/snapshot.h
index 9f77c20f..bedd186e 100644
--- a/src/snapshot.h
+++ b/src/snapshot.h
@@ -25,13 +25,15 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "isolate.h"
+
#ifndef V8_SNAPSHOT_H_
#define V8_SNAPSHOT_H_
namespace v8 {
namespace internal {
-class Snapshot {
+STATIC_CLASS Snapshot {
public:
// Initialize the VM from the given snapshot file. If snapshot_file is
// NULL, use the internal snapshot instead. Returns false if no snapshot
diff --git a/src/spaces-inl.h b/src/spaces-inl.h
index b5ee1e40..070f9705 100644
--- a/src/spaces-inl.h
+++ b/src/spaces-inl.h
@@ -28,8 +28,9 @@
#ifndef V8_SPACES_INL_H_
#define V8_SPACES_INL_H_
-#include "memory.h"
+#include "isolate.h"
#include "spaces.h"
+#include "v8memory.h"
namespace v8 {
namespace internal {
@@ -56,18 +57,18 @@ Page* PageIterator::next() {
// Page
Page* Page::next_page() {
- return MemoryAllocator::GetNextPage(this);
+ return heap_->isolate()->memory_allocator()->GetNextPage(this);
}
Address Page::AllocationTop() {
- PagedSpace* owner = MemoryAllocator::PageOwner(this);
+ PagedSpace* owner = heap_->isolate()->memory_allocator()->PageOwner(this);
return owner->PageAllocationTop(this);
}
Address Page::AllocationWatermark() {
- PagedSpace* owner = MemoryAllocator::PageOwner(this);
+ PagedSpace* owner = heap_->isolate()->memory_allocator()->PageOwner(this);
if (this == owner->AllocationTopPage()) {
return owner->top();
}
@@ -82,7 +83,7 @@ uint32_t Page::AllocationWatermarkOffset() {
void Page::SetAllocationWatermark(Address allocation_watermark) {
- if ((Heap::gc_state() == Heap::SCAVENGE) && IsWatermarkValid()) {
+ if ((heap_->gc_state() == Heap::SCAVENGE) && IsWatermarkValid()) {
// When iterating intergenerational references during scavenge
// we might decide to promote an encountered young object.
// We will allocate a space for such an object and put it
@@ -219,23 +220,26 @@ void Page::ClearRegionMarks(Address start, Address end, bool reaches_limit) {
}
-void Page::FlipMeaningOfInvalidatedWatermarkFlag() {
- watermark_invalidated_mark_ ^= 1 << WATERMARK_INVALIDATED;
+void Page::FlipMeaningOfInvalidatedWatermarkFlag(Heap* heap) {
+ heap->page_watermark_invalidated_mark_ ^= 1 << WATERMARK_INVALIDATED;
}
bool Page::IsWatermarkValid() {
- return (flags_ & (1 << WATERMARK_INVALIDATED)) != watermark_invalidated_mark_;
+ return (flags_ & (1 << WATERMARK_INVALIDATED)) !=
+ heap_->page_watermark_invalidated_mark_;
}
void Page::InvalidateWatermark(bool value) {
if (value) {
flags_ = (flags_ & ~(1 << WATERMARK_INVALIDATED)) |
- watermark_invalidated_mark_;
+ heap_->page_watermark_invalidated_mark_;
} else {
- flags_ = (flags_ & ~(1 << WATERMARK_INVALIDATED)) |
- (watermark_invalidated_mark_ ^ (1 << WATERMARK_INVALIDATED));
+ flags_ =
+ (flags_ & ~(1 << WATERMARK_INVALIDATED)) |
+ (heap_->page_watermark_invalidated_mark_ ^
+ (1 << WATERMARK_INVALIDATED));
}
ASSERT(IsWatermarkValid() == !value);
@@ -264,7 +268,7 @@ void Page::ClearPageFlags() {
void Page::ClearGCFields() {
InvalidateWatermark(true);
SetAllocationWatermark(ObjectAreaStart());
- if (Heap::gc_state() == Heap::SCAVENGE) {
+ if (heap_->gc_state() == Heap::SCAVENGE) {
SetCachedAllocationWatermark(ObjectAreaStart());
}
SetRegionMarks(kAllRegionsCleanMarks);
@@ -308,6 +312,7 @@ void MemoryAllocator::ChunkInfo::init(Address a, size_t s, PagedSpace* o) {
size_ = s;
owner_ = o;
executable_ = (o == NULL) ? NOT_EXECUTABLE : o->executable();
+ owner_identity_ = (o == NULL) ? FIRST_SPACE : o->identity();
}
@@ -408,15 +413,7 @@ void MemoryAllocator::UnprotectChunkFromPage(Page* page) {
bool PagedSpace::Contains(Address addr) {
Page* p = Page::FromAddress(addr);
if (!p->is_valid()) return false;
- return MemoryAllocator::IsPageInSpace(p, this);
-}
-
-
-bool PagedSpace::SafeContains(Address addr) {
- if (!MemoryAllocator::SafeIsInAPageChunk(addr)) return false;
- Page* p = Page::FromAddress(addr);
- if (!p->is_valid()) return false;
- return MemoryAllocator::IsPageInSpace(p, this);
+ return heap()->isolate()->memory_allocator()->IsPageInSpace(p, this);
}
@@ -477,7 +474,9 @@ Address LargeObjectChunk::GetStartAddress() {
void LargeObjectChunk::Free(Executability executable) {
- MemoryAllocator::FreeRawMemory(address(), size(), executable);
+ Isolate* isolate =
+ Page::FromAddress(RoundUp(address(), Page::kPageSize))->heap_->isolate();
+ isolate->memory_allocator()->FreeRawMemory(address(), size(), executable);
}
// -----------------------------------------------------------------------------
@@ -501,6 +500,12 @@ MaybeObject* NewSpace::AllocateRawInternal(int size_in_bytes,
}
+intptr_t LargeObjectSpace::Available() {
+ return LargeObjectChunk::ObjectSizeFor(
+ heap()->isolate()->memory_allocator()->Available());
+}
+
+
template <typename StringType>
void NewSpace::ShrinkStringAtAllocationBoundary(String* string, int length) {
ASSERT(length <= string->length());
@@ -514,9 +519,9 @@ void NewSpace::ShrinkStringAtAllocationBoundary(String* string, int length) {
bool FreeListNode::IsFreeListNode(HeapObject* object) {
- return object->map() == Heap::raw_unchecked_byte_array_map()
- || object->map() == Heap::raw_unchecked_one_pointer_filler_map()
- || object->map() == Heap::raw_unchecked_two_pointer_filler_map();
+ return object->map() == HEAP->raw_unchecked_byte_array_map()
+ || object->map() == HEAP->raw_unchecked_one_pointer_filler_map()
+ || object->map() == HEAP->raw_unchecked_two_pointer_filler_map();
}
} } // namespace v8::internal
diff --git a/src/spaces.cc b/src/spaces.cc
index a586fbf9..20700e1d 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -42,8 +42,6 @@ namespace internal {
&& (info).top <= (space).high() \
&& (info).limit == (space).high())
-intptr_t Page::watermark_invalidated_mark_ = 1 << Page::WATERMARK_INVALIDATED;
-
// ----------------------------------------------------------------------------
// HeapObjectIterator
@@ -149,10 +147,14 @@ PageIterator::PageIterator(PagedSpace* space, Mode mode) : space_(space) {
// -----------------------------------------------------------------------------
// CodeRange
-List<CodeRange::FreeBlock> CodeRange::free_list_(0);
-List<CodeRange::FreeBlock> CodeRange::allocation_list_(0);
-int CodeRange::current_allocation_block_index_ = 0;
-VirtualMemory* CodeRange::code_range_ = NULL;
+
+CodeRange::CodeRange()
+ : code_range_(NULL),
+ free_list_(0),
+ allocation_list_(0),
+ current_allocation_block_index_(0),
+ isolate_(NULL) {
+}
bool CodeRange::Setup(const size_t requested) {
@@ -168,7 +170,7 @@ bool CodeRange::Setup(const size_t requested) {
// We are sure that we have mapped a block of requested addresses.
ASSERT(code_range_->size() == requested);
- LOG(NewEvent("CodeRange", code_range_->address(), requested));
+ LOG(isolate_, NewEvent("CodeRange", code_range_->address(), requested));
allocation_list_.Add(FreeBlock(code_range_->address(), code_range_->size()));
current_allocation_block_index_ = 0;
return true;
@@ -271,24 +273,24 @@ void CodeRange::TearDown() {
// -----------------------------------------------------------------------------
// MemoryAllocator
//
-intptr_t MemoryAllocator::capacity_ = 0;
-intptr_t MemoryAllocator::capacity_executable_ = 0;
-intptr_t MemoryAllocator::size_ = 0;
-intptr_t MemoryAllocator::size_executable_ = 0;
-
-List<MemoryAllocator::MemoryAllocationCallbackRegistration>
- MemoryAllocator::memory_allocation_callbacks_;
-
-VirtualMemory* MemoryAllocator::initial_chunk_ = NULL;
// 270 is an estimate based on the static default heap size of a pair of 256K
// semispaces and a 64M old generation.
const int kEstimatedNumberOfChunks = 270;
-List<MemoryAllocator::ChunkInfo> MemoryAllocator::chunks_(
- kEstimatedNumberOfChunks);
-List<int> MemoryAllocator::free_chunk_ids_(kEstimatedNumberOfChunks);
-int MemoryAllocator::max_nof_chunks_ = 0;
-int MemoryAllocator::top_ = 0;
+
+
+MemoryAllocator::MemoryAllocator()
+ : capacity_(0),
+ capacity_executable_(0),
+ size_(0),
+ size_executable_(0),
+ initial_chunk_(NULL),
+ chunks_(kEstimatedNumberOfChunks),
+ free_chunk_ids_(kEstimatedNumberOfChunks),
+ max_nof_chunks_(0),
+ top_(0),
+ isolate_(NULL) {
+}
void MemoryAllocator::Push(int free_chunk_id) {
@@ -334,11 +336,6 @@ bool MemoryAllocator::Setup(intptr_t capacity, intptr_t capacity_executable) {
}
-bool MemoryAllocator::SafeIsInAPageChunk(Address addr) {
- return InInitialChunk(addr) || InAllocatedChunks(addr);
-}
-
-
void MemoryAllocator::TearDown() {
for (int i = 0; i < max_nof_chunks_; i++) {
if (chunks_[i].address() != NULL) DeleteChunk(i);
@@ -347,15 +344,11 @@ void MemoryAllocator::TearDown() {
free_chunk_ids_.Clear();
if (initial_chunk_ != NULL) {
- LOG(DeleteEvent("InitialChunk", initial_chunk_->address()));
+ LOG(isolate_, DeleteEvent("InitialChunk", initial_chunk_->address()));
delete initial_chunk_;
initial_chunk_ = NULL;
}
- FreeChunkTables(&chunk_table_[0],
- kChunkTableTopLevelEntries,
- kChunkTableLevels);
-
ASSERT(top_ == max_nof_chunks_); // all chunks are free
top_ = 0;
capacity_ = 0;
@@ -365,22 +358,6 @@ void MemoryAllocator::TearDown() {
}
-void MemoryAllocator::FreeChunkTables(uintptr_t* array, int len, int level) {
- for (int i = 0; i < len; i++) {
- if (array[i] != kUnusedChunkTableEntry) {
- uintptr_t* subarray = reinterpret_cast<uintptr_t*>(array[i]);
- if (level > 1) {
- array[i] = kUnusedChunkTableEntry;
- FreeChunkTables(subarray, 1 << kChunkTableBitsPerLevel, level - 1);
- } else {
- array[i] = kUnusedChunkTableEntry;
- }
- delete[] subarray;
- }
- }
-}
-
-
void* MemoryAllocator::AllocateRawMemory(const size_t requested,
size_t* allocated,
Executability executable) {
@@ -393,14 +370,15 @@ void* MemoryAllocator::AllocateRawMemory(const size_t requested,
// Check executable memory limit.
if (size_executable_ + requested >
static_cast<size_t>(capacity_executable_)) {
- LOG(StringEvent("MemoryAllocator::AllocateRawMemory",
+ LOG(isolate_,
+ StringEvent("MemoryAllocator::AllocateRawMemory",
"V8 Executable Allocation capacity exceeded"));
return NULL;
}
// Allocate executable memory either from code range or from the
// OS.
- if (CodeRange::exists()) {
- mem = CodeRange::AllocateRawMemory(requested, allocated);
+ if (isolate_->code_range()->exists()) {
+ mem = isolate_->code_range()->AllocateRawMemory(requested, allocated);
} else {
mem = OS::Allocate(requested, allocated, true);
}
@@ -415,7 +393,7 @@ void* MemoryAllocator::AllocateRawMemory(const size_t requested,
#ifdef DEBUG
ZapBlock(reinterpret_cast<Address>(mem), alloced);
#endif
- Counters::memory_allocated.Increment(alloced);
+ isolate_->counters()->memory_allocated()->Increment(alloced);
return mem;
}
@@ -426,12 +404,12 @@ void MemoryAllocator::FreeRawMemory(void* mem,
#ifdef DEBUG
ZapBlock(reinterpret_cast<Address>(mem), length);
#endif
- if (CodeRange::contains(static_cast<Address>(mem))) {
- CodeRange::FreeRawMemory(mem, length);
+ if (isolate_->code_range()->contains(static_cast<Address>(mem))) {
+ isolate_->code_range()->FreeRawMemory(mem, length);
} else {
OS::Free(mem, length);
}
- Counters::memory_allocated.Decrement(static_cast<int>(length));
+ isolate_->counters()->memory_allocated()->Decrement(static_cast<int>(length));
size_ -= static_cast<int>(length);
if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length);
@@ -498,7 +476,8 @@ void* MemoryAllocator::ReserveInitialChunk(const size_t requested) {
// We are sure that we have mapped a block of requested addresses.
ASSERT(initial_chunk_->size() == requested);
- LOG(NewEvent("InitialChunk", initial_chunk_->address(), requested));
+ LOG(isolate_,
+ NewEvent("InitialChunk", initial_chunk_->address(), requested));
size_ += static_cast<int>(requested);
return initial_chunk_->address();
}
@@ -522,14 +501,14 @@ Page* MemoryAllocator::AllocatePages(int requested_pages,
void* chunk = AllocateRawMemory(chunk_size, &chunk_size, owner->executable());
if (chunk == NULL) return Page::FromAddress(NULL);
- LOG(NewEvent("PagedChunk", chunk, chunk_size));
+ LOG(isolate_, NewEvent("PagedChunk", chunk, chunk_size));
*allocated_pages = PagesInChunk(static_cast<Address>(chunk), chunk_size);
// We may 'lose' a page due to alignment.
ASSERT(*allocated_pages >= kPagesPerChunk - 1);
if (*allocated_pages == 0) {
FreeRawMemory(chunk, chunk_size, owner->executable());
- LOG(DeleteEvent("PagedChunk", chunk));
+ LOG(isolate_, DeleteEvent("PagedChunk", chunk));
return Page::FromAddress(NULL);
}
@@ -540,8 +519,6 @@ Page* MemoryAllocator::AllocatePages(int requested_pages,
PerformAllocationCallback(space, kAllocationActionAllocate, chunk_size);
Page* new_pages = InitializePagesInChunk(chunk_id, *allocated_pages, owner);
- AddToAllocatedChunks(static_cast<Address>(chunk), chunk_size);
-
return new_pages;
}
@@ -560,7 +537,7 @@ Page* MemoryAllocator::CommitPages(Address start, size_t size,
#ifdef DEBUG
ZapBlock(start, size);
#endif
- Counters::memory_allocated.Increment(static_cast<int>(size));
+ isolate_->counters()->memory_allocated()->Increment(static_cast<int>(size));
// So long as we correctly overestimated the number of chunks we should not
// run out of chunk ids.
@@ -584,7 +561,7 @@ bool MemoryAllocator::CommitBlock(Address start,
#ifdef DEBUG
ZapBlock(start, size);
#endif
- Counters::memory_allocated.Increment(static_cast<int>(size));
+ isolate_->counters()->memory_allocated()->Increment(static_cast<int>(size));
return true;
}
@@ -597,7 +574,7 @@ bool MemoryAllocator::UncommitBlock(Address start, size_t size) {
ASSERT(InInitialChunk(start + size - 1));
if (!initial_chunk_->Uncommit(start, size)) return false;
- Counters::memory_allocated.Decrement(static_cast<int>(size));
+ isolate_->counters()->memory_allocated()->Decrement(static_cast<int>(size));
return true;
}
@@ -628,6 +605,7 @@ Page* MemoryAllocator::InitializePagesInChunk(int chunk_id, int pages_in_chunk,
Address page_addr = low;
for (int i = 0; i < pages_in_chunk; i++) {
Page* p = Page::FromAddress(page_addr);
+ p->heap_ = owner->heap();
p->opaque_header = OffsetFrom(page_addr + Page::kPageSize) | chunk_id;
p->InvalidateWatermark(true);
p->SetIsLargeObjectPage(false);
@@ -697,11 +675,11 @@ void MemoryAllocator::DeleteChunk(int chunk_id) {
// TODO(1240712): VirtualMemory::Uncommit has a return value which
// is ignored here.
initial_chunk_->Uncommit(c.address(), c.size());
- Counters::memory_allocated.Decrement(static_cast<int>(c.size()));
+ Counters* counters = isolate_->counters();
+ counters->memory_allocated()->Decrement(static_cast<int>(c.size()));
} else {
- RemoveFromAllocatedChunks(c.address(), c.size());
- LOG(DeleteEvent("PagedChunk", c.address()));
- ObjectSpace space = static_cast<ObjectSpace>(1 << c.owner()->identity());
+ LOG(isolate_, DeleteEvent("PagedChunk", c.address()));
+ ObjectSpace space = static_cast<ObjectSpace>(1 << c.owner_identity());
size_t size = c.size();
FreeRawMemory(c.address(), size, c.executable());
PerformAllocationCallback(space, kAllocationActionFree, size);
@@ -813,131 +791,14 @@ Page* MemoryAllocator::RelinkPagesInChunk(int chunk_id,
}
-void MemoryAllocator::AddToAllocatedChunks(Address addr, intptr_t size) {
- ASSERT(size == kChunkSize);
- uintptr_t int_address = reinterpret_cast<uintptr_t>(addr);
- AddChunkUsingAddress(int_address, int_address);
- AddChunkUsingAddress(int_address, int_address + size - 1);
-}
-
-
-void MemoryAllocator::AddChunkUsingAddress(uintptr_t chunk_start,
- uintptr_t chunk_index_base) {
- uintptr_t* fine_grained = AllocatedChunksFinder(
- chunk_table_,
- chunk_index_base,
- kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel,
- kCreateTablesAsNeeded);
- int index = FineGrainedIndexForAddress(chunk_index_base);
- if (fine_grained[index] != kUnusedChunkTableEntry) index++;
- ASSERT(fine_grained[index] == kUnusedChunkTableEntry);
- fine_grained[index] = chunk_start;
-}
-
-
-void MemoryAllocator::RemoveFromAllocatedChunks(Address addr, intptr_t size) {
- ASSERT(size == kChunkSize);
- uintptr_t int_address = reinterpret_cast<uintptr_t>(addr);
- RemoveChunkFoundUsingAddress(int_address, int_address);
- RemoveChunkFoundUsingAddress(int_address, int_address + size - 1);
-}
-
-
-void MemoryAllocator::RemoveChunkFoundUsingAddress(
- uintptr_t chunk_start,
- uintptr_t chunk_index_base) {
- uintptr_t* fine_grained = AllocatedChunksFinder(
- chunk_table_,
- chunk_index_base,
- kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel,
- kDontCreateTables);
- // Can't remove an entry that's not there.
- ASSERT(fine_grained != kUnusedChunkTableEntry);
- int index = FineGrainedIndexForAddress(chunk_index_base);
- ASSERT(fine_grained[index] != kUnusedChunkTableEntry);
- if (fine_grained[index] != chunk_start) {
- index++;
- ASSERT(fine_grained[index] == chunk_start);
- fine_grained[index] = kUnusedChunkTableEntry;
- } else {
- // If only one of the entries is used it must be the first, since
- // InAllocatedChunks relies on that. Move things around so that this is
- // the case.
- fine_grained[index] = fine_grained[index + 1];
- fine_grained[index + 1] = kUnusedChunkTableEntry;
- }
-}
-
-
-bool MemoryAllocator::InAllocatedChunks(Address addr) {
- uintptr_t int_address = reinterpret_cast<uintptr_t>(addr);
- uintptr_t* fine_grained = AllocatedChunksFinder(
- chunk_table_,
- int_address,
- kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel,
- kDontCreateTables);
- if (fine_grained == NULL) return false;
- int index = FineGrainedIndexForAddress(int_address);
- if (fine_grained[index] == kUnusedChunkTableEntry) return false;
- uintptr_t entry = fine_grained[index];
- if (entry <= int_address && entry + kChunkSize > int_address) return true;
- index++;
- if (fine_grained[index] == kUnusedChunkTableEntry) return false;
- entry = fine_grained[index];
- if (entry <= int_address && entry + kChunkSize > int_address) return true;
- return false;
-}
-
-
-uintptr_t* MemoryAllocator::AllocatedChunksFinder(
- uintptr_t* table,
- uintptr_t address,
- int bit_position,
- CreateTables create_as_needed) {
- if (bit_position == kChunkSizeLog2) {
- return table;
- }
- ASSERT(bit_position >= kChunkSizeLog2 + kChunkTableBitsPerLevel);
- int index =
- ((address >> bit_position) &
- ((V8_INTPTR_C(1) << kChunkTableBitsPerLevel) - 1));
- uintptr_t more_fine_grained_address =
- address & ((V8_INTPTR_C(1) << bit_position) - 1);
- ASSERT((table == chunk_table_ && index < kChunkTableTopLevelEntries) ||
- (table != chunk_table_ && index < 1 << kChunkTableBitsPerLevel));
- uintptr_t* more_fine_grained_table =
- reinterpret_cast<uintptr_t*>(table[index]);
- if (more_fine_grained_table == kUnusedChunkTableEntry) {
- if (create_as_needed == kDontCreateTables) return NULL;
- int words_needed = 1 << kChunkTableBitsPerLevel;
- if (bit_position == kChunkTableBitsPerLevel + kChunkSizeLog2) {
- words_needed =
- (1 << kChunkTableBitsPerLevel) * kChunkTableFineGrainedWordsPerEntry;
- }
- more_fine_grained_table = new uintptr_t[words_needed];
- for (int i = 0; i < words_needed; i++) {
- more_fine_grained_table[i] = kUnusedChunkTableEntry;
- }
- table[index] = reinterpret_cast<uintptr_t>(more_fine_grained_table);
- }
- return AllocatedChunksFinder(
- more_fine_grained_table,
- more_fine_grained_address,
- bit_position - kChunkTableBitsPerLevel,
- create_as_needed);
-}
-
-
-uintptr_t MemoryAllocator::chunk_table_[kChunkTableTopLevelEntries];
-
-
// -----------------------------------------------------------------------------
// PagedSpace implementation
-PagedSpace::PagedSpace(intptr_t max_capacity,
+PagedSpace::PagedSpace(Heap* heap,
+ intptr_t max_capacity,
AllocationSpace id,
Executability executable)
- : Space(id, executable) {
+ : Space(heap, id, executable) {
max_capacity_ = (RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize)
* Page::kObjectAreaSize;
accounting_stats_.Clear();
@@ -958,15 +819,17 @@ bool PagedSpace::Setup(Address start, size_t size) {
// contain at least one page, ignore it and allocate instead.
int pages_in_chunk = PagesInChunk(start, size);
if (pages_in_chunk > 0) {
- first_page_ = MemoryAllocator::CommitPages(RoundUp(start, Page::kPageSize),
- Page::kPageSize * pages_in_chunk,
- this, &num_pages);
+ first_page_ = Isolate::Current()->memory_allocator()->CommitPages(
+ RoundUp(start, Page::kPageSize),
+ Page::kPageSize * pages_in_chunk,
+ this, &num_pages);
} else {
int requested_pages =
Min(MemoryAllocator::kPagesPerChunk,
static_cast<int>(max_capacity_ / Page::kObjectAreaSize));
first_page_ =
- MemoryAllocator::AllocatePages(requested_pages, &num_pages, this);
+ Isolate::Current()->memory_allocator()->AllocatePages(
+ requested_pages, &num_pages, this);
if (!first_page_->is_valid()) return false;
}
@@ -999,7 +862,7 @@ bool PagedSpace::HasBeenSetup() {
void PagedSpace::TearDown() {
- MemoryAllocator::FreeAllPages(this);
+ Isolate::Current()->memory_allocator()->FreeAllPages(this);
first_page_ = NULL;
accounting_stats_.Clear();
}
@@ -1010,8 +873,9 @@ void PagedSpace::TearDown() {
void PagedSpace::Protect() {
Page* page = first_page_;
while (page->is_valid()) {
- MemoryAllocator::ProtectChunkFromPage(page);
- page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page();
+ Isolate::Current()->memory_allocator()->ProtectChunkFromPage(page);
+ page = Isolate::Current()->memory_allocator()->
+ FindLastPageInSameChunk(page)->next_page();
}
}
@@ -1019,8 +883,9 @@ void PagedSpace::Protect() {
void PagedSpace::Unprotect() {
Page* page = first_page_;
while (page->is_valid()) {
- MemoryAllocator::UnprotectChunkFromPage(page);
- page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page();
+ Isolate::Current()->memory_allocator()->UnprotectChunkFromPage(page);
+ page = Isolate::Current()->memory_allocator()->
+ FindLastPageInSameChunk(page)->next_page();
}
}
@@ -1038,7 +903,7 @@ void PagedSpace::MarkAllPagesClean() {
MaybeObject* PagedSpace::FindObject(Address addr) {
// Note: this function can only be called before or after mark-compact GC
// because it accesses map pointers.
- ASSERT(!MarkCompactCollector::in_use());
+ ASSERT(!heap()->mark_compact_collector()->in_use());
if (!Contains(addr)) return Failure::Exception();
@@ -1158,13 +1023,14 @@ bool PagedSpace::Expand(Page* last_page) {
if (available_pages < MemoryAllocator::kPagesPerChunk) return false;
int desired_pages = Min(available_pages, MemoryAllocator::kPagesPerChunk);
- Page* p = MemoryAllocator::AllocatePages(desired_pages, &desired_pages, this);
+ Page* p = heap()->isolate()->memory_allocator()->AllocatePages(
+ desired_pages, &desired_pages, this);
if (!p->is_valid()) return false;
accounting_stats_.ExpandSpace(desired_pages * Page::kObjectAreaSize);
ASSERT(Capacity() <= max_capacity_);
- MemoryAllocator::SetNextPage(last_page, p);
+ heap()->isolate()->memory_allocator()->SetNextPage(last_page, p);
// Sequentially clear region marks of new pages and and cache the
// new last page in the space.
@@ -1207,8 +1073,9 @@ void PagedSpace::Shrink() {
}
// Free pages after top_page.
- Page* p = MemoryAllocator::FreePages(top_page->next_page());
- MemoryAllocator::SetNextPage(top_page, p);
+ Page* p = heap()->isolate()->memory_allocator()->
+ FreePages(top_page->next_page());
+ heap()->isolate()->memory_allocator()->SetNextPage(top_page, p);
// Find out how many pages we failed to free and update last_page_.
// Please note pages can only be freed in whole chunks.
@@ -1230,7 +1097,8 @@ bool PagedSpace::EnsureCapacity(int capacity) {
Page* last_page = AllocationTopPage();
Page* next_page = last_page->next_page();
while (next_page->is_valid()) {
- last_page = MemoryAllocator::FindLastPageInSameChunk(next_page);
+ last_page = heap()->isolate()->memory_allocator()->
+ FindLastPageInSameChunk(next_page);
next_page = last_page->next_page();
}
@@ -1239,7 +1107,8 @@ bool PagedSpace::EnsureCapacity(int capacity) {
if (!Expand(last_page)) return false;
ASSERT(last_page->next_page()->is_valid());
last_page =
- MemoryAllocator::FindLastPageInSameChunk(last_page->next_page());
+ heap()->isolate()->memory_allocator()->FindLastPageInSameChunk(
+ last_page->next_page());
} while (Capacity() < capacity);
return true;
@@ -1259,7 +1128,7 @@ void PagedSpace::Verify(ObjectVisitor* visitor) {
// space.
ASSERT(allocation_info_.VerifyPagedAllocation());
Page* top_page = Page::FromAllocationTop(allocation_info_.top);
- ASSERT(MemoryAllocator::IsPageInSpace(top_page, this));
+ ASSERT(heap()->isolate()->memory_allocator()->IsPageInSpace(top_page, this));
// Loop over all the pages.
bool above_allocation_top = false;
@@ -1284,7 +1153,7 @@ void PagedSpace::Verify(ObjectVisitor* visitor) {
// be in map space.
Map* map = object->map();
ASSERT(map->IsMap());
- ASSERT(Heap::map_space()->Contains(map));
+ ASSERT(heap()->map_space()->Contains(map));
// Perform space-specific object verification.
VerifyObject(object);
@@ -1320,8 +1189,8 @@ bool NewSpace::Setup(Address start, int size) {
// start and size. The provided space is divided into two semi-spaces.
// To support fast containment testing in the new space, the size of
// this chunk must be a power of two and it must be aligned to its size.
- int initial_semispace_capacity = Heap::InitialSemiSpaceSize();
- int maximum_semispace_capacity = Heap::MaxSemiSpaceSize();
+ int initial_semispace_capacity = heap()->InitialSemiSpaceSize();
+ int maximum_semispace_capacity = heap()->MaxSemiSpaceSize();
ASSERT(initial_semispace_capacity <= maximum_semispace_capacity);
ASSERT(IsPowerOf2(maximum_semispace_capacity));
@@ -1337,7 +1206,7 @@ bool NewSpace::Setup(Address start, int size) {
#undef SET_NAME
#endif
- ASSERT(size == 2 * Heap::ReservedSemiSpaceSize());
+ ASSERT(size == 2 * heap()->ReservedSemiSpaceSize());
ASSERT(IsAddressAligned(start, size, 0));
if (!to_space_.Setup(start,
@@ -1392,16 +1261,16 @@ void NewSpace::TearDown() {
#ifdef ENABLE_HEAP_PROTECTION
void NewSpace::Protect() {
- MemoryAllocator::Protect(ToSpaceLow(), Capacity());
- MemoryAllocator::Protect(FromSpaceLow(), Capacity());
+ heap()->isolate()->memory_allocator()->Protect(ToSpaceLow(), Capacity());
+ heap()->isolate()->memory_allocator()->Protect(FromSpaceLow(), Capacity());
}
void NewSpace::Unprotect() {
- MemoryAllocator::Unprotect(ToSpaceLow(), Capacity(),
- to_space_.executable());
- MemoryAllocator::Unprotect(FromSpaceLow(), Capacity(),
- from_space_.executable());
+ heap()->isolate()->memory_allocator()->Unprotect(ToSpaceLow(), Capacity(),
+ to_space_.executable());
+ heap()->isolate()->memory_allocator()->Unprotect(FromSpaceLow(), Capacity(),
+ from_space_.executable());
}
#endif
@@ -1495,7 +1364,7 @@ void NewSpace::Verify() {
// be in map space.
Map* map = object->map();
ASSERT(map->IsMap());
- ASSERT(Heap::map_space()->Contains(map));
+ ASSERT(heap()->map_space()->Contains(map));
// The object should not be code or a map.
ASSERT(!object->IsMap());
@@ -1520,7 +1389,8 @@ void NewSpace::Verify() {
bool SemiSpace::Commit() {
ASSERT(!is_committed());
- if (!MemoryAllocator::CommitBlock(start_, capacity_, executable())) {
+ if (!heap()->isolate()->memory_allocator()->CommitBlock(
+ start_, capacity_, executable())) {
return false;
}
committed_ = true;
@@ -1530,7 +1400,8 @@ bool SemiSpace::Commit() {
bool SemiSpace::Uncommit() {
ASSERT(is_committed());
- if (!MemoryAllocator::UncommitBlock(start_, capacity_)) {
+ if (!heap()->isolate()->memory_allocator()->UncommitBlock(
+ start_, capacity_)) {
return false;
}
committed_ = false;
@@ -1576,7 +1447,8 @@ bool SemiSpace::Grow() {
int maximum_extra = maximum_capacity_ - capacity_;
int extra = Min(RoundUp(capacity_, static_cast<int>(OS::AllocateAlignment())),
maximum_extra);
- if (!MemoryAllocator::CommitBlock(high(), extra, executable())) {
+ if (!heap()->isolate()->memory_allocator()->CommitBlock(
+ high(), extra, executable())) {
return false;
}
capacity_ += extra;
@@ -1589,7 +1461,8 @@ bool SemiSpace::GrowTo(int new_capacity) {
ASSERT(new_capacity > capacity_);
size_t delta = new_capacity - capacity_;
ASSERT(IsAligned(delta, OS::AllocateAlignment()));
- if (!MemoryAllocator::CommitBlock(high(), delta, executable())) {
+ if (!heap()->isolate()->memory_allocator()->CommitBlock(
+ high(), delta, executable())) {
return false;
}
capacity_ = new_capacity;
@@ -1602,7 +1475,8 @@ bool SemiSpace::ShrinkTo(int new_capacity) {
ASSERT(new_capacity < capacity_);
size_t delta = capacity_ - new_capacity;
ASSERT(IsAligned(delta, OS::AllocateAlignment()));
- if (!MemoryAllocator::UncommitBlock(high() - delta, delta)) {
+ if (!heap()->isolate()->memory_allocator()->UncommitBlock(
+ high() - delta, delta)) {
return false;
}
capacity_ = new_capacity;
@@ -1650,36 +1524,32 @@ void SemiSpaceIterator::Initialize(NewSpace* space, Address start,
#ifdef DEBUG
-// A static array of histogram info for each type.
-static HistogramInfo heap_histograms[LAST_TYPE+1];
-static JSObject::SpillInformation js_spill_information;
-
// heap_histograms is shared, always clear it before using it.
static void ClearHistograms() {
+ Isolate* isolate = Isolate::Current();
// We reset the name each time, though it hasn't changed.
-#define DEF_TYPE_NAME(name) heap_histograms[name].set_name(#name);
+#define DEF_TYPE_NAME(name) isolate->heap_histograms()[name].set_name(#name);
INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
#undef DEF_TYPE_NAME
-#define CLEAR_HISTOGRAM(name) heap_histograms[name].clear();
+#define CLEAR_HISTOGRAM(name) isolate->heap_histograms()[name].clear();
INSTANCE_TYPE_LIST(CLEAR_HISTOGRAM)
#undef CLEAR_HISTOGRAM
- js_spill_information.Clear();
+ isolate->js_spill_information()->Clear();
}
-static int code_kind_statistics[Code::NUMBER_OF_KINDS];
-
-
static void ClearCodeKindStatistics() {
+ Isolate* isolate = Isolate::Current();
for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) {
- code_kind_statistics[i] = 0;
+ isolate->code_kind_statistics()[i] = 0;
}
}
static void ReportCodeKindStatistics() {
+ Isolate* isolate = Isolate::Current();
const char* table[Code::NUMBER_OF_KINDS] = { NULL };
#define CASE(name) \
@@ -1694,8 +1564,10 @@ static void ReportCodeKindStatistics() {
CASE(BUILTIN);
CASE(LOAD_IC);
CASE(KEYED_LOAD_IC);
+ CASE(KEYED_EXTERNAL_ARRAY_LOAD_IC);
CASE(STORE_IC);
CASE(KEYED_STORE_IC);
+ CASE(KEYED_EXTERNAL_ARRAY_STORE_IC);
CASE(CALL_IC);
CASE(KEYED_CALL_IC);
CASE(BINARY_OP_IC);
@@ -1708,8 +1580,9 @@ static void ReportCodeKindStatistics() {
PrintF("\n Code kind histograms: \n");
for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) {
- if (code_kind_statistics[i] > 0) {
- PrintF(" %-20s: %10d bytes\n", table[i], code_kind_statistics[i]);
+ if (isolate->code_kind_statistics()[i] > 0) {
+ PrintF(" %-20s: %10d bytes\n", table[i],
+ isolate->code_kind_statistics()[i]);
}
}
PrintF("\n");
@@ -1717,14 +1590,16 @@ static void ReportCodeKindStatistics() {
static int CollectHistogramInfo(HeapObject* obj) {
+ Isolate* isolate = Isolate::Current();
InstanceType type = obj->map()->instance_type();
ASSERT(0 <= type && type <= LAST_TYPE);
- ASSERT(heap_histograms[type].name() != NULL);
- heap_histograms[type].increment_number(1);
- heap_histograms[type].increment_bytes(obj->Size());
+ ASSERT(isolate->heap_histograms()[type].name() != NULL);
+ isolate->heap_histograms()[type].increment_number(1);
+ isolate->heap_histograms()[type].increment_bytes(obj->Size());
if (FLAG_collect_heap_spill_statistics && obj->IsJSObject()) {
- JSObject::cast(obj)->IncrementSpillStatistics(&js_spill_information);
+ JSObject::cast(obj)->IncrementSpillStatistics(
+ isolate->js_spill_information());
}
return obj->Size();
@@ -1732,13 +1607,14 @@ static int CollectHistogramInfo(HeapObject* obj) {
static void ReportHistogram(bool print_spill) {
+ Isolate* isolate = Isolate::Current();
PrintF("\n Object Histogram:\n");
for (int i = 0; i <= LAST_TYPE; i++) {
- if (heap_histograms[i].number() > 0) {
+ if (isolate->heap_histograms()[i].number() > 0) {
PrintF(" %-34s%10d (%10d bytes)\n",
- heap_histograms[i].name(),
- heap_histograms[i].number(),
- heap_histograms[i].bytes());
+ isolate->heap_histograms()[i].name(),
+ isolate->heap_histograms()[i].number(),
+ isolate->heap_histograms()[i].bytes());
}
}
PrintF("\n");
@@ -1747,8 +1623,8 @@ static void ReportHistogram(bool print_spill) {
int string_number = 0;
int string_bytes = 0;
#define INCREMENT(type, size, name, camel_name) \
- string_number += heap_histograms[type].number(); \
- string_bytes += heap_histograms[type].bytes();
+ string_number += isolate->heap_histograms()[type].number(); \
+ string_bytes += isolate->heap_histograms()[type].bytes();
STRING_TYPE_LIST(INCREMENT)
#undef INCREMENT
if (string_number > 0) {
@@ -1757,7 +1633,7 @@ static void ReportHistogram(bool print_spill) {
}
if (FLAG_collect_heap_spill_statistics && print_spill) {
- js_spill_information.Print();
+ isolate->js_spill_information()->Print();
}
}
#endif // DEBUG
@@ -1786,8 +1662,9 @@ void NewSpace::CollectStatistics() {
#ifdef ENABLE_LOGGING_AND_PROFILING
-static void DoReportStatistics(HistogramInfo* info, const char* description) {
- LOG(HeapSampleBeginEvent("NewSpace", description));
+static void DoReportStatistics(Isolate* isolate,
+ HistogramInfo* info, const char* description) {
+ LOG(isolate, HeapSampleBeginEvent("NewSpace", description));
// Lump all the string types together.
int string_number = 0;
int string_bytes = 0;
@@ -1797,17 +1674,19 @@ static void DoReportStatistics(HistogramInfo* info, const char* description) {
STRING_TYPE_LIST(INCREMENT)
#undef INCREMENT
if (string_number > 0) {
- LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes));
+ LOG(isolate,
+ HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes));
}
// Then do the other types.
for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) {
if (info[i].number() > 0) {
- LOG(HeapSampleItemEvent(info[i].name(), info[i].number(),
+ LOG(isolate,
+ HeapSampleItemEvent(info[i].name(), info[i].number(),
info[i].bytes()));
}
}
- LOG(HeapSampleEndEvent("NewSpace", description));
+ LOG(isolate, HeapSampleEndEvent("NewSpace", description));
}
#endif // ENABLE_LOGGING_AND_PROFILING
@@ -1834,8 +1713,9 @@ void NewSpace::ReportStatistics() {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (FLAG_log_gc) {
- DoReportStatistics(allocated_histogram_, "allocated");
- DoReportStatistics(promoted_histogram_, "promoted");
+ Isolate* isolate = ISOLATE;
+ DoReportStatistics(isolate, allocated_histogram_, "allocated");
+ DoReportStatistics(isolate, promoted_histogram_, "promoted");
}
#endif // ENABLE_LOGGING_AND_PROFILING
}
@@ -1861,7 +1741,7 @@ void NewSpace::RecordPromotion(HeapObject* obj) {
// -----------------------------------------------------------------------------
// Free lists for old object spaces implementation
-void FreeListNode::set_size(int size_in_bytes) {
+void FreeListNode::set_size(Heap* heap, int size_in_bytes) {
ASSERT(size_in_bytes > 0);
ASSERT(IsAligned(size_in_bytes, kPointerSize));
@@ -1873,14 +1753,14 @@ void FreeListNode::set_size(int size_in_bytes) {
// field and a next pointer, we give it a filler map that gives it the
// correct size.
if (size_in_bytes > ByteArray::kHeaderSize) {
- set_map(Heap::raw_unchecked_byte_array_map());
+ set_map(heap->raw_unchecked_byte_array_map());
// Can't use ByteArray::cast because it fails during deserialization.
ByteArray* this_as_byte_array = reinterpret_cast<ByteArray*>(this);
this_as_byte_array->set_length(ByteArray::LengthFor(size_in_bytes));
} else if (size_in_bytes == kPointerSize) {
- set_map(Heap::raw_unchecked_one_pointer_filler_map());
+ set_map(heap->raw_unchecked_one_pointer_filler_map());
} else if (size_in_bytes == 2 * kPointerSize) {
- set_map(Heap::raw_unchecked_two_pointer_filler_map());
+ set_map(heap->raw_unchecked_two_pointer_filler_map());
} else {
UNREACHABLE();
}
@@ -1889,9 +1769,9 @@ void FreeListNode::set_size(int size_in_bytes) {
}
-Address FreeListNode::next() {
+Address FreeListNode::next(Heap* heap) {
ASSERT(IsFreeListNode(this));
- if (map() == Heap::raw_unchecked_byte_array_map()) {
+ if (map() == heap->raw_unchecked_byte_array_map()) {
ASSERT(Size() >= kNextOffset + kPointerSize);
return Memory::Address_at(address() + kNextOffset);
} else {
@@ -1900,9 +1780,9 @@ Address FreeListNode::next() {
}
-void FreeListNode::set_next(Address next) {
+void FreeListNode::set_next(Heap* heap, Address next) {
ASSERT(IsFreeListNode(this));
- if (map() == Heap::raw_unchecked_byte_array_map()) {
+ if (map() == heap->raw_unchecked_byte_array_map()) {
ASSERT(Size() >= kNextOffset + kPointerSize);
Memory::Address_at(address() + kNextOffset) = next;
} else {
@@ -1911,7 +1791,9 @@ void FreeListNode::set_next(Address next) {
}
-OldSpaceFreeList::OldSpaceFreeList(AllocationSpace owner) : owner_(owner) {
+OldSpaceFreeList::OldSpaceFreeList(Heap* heap, AllocationSpace owner)
+ : heap_(heap),
+ owner_(owner) {
Reset();
}
@@ -1943,10 +1825,10 @@ void OldSpaceFreeList::RebuildSizeList() {
int OldSpaceFreeList::Free(Address start, int size_in_bytes) {
#ifdef DEBUG
- MemoryAllocator::ZapBlock(start, size_in_bytes);
+ Isolate::Current()->memory_allocator()->ZapBlock(start, size_in_bytes);
#endif
FreeListNode* node = FreeListNode::FromAddress(start);
- node->set_size(size_in_bytes);
+ node->set_size(heap_, size_in_bytes);
// We don't use the freelists in compacting mode. This makes it more like a
// GC that only has mark-sweep-compact and doesn't have a mark-sweep
@@ -1964,7 +1846,7 @@ int OldSpaceFreeList::Free(Address start, int size_in_bytes) {
// Insert other blocks at the head of an exact free list.
int index = size_in_bytes >> kPointerSizeLog2;
- node->set_next(free_[index].head_node_);
+ node->set_next(heap_, free_[index].head_node_);
free_[index].head_node_ = node->address();
available_ += size_in_bytes;
needs_rebuild_ = true;
@@ -1983,7 +1865,8 @@ MaybeObject* OldSpaceFreeList::Allocate(int size_in_bytes, int* wasted_bytes) {
if (free_[index].head_node_ != NULL) {
FreeListNode* node = FreeListNode::FromAddress(free_[index].head_node_);
// If this was the last block of its size, remove the size.
- if ((free_[index].head_node_ = node->next()) == NULL) RemoveSize(index);
+ if ((free_[index].head_node_ = node->next(heap_)) == NULL)
+ RemoveSize(index);
available_ -= size_in_bytes;
*wasted_bytes = 0;
ASSERT(!FLAG_always_compact); // We only use the freelists with mark-sweep.
@@ -2012,33 +1895,33 @@ MaybeObject* OldSpaceFreeList::Allocate(int size_in_bytes, int* wasted_bytes) {
finger_ = prev;
free_[prev].next_size_ = rem;
// If this was the last block of size cur, remove the size.
- if ((free_[cur].head_node_ = cur_node->next()) == NULL) {
+ if ((free_[cur].head_node_ = cur_node->next(heap_)) == NULL) {
free_[rem].next_size_ = free_[cur].next_size_;
} else {
free_[rem].next_size_ = cur;
}
// Add the remainder block.
- rem_node->set_size(rem_bytes);
- rem_node->set_next(free_[rem].head_node_);
+ rem_node->set_size(heap_, rem_bytes);
+ rem_node->set_next(heap_, free_[rem].head_node_);
free_[rem].head_node_ = rem_node->address();
} else {
// If this was the last block of size cur, remove the size.
- if ((free_[cur].head_node_ = cur_node->next()) == NULL) {
+ if ((free_[cur].head_node_ = cur_node->next(heap_)) == NULL) {
finger_ = prev;
free_[prev].next_size_ = free_[cur].next_size_;
}
if (rem_bytes < kMinBlockSize) {
// Too-small remainder is wasted.
- rem_node->set_size(rem_bytes);
+ rem_node->set_size(heap_, rem_bytes);
available_ -= size_in_bytes + rem_bytes;
*wasted_bytes = rem_bytes;
return cur_node;
}
// Add the remainder block and, if needed, insert its size.
- rem_node->set_size(rem_bytes);
- rem_node->set_next(free_[rem].head_node_);
+ rem_node->set_size(heap_, rem_bytes);
+ rem_node->set_next(heap_, free_[rem].head_node_);
free_[rem].head_node_ = rem_node->address();
- if (rem_node->next() == NULL) InsertSize(rem);
+ if (rem_node->next(heap_) == NULL) InsertSize(rem);
}
available_ -= size_in_bytes;
*wasted_bytes = 0;
@@ -2051,7 +1934,7 @@ void OldSpaceFreeList::MarkNodes() {
Address cur_addr = free_[i].head_node_;
while (cur_addr != NULL) {
FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
- cur_addr = cur_node->next();
+ cur_addr = cur_node->next(heap_);
cur_node->SetMark();
}
}
@@ -2065,7 +1948,7 @@ bool OldSpaceFreeList::Contains(FreeListNode* node) {
while (cur_addr != NULL) {
FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
if (cur_node == node) return true;
- cur_addr = cur_node->next();
+ cur_addr = cur_node->next(heap_);
}
}
return false;
@@ -2073,8 +1956,10 @@ bool OldSpaceFreeList::Contains(FreeListNode* node) {
#endif
-FixedSizeFreeList::FixedSizeFreeList(AllocationSpace owner, int object_size)
- : owner_(owner), object_size_(object_size) {
+FixedSizeFreeList::FixedSizeFreeList(Heap* heap,
+ AllocationSpace owner,
+ int object_size)
+ : heap_(heap), owner_(owner), object_size_(object_size) {
Reset();
}
@@ -2087,17 +1972,17 @@ void FixedSizeFreeList::Reset() {
void FixedSizeFreeList::Free(Address start) {
#ifdef DEBUG
- MemoryAllocator::ZapBlock(start, object_size_);
+ Isolate::Current()->memory_allocator()->ZapBlock(start, object_size_);
#endif
// We only use the freelists with mark-sweep.
- ASSERT(!MarkCompactCollector::IsCompacting());
+ ASSERT(!HEAP->mark_compact_collector()->IsCompacting());
FreeListNode* node = FreeListNode::FromAddress(start);
- node->set_size(object_size_);
- node->set_next(NULL);
+ node->set_size(heap_, object_size_);
+ node->set_next(heap_, NULL);
if (head_ == NULL) {
tail_ = head_ = node->address();
} else {
- FreeListNode::FromAddress(tail_)->set_next(node->address());
+ FreeListNode::FromAddress(tail_)->set_next(heap_, node->address());
tail_ = node->address();
}
available_ += object_size_;
@@ -2111,7 +1996,7 @@ MaybeObject* FixedSizeFreeList::Allocate() {
ASSERT(!FLAG_always_compact); // We only use the freelists with mark-sweep.
FreeListNode* node = FreeListNode::FromAddress(head_);
- head_ = node->next();
+ head_ = node->next(heap_);
available_ -= object_size_;
return node;
}
@@ -2121,7 +2006,7 @@ void FixedSizeFreeList::MarkNodes() {
Address cur_addr = head_;
while (cur_addr != NULL && cur_addr != tail_) {
FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
- cur_addr = cur_node->next();
+ cur_addr = cur_node->next(heap_);
cur_node->SetMark();
}
}
@@ -2217,13 +2102,14 @@ void PagedSpace::FreePages(Page* prev, Page* last) {
first_page_ = last->next_page();
} else {
first = prev->next_page();
- MemoryAllocator::SetNextPage(prev, last->next_page());
+ heap()->isolate()->memory_allocator()->SetNextPage(
+ prev, last->next_page());
}
// Attach it after the last page.
- MemoryAllocator::SetNextPage(last_page_, first);
+ heap()->isolate()->memory_allocator()->SetNextPage(last_page_, first);
last_page_ = last;
- MemoryAllocator::SetNextPage(last, NULL);
+ heap()->isolate()->memory_allocator()->SetNextPage(last, NULL);
// Clean them up.
do {
@@ -2262,10 +2148,8 @@ void PagedSpace::RelinkPageListInChunkOrder(bool deallocate_blocks) {
if (page_list_is_chunk_ordered_) return;
Page* new_last_in_use = Page::FromAddress(NULL);
- MemoryAllocator::RelinkPageListInChunkOrder(this,
- &first_page_,
- &last_page_,
- &new_last_in_use);
+ heap()->isolate()->memory_allocator()->RelinkPageListInChunkOrder(
+ this, &first_page_, &last_page_, &new_last_in_use);
ASSERT(new_last_in_use->is_valid());
if (new_last_in_use != last_in_use) {
@@ -2282,7 +2166,7 @@ void PagedSpace::RelinkPageListInChunkOrder(bool deallocate_blocks) {
accounting_stats_.AllocateBytes(size_in_bytes);
DeallocateBlock(start, size_in_bytes, add_to_freelist);
} else {
- Heap::CreateFillerObjectAt(start, size_in_bytes);
+ heap()->CreateFillerObjectAt(start, size_in_bytes);
}
}
@@ -2309,7 +2193,7 @@ void PagedSpace::RelinkPageListInChunkOrder(bool deallocate_blocks) {
accounting_stats_.AllocateBytes(size_in_bytes);
DeallocateBlock(start, size_in_bytes, add_to_freelist);
} else {
- Heap::CreateFillerObjectAt(start, size_in_bytes);
+ heap()->CreateFillerObjectAt(start, size_in_bytes);
}
}
}
@@ -2338,7 +2222,7 @@ bool PagedSpace::ReserveSpace(int bytes) {
int bytes_left_to_reserve = bytes;
while (bytes_left_to_reserve > 0) {
if (!reserved_page->next_page()->is_valid()) {
- if (Heap::OldGenerationAllocationLimitReached()) return false;
+ if (heap()->OldGenerationAllocationLimitReached()) return false;
Expand(reserved_page);
}
bytes_left_to_reserve -= Page::kPageSize;
@@ -2356,7 +2240,7 @@ bool PagedSpace::ReserveSpace(int bytes) {
// You have to call this last, since the implementation from PagedSpace
// doesn't know that memory was 'promised' to large object space.
bool LargeObjectSpace::ReserveSpace(int bytes) {
- return Heap::OldGenerationSpaceAvailable() >= bytes;
+ return heap()->OldGenerationSpaceAvailable() >= bytes;
}
@@ -2375,7 +2259,7 @@ HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) {
// There is no next page in this space. Try free list allocation unless that
// is currently forbidden.
- if (!Heap::linear_allocation()) {
+ if (!heap()->linear_allocation()) {
int wasted_bytes;
Object* result;
MaybeObject* maybe = free_list_.Allocate(size_in_bytes, &wasted_bytes);
@@ -2402,7 +2286,8 @@ HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) {
// Free list allocation failed and there is no next page. Fail if we have
// hit the old generation size limit that should cause a garbage
// collection.
- if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) {
+ if (!heap()->always_allocate() &&
+ heap()->OldGenerationAllocationLimitReached()) {
return NULL;
}
@@ -2465,28 +2350,14 @@ void OldSpace::DeallocateBlock(Address start,
#ifdef DEBUG
-struct CommentStatistic {
- const char* comment;
- int size;
- int count;
- void Clear() {
- comment = NULL;
- size = 0;
- count = 0;
- }
-};
-
-
-// must be small, since an iteration is used for lookup
-const int kMaxComments = 64;
-static CommentStatistic comments_statistics[kMaxComments+1];
-
-
void PagedSpace::ReportCodeStatistics() {
+ Isolate* isolate = Isolate::Current();
+ CommentStatistic* comments_statistics =
+ isolate->paged_space_comments_statistics();
ReportCodeKindStatistics();
PrintF("Code comment statistics (\" [ comment-txt : size/ "
"count (average)\"):\n");
- for (int i = 0; i <= kMaxComments; i++) {
+ for (int i = 0; i <= CommentStatistic::kMaxComments; i++) {
const CommentStatistic& cs = comments_statistics[i];
if (cs.size > 0) {
PrintF(" %-30s: %10d/%6d (%d)\n", cs.comment, cs.size, cs.count,
@@ -2498,23 +2369,30 @@ void PagedSpace::ReportCodeStatistics() {
void PagedSpace::ResetCodeStatistics() {
+ Isolate* isolate = Isolate::Current();
+ CommentStatistic* comments_statistics =
+ isolate->paged_space_comments_statistics();
ClearCodeKindStatistics();
- for (int i = 0; i < kMaxComments; i++) comments_statistics[i].Clear();
- comments_statistics[kMaxComments].comment = "Unknown";
- comments_statistics[kMaxComments].size = 0;
- comments_statistics[kMaxComments].count = 0;
+ for (int i = 0; i < CommentStatistic::kMaxComments; i++) {
+ comments_statistics[i].Clear();
+ }
+ comments_statistics[CommentStatistic::kMaxComments].comment = "Unknown";
+ comments_statistics[CommentStatistic::kMaxComments].size = 0;
+ comments_statistics[CommentStatistic::kMaxComments].count = 0;
}
-// Adds comment to 'comment_statistics' table. Performance OK sa long as
+// Adds comment to 'comment_statistics' table. Performance OK as long as
// 'kMaxComments' is small
-static void EnterComment(const char* comment, int delta) {
+static void EnterComment(Isolate* isolate, const char* comment, int delta) {
+ CommentStatistic* comments_statistics =
+ isolate->paged_space_comments_statistics();
// Do not count empty comments
if (delta <= 0) return;
- CommentStatistic* cs = &comments_statistics[kMaxComments];
+ CommentStatistic* cs = &comments_statistics[CommentStatistic::kMaxComments];
// Search for a free or matching entry in 'comments_statistics': 'cs'
// points to result.
- for (int i = 0; i < kMaxComments; i++) {
+ for (int i = 0; i < CommentStatistic::kMaxComments; i++) {
if (comments_statistics[i].comment == NULL) {
cs = &comments_statistics[i];
cs->comment = comment;
@@ -2532,7 +2410,7 @@ static void EnterComment(const char* comment, int delta) {
// Call for each nested comment start (start marked with '[ xxx', end marked
// with ']'. RelocIterator 'it' must point to a comment reloc info.
-static void CollectCommentStatistics(RelocIterator* it) {
+static void CollectCommentStatistics(Isolate* isolate, RelocIterator* it) {
ASSERT(!it->done());
ASSERT(it->rinfo()->rmode() == RelocInfo::COMMENT);
const char* tmp = reinterpret_cast<const char*>(it->rinfo()->data());
@@ -2557,13 +2435,13 @@ static void CollectCommentStatistics(RelocIterator* it) {
flat_delta += static_cast<int>(it->rinfo()->pc() - prev_pc);
if (txt[0] == ']') break; // End of nested comment
// A new comment
- CollectCommentStatistics(it);
+ CollectCommentStatistics(isolate, it);
// Skip code that was covered with previous comment
prev_pc = it->rinfo()->pc();
}
it->next();
}
- EnterComment(comment_txt, flat_delta);
+ EnterComment(isolate, comment_txt, flat_delta);
}
@@ -2571,18 +2449,19 @@ static void CollectCommentStatistics(RelocIterator* it) {
// - by code kind
// - by code comment
void PagedSpace::CollectCodeStatistics() {
+ Isolate* isolate = heap()->isolate();
HeapObjectIterator obj_it(this);
for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) {
if (obj->IsCode()) {
Code* code = Code::cast(obj);
- code_kind_statistics[code->kind()] += code->Size();
+ isolate->code_kind_statistics()[code->kind()] += code->Size();
RelocIterator it(code);
int delta = 0;
const byte* prev_pc = code->instruction_start();
while (!it.done()) {
if (it.rinfo()->rmode() == RelocInfo::COMMENT) {
delta += static_cast<int>(it.rinfo()->pc() - prev_pc);
- CollectCommentStatistics(&it);
+ CollectCommentStatistics(isolate, &it);
prev_pc = it.rinfo()->pc();
}
it.next();
@@ -2591,7 +2470,7 @@ void PagedSpace::CollectCodeStatistics() {
ASSERT(code->instruction_start() <= prev_pc &&
prev_pc <= code->instruction_end());
delta += static_cast<int>(code->instruction_end() - prev_pc);
- EnterComment("NoComment", delta);
+ EnterComment(isolate, "NoComment", delta);
}
}
}
@@ -2685,7 +2564,7 @@ HeapObject* FixedSpace::SlowAllocateRaw(int size_in_bytes) {
// There is no next page in this space. Try free list allocation unless
// that is currently forbidden. The fixed space free list implicitly assumes
// that all free blocks are of the fixed size.
- if (!Heap::linear_allocation()) {
+ if (!heap()->linear_allocation()) {
Object* result;
MaybeObject* maybe = free_list_.Allocate();
if (maybe->ToObject(&result)) {
@@ -2709,7 +2588,8 @@ HeapObject* FixedSpace::SlowAllocateRaw(int size_in_bytes) {
// Free list allocation failed and there is no next page. Fail if we have
// hit the old generation size limit that should cause a garbage
// collection.
- if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) {
+ if (!heap()->always_allocate() &&
+ heap()->OldGenerationAllocationLimitReached()) {
return NULL;
}
@@ -2811,7 +2691,7 @@ void MapSpace::VerifyObject(HeapObject* object) {
void CellSpace::VerifyObject(HeapObject* object) {
// The object should be a global object property cell or a free-list node.
ASSERT(object->IsJSGlobalPropertyCell() ||
- object->map() == Heap::two_pointer_filler_map());
+ object->map() == heap()->two_pointer_filler_map());
}
#endif
@@ -2848,28 +2728,33 @@ LargeObjectChunk* LargeObjectChunk::New(int size_in_bytes,
Executability executable) {
size_t requested = ChunkSizeFor(size_in_bytes);
size_t size;
- void* mem = MemoryAllocator::AllocateRawMemory(requested, &size, executable);
+ Isolate* isolate = Isolate::Current();
+ void* mem = isolate->memory_allocator()->AllocateRawMemory(
+ requested, &size, executable);
if (mem == NULL) return NULL;
// The start of the chunk may be overlayed with a page so we have to
// make sure that the page flags fit in the size field.
ASSERT((size & Page::kPageFlagMask) == 0);
- LOG(NewEvent("LargeObjectChunk", mem, size));
+ LOG(isolate, NewEvent("LargeObjectChunk", mem, size));
if (size < requested) {
- MemoryAllocator::FreeRawMemory(mem, size, executable);
- LOG(DeleteEvent("LargeObjectChunk", mem));
+ isolate->memory_allocator()->FreeRawMemory(
+ mem, size, executable);
+ LOG(isolate, DeleteEvent("LargeObjectChunk", mem));
return NULL;
}
ObjectSpace space = (executable == EXECUTABLE)
? kObjectSpaceCodeSpace
: kObjectSpaceLoSpace;
- MemoryAllocator::PerformAllocationCallback(
+ isolate->memory_allocator()->PerformAllocationCallback(
space, kAllocationActionAllocate, size);
LargeObjectChunk* chunk = reinterpret_cast<LargeObjectChunk*>(mem);
chunk->size_ = size;
+ Page* page = Page::FromAddress(RoundUp(chunk->address(), Page::kPageSize));
+ page->heap_ = isolate->heap();
return chunk;
}
@@ -2885,8 +2770,8 @@ int LargeObjectChunk::ChunkSizeFor(int size_in_bytes) {
// -----------------------------------------------------------------------------
// LargeObjectSpace
-LargeObjectSpace::LargeObjectSpace(AllocationSpace id)
- : Space(id, NOT_EXECUTABLE), // Managed on a per-allocation basis
+LargeObjectSpace::LargeObjectSpace(Heap* heap, AllocationSpace id)
+ : Space(heap, id, NOT_EXECUTABLE), // Managed on a per-allocation basis
first_chunk_(NULL),
size_(0),
page_count_(0),
@@ -2906,15 +2791,17 @@ void LargeObjectSpace::TearDown() {
while (first_chunk_ != NULL) {
LargeObjectChunk* chunk = first_chunk_;
first_chunk_ = first_chunk_->next();
- LOG(DeleteEvent("LargeObjectChunk", chunk->address()));
+ LOG(heap()->isolate(), DeleteEvent("LargeObjectChunk", chunk->address()));
Page* page = Page::FromAddress(RoundUp(chunk->address(), Page::kPageSize));
Executability executable =
page->IsPageExecutable() ? EXECUTABLE : NOT_EXECUTABLE;
ObjectSpace space = kObjectSpaceLoSpace;
if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace;
size_t size = chunk->size();
- MemoryAllocator::FreeRawMemory(chunk->address(), size, executable);
- MemoryAllocator::PerformAllocationCallback(
+ heap()->isolate()->memory_allocator()->FreeRawMemory(chunk->address(),
+ size,
+ executable);
+ heap()->isolate()->memory_allocator()->PerformAllocationCallback(
space, kAllocationActionFree, size);
}
@@ -2929,7 +2816,8 @@ void LargeObjectSpace::TearDown() {
void LargeObjectSpace::Protect() {
LargeObjectChunk* chunk = first_chunk_;
while (chunk != NULL) {
- MemoryAllocator::Protect(chunk->address(), chunk->size());
+ heap()->isolate()->memory_allocator()->Protect(chunk->address(),
+ chunk->size());
chunk = chunk->next();
}
}
@@ -2939,8 +2827,8 @@ void LargeObjectSpace::Unprotect() {
LargeObjectChunk* chunk = first_chunk_;
while (chunk != NULL) {
bool is_code = chunk->GetObject()->IsCode();
- MemoryAllocator::Unprotect(chunk->address(), chunk->size(),
- is_code ? EXECUTABLE : NOT_EXECUTABLE);
+ heap()->isolate()->memory_allocator()->Unprotect(chunk->address(),
+ chunk->size(), is_code ? EXECUTABLE : NOT_EXECUTABLE);
chunk = chunk->next();
}
}
@@ -2955,7 +2843,8 @@ MaybeObject* LargeObjectSpace::AllocateRawInternal(int requested_size,
// Check if we want to force a GC before growing the old space further.
// If so, fail the allocation.
- if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) {
+ if (!heap()->always_allocate() &&
+ heap()->OldGenerationAllocationLimitReached()) {
return Failure::RetryAfterGC(identity());
}
@@ -3060,22 +2949,22 @@ void LargeObjectSpace::IterateDirtyRegions(ObjectSlotCallback copy_object) {
// Iterate regions of the first normal page covering object.
uint32_t first_region_number = page->GetRegionNumberForAddress(start);
newmarks |=
- Heap::IterateDirtyRegions(marks >> first_region_number,
- start,
- end,
- &Heap::IteratePointersInDirtyRegion,
- copy_object) << first_region_number;
+ heap()->IterateDirtyRegions(marks >> first_region_number,
+ start,
+ end,
+ &Heap::IteratePointersInDirtyRegion,
+ copy_object) << first_region_number;
start = end;
end = start + Page::kPageSize;
while (end <= object_end) {
// Iterate next 32 regions.
newmarks |=
- Heap::IterateDirtyRegions(marks,
- start,
- end,
- &Heap::IteratePointersInDirtyRegion,
- copy_object);
+ heap()->IterateDirtyRegions(marks,
+ start,
+ end,
+ &Heap::IteratePointersInDirtyRegion,
+ copy_object);
start = end;
end = start + Page::kPageSize;
}
@@ -3084,11 +2973,11 @@ void LargeObjectSpace::IterateDirtyRegions(ObjectSlotCallback copy_object) {
// Iterate the last piece of an object which is less than
// Page::kPageSize.
newmarks |=
- Heap::IterateDirtyRegions(marks,
- start,
- object_end,
- &Heap::IteratePointersInDirtyRegion,
- copy_object);
+ heap()->IterateDirtyRegions(marks,
+ start,
+ object_end,
+ &Heap::IteratePointersInDirtyRegion,
+ copy_object);
}
page->SetRegionMarks(newmarks);
@@ -3105,7 +2994,7 @@ void LargeObjectSpace::FreeUnmarkedObjects() {
HeapObject* object = current->GetObject();
if (object->IsMarked()) {
object->ClearMark();
- MarkCompactCollector::tracer()->decrement_marked_count();
+ heap()->mark_compact_collector()->tracer()->decrement_marked_count();
previous = current;
current = current->next();
} else {
@@ -3125,7 +3014,7 @@ void LargeObjectSpace::FreeUnmarkedObjects() {
}
// Free the chunk.
- MarkCompactCollector::ReportDeleteIfNeeded(object);
+ heap()->mark_compact_collector()->ReportDeleteIfNeeded(object);
LiveObjectList::ProcessNonLive(object);
size_ -= static_cast<int>(chunk_size);
@@ -3133,10 +3022,12 @@ void LargeObjectSpace::FreeUnmarkedObjects() {
page_count_--;
ObjectSpace space = kObjectSpaceLoSpace;
if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace;
- MemoryAllocator::FreeRawMemory(chunk_address, chunk_size, executable);
- MemoryAllocator::PerformAllocationCallback(space, kAllocationActionFree,
- size_);
- LOG(DeleteEvent("LargeObjectChunk", chunk_address));
+ heap()->isolate()->memory_allocator()->FreeRawMemory(chunk_address,
+ chunk_size,
+ executable);
+ heap()->isolate()->memory_allocator()->PerformAllocationCallback(
+ space, kAllocationActionFree, size_);
+ LOG(heap()->isolate(), DeleteEvent("LargeObjectChunk", chunk_address));
}
}
}
@@ -3144,7 +3035,7 @@ void LargeObjectSpace::FreeUnmarkedObjects() {
bool LargeObjectSpace::Contains(HeapObject* object) {
Address address = object->address();
- if (Heap::new_space()->Contains(address)) {
+ if (heap()->new_space()->Contains(address)) {
return false;
}
Page* page = Page::FromAddress(address);
@@ -3173,7 +3064,7 @@ void LargeObjectSpace::Verify() {
// in map space.
Map* map = object->map();
ASSERT(map->IsMap());
- ASSERT(Heap::map_space()->Contains(map));
+ ASSERT(heap()->map_space()->Contains(map));
// We have only code, sequential strings, external strings
// (sequential strings that have been morphed into external
@@ -3200,9 +3091,9 @@ void LargeObjectSpace::Verify() {
Object* element = array->get(j);
if (element->IsHeapObject()) {
HeapObject* element_object = HeapObject::cast(element);
- ASSERT(Heap::Contains(element_object));
+ ASSERT(heap()->Contains(element_object));
ASSERT(element_object->map()->IsMap());
- if (Heap::InNewSpace(element_object)) {
+ if (heap()->InNewSpace(element_object)) {
Address array_addr = object->address();
Address element_addr = array_addr + FixedArray::kHeaderSize +
j * kPointerSize;
@@ -3241,11 +3132,12 @@ void LargeObjectSpace::ReportStatistics() {
void LargeObjectSpace::CollectCodeStatistics() {
+ Isolate* isolate = heap()->isolate();
LargeObjectIterator obj_it(this);
for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) {
if (obj->IsCode()) {
Code* code = Code::cast(obj);
- code_kind_statistics[code->kind()] += code->Size();
+ isolate->code_kind_statistics()[code->kind()] += code->Size();
}
}
}
diff --git a/src/spaces.h b/src/spaces.h
index 6165255f..bd939d1e 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -34,6 +34,8 @@
namespace v8 {
namespace internal {
+class Isolate;
+
// -----------------------------------------------------------------------------
// Heap structures:
//
@@ -241,7 +243,7 @@ class Page {
static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1;
static const int kPageHeaderSize = kPointerSize + kPointerSize + kIntSize +
- kIntSize + kPointerSize;
+ kIntSize + kPointerSize + kPointerSize;
// The start offset of the object area in a page. Aligned to both maps and
// code alignment to be suitable for both.
@@ -286,7 +288,7 @@ class Page {
// This invariant guarantees that after flipping flag meaning at the
// beginning of scavenge all pages in use will be marked as having valid
// watermark.
- static inline void FlipMeaningOfInvalidatedWatermarkFlag();
+ static inline void FlipMeaningOfInvalidatedWatermarkFlag(Heap* heap);
// Returns true if the page allocation watermark was not altered during
// scavenge.
@@ -312,11 +314,6 @@ class Page {
STATIC_CHECK(kBitsPerInt - kAllocationWatermarkOffsetShift >=
kAllocationWatermarkOffsetBits);
- // This field contains the meaning of the WATERMARK_INVALIDATED flag.
- // Instead of clearing this flag from all pages we just flip
- // its meaning at the beginning of a scavenge.
- static intptr_t watermark_invalidated_mark_;
-
//---------------------------------------------------------------------------
// Page header description.
//
@@ -353,6 +350,8 @@ class Page {
// During scavenge collection this field is used to store allocation watermark
// if it is altered during scavenge.
Address mc_first_forwarded;
+
+ Heap* heap_;
};
@@ -360,11 +359,13 @@ class Page {
// Space is the abstract superclass for all allocation spaces.
class Space : public Malloced {
public:
- Space(AllocationSpace id, Executability executable)
- : id_(id), executable_(executable) {}
+ Space(Heap* heap, AllocationSpace id, Executability executable)
+ : heap_(heap), id_(id), executable_(executable) {}
virtual ~Space() {}
+ Heap* heap() const { return heap_; }
+
// Does the space need executable memory?
Executability executable() { return executable_; }
@@ -397,6 +398,7 @@ class Space : public Malloced {
virtual bool ReserveSpace(int bytes) = 0;
private:
+ Heap* heap_;
AllocationSpace id_;
Executability executable_;
};
@@ -409,19 +411,19 @@ class Space : public Malloced {
// displacements cover the entire 4GB virtual address space. On 64-bit
// platforms, we support this using the CodeRange object, which reserves and
// manages a range of virtual memory.
-class CodeRange : public AllStatic {
+class CodeRange {
public:
// Reserves a range of virtual memory, but does not commit any of it.
// Can only be called once, at heap initialization time.
// Returns false on failure.
- static bool Setup(const size_t requested_size);
+ bool Setup(const size_t requested_size);
// Frees the range of virtual memory, and frees the data structures used to
// manage it.
- static void TearDown();
+ void TearDown();
- static bool exists() { return code_range_ != NULL; }
- static bool contains(Address address) {
+ bool exists() { return code_range_ != NULL; }
+ bool contains(Address address) {
if (code_range_ == NULL) return false;
Address start = static_cast<Address>(code_range_->address());
return start <= address && address < start + code_range_->size();
@@ -430,13 +432,15 @@ class CodeRange : public AllStatic {
// Allocates a chunk of memory from the large-object portion of
// the code range. On platforms with no separate code range, should
// not be called.
- MUST_USE_RESULT static void* AllocateRawMemory(const size_t requested,
- size_t* allocated);
- static void FreeRawMemory(void* buf, size_t length);
+ MUST_USE_RESULT void* AllocateRawMemory(const size_t requested,
+ size_t* allocated);
+ void FreeRawMemory(void* buf, size_t length);
private:
+ CodeRange();
+
// The reserved range of virtual memory that all code objects are put in.
- static VirtualMemory* code_range_;
+ VirtualMemory* code_range_;
// Plain old data class, just a struct plus a constructor.
class FreeBlock {
public:
@@ -452,20 +456,26 @@ class CodeRange : public AllStatic {
// Freed blocks of memory are added to the free list. When the allocation
// list is exhausted, the free list is sorted and merged to make the new
// allocation list.
- static List<FreeBlock> free_list_;
+ List<FreeBlock> free_list_;
// Memory is allocated from the free blocks on the allocation list.
// The block at current_allocation_block_index_ is the current block.
- static List<FreeBlock> allocation_list_;
- static int current_allocation_block_index_;
+ List<FreeBlock> allocation_list_;
+ int current_allocation_block_index_;
// Finds a block on the allocation list that contains at least the
// requested amount of memory. If none is found, sorts and merges
// the existing free memory blocks, and searches again.
// If none can be found, terminates V8 with FatalProcessOutOfMemory.
- static void GetNextAllocationBlock(size_t requested);
+ void GetNextAllocationBlock(size_t requested);
// Compares the start addresses of two free blocks.
static int CompareFreeBlockAddress(const FreeBlock* left,
const FreeBlock* right);
+
+ friend class Isolate;
+
+ Isolate* isolate_;
+
+ DISALLOW_COPY_AND_ASSIGN(CodeRange);
};
@@ -493,14 +503,14 @@ class CodeRange : public AllStatic {
//
-class MemoryAllocator : public AllStatic {
+class MemoryAllocator {
public:
// Initializes its internal bookkeeping structures.
// Max capacity of the total space and executable memory limit.
- static bool Setup(intptr_t max_capacity, intptr_t capacity_executable);
+ bool Setup(intptr_t max_capacity, intptr_t capacity_executable);
// Deletes valid chunks.
- static void TearDown();
+ void TearDown();
// Reserves an initial address range of virtual memory to be split between
// the two new space semispaces, the old space, and the map space. The
@@ -511,7 +521,7 @@ class MemoryAllocator : public AllStatic {
// address of the initial chunk if successful, with the side effect of
// setting the initial chunk, or else NULL if unsuccessful and leaves the
// initial chunk NULL.
- static void* ReserveInitialChunk(const size_t requested);
+ void* ReserveInitialChunk(const size_t requested);
// Commits pages from an as-yet-unmanaged block of virtual memory into a
// paged space. The block should be part of the initial chunk reserved via
@@ -520,24 +530,24 @@ class MemoryAllocator : public AllStatic {
// address is non-null and that it is big enough to hold at least one
// page-aligned page. The call always succeeds, and num_pages is always
// greater than zero.
- static Page* CommitPages(Address start, size_t size, PagedSpace* owner,
- int* num_pages);
+ Page* CommitPages(Address start, size_t size, PagedSpace* owner,
+ int* num_pages);
// Commit a contiguous block of memory from the initial chunk. Assumes that
// the address is not NULL, the size is greater than zero, and that the
// block is contained in the initial chunk. Returns true if it succeeded
// and false otherwise.
- static bool CommitBlock(Address start, size_t size, Executability executable);
+ bool CommitBlock(Address start, size_t size, Executability executable);
// Uncommit a contiguous block of memory [start..(start+size)[.
// start is not NULL, the size is greater than zero, and the
// block is contained in the initial chunk. Returns true if it succeeded
// and false otherwise.
- static bool UncommitBlock(Address start, size_t size);
+ bool UncommitBlock(Address start, size_t size);
// Zaps a contiguous block of memory [start..(start+size)[ thus
// filling it up with a recognizable non-NULL bit pattern.
- static void ZapBlock(Address start, size_t size);
+ void ZapBlock(Address start, size_t size);
// Attempts to allocate the requested (non-zero) number of pages from the
// OS. Fewer pages might be allocated than requested. If it fails to
@@ -548,8 +558,8 @@ class MemoryAllocator : public AllStatic {
// number of allocated pages is returned in the output parameter
// allocated_pages. If the PagedSpace owner is executable and there is
// a code range, the pages are allocated from the code range.
- static Page* AllocatePages(int requested_pages, int* allocated_pages,
- PagedSpace* owner);
+ Page* AllocatePages(int requested_pages, int* allocated_pages,
+ PagedSpace* owner);
// Frees pages from a given page and after. Requires pages to be
// linked in chunk-order (see comment for class).
@@ -558,10 +568,10 @@ class MemoryAllocator : public AllStatic {
// Otherwise, the function searches a page after 'p' that is
// the first page of a chunk. Pages after the found page
// are freed and the function returns 'p'.
- static Page* FreePages(Page* p);
+ Page* FreePages(Page* p);
// Frees all pages owned by given space.
- static void FreeAllPages(PagedSpace* space);
+ void FreeAllPages(PagedSpace* space);
// Allocates and frees raw memory of certain size.
// These are just thin wrappers around OS::Allocate and OS::Free,
@@ -569,96 +579,83 @@ class MemoryAllocator : public AllStatic {
// If the flag is EXECUTABLE and a code range exists, the requested
// memory is allocated from the code range. If a code range exists
// and the freed memory is in it, the code range manages the freed memory.
- MUST_USE_RESULT static void* AllocateRawMemory(const size_t requested,
- size_t* allocated,
- Executability executable);
- static void FreeRawMemory(void* buf,
- size_t length,
- Executability executable);
- static void PerformAllocationCallback(ObjectSpace space,
- AllocationAction action,
- size_t size);
-
- static void AddMemoryAllocationCallback(MemoryAllocationCallback callback,
- ObjectSpace space,
- AllocationAction action);
- static void RemoveMemoryAllocationCallback(
- MemoryAllocationCallback callback);
- static bool MemoryAllocationCallbackRegistered(
- MemoryAllocationCallback callback);
+ MUST_USE_RESULT void* AllocateRawMemory(const size_t requested,
+ size_t* allocated,
+ Executability executable);
+ void FreeRawMemory(void* buf,
+ size_t length,
+ Executability executable);
+ void PerformAllocationCallback(ObjectSpace space,
+ AllocationAction action,
+ size_t size);
+
+ void AddMemoryAllocationCallback(MemoryAllocationCallback callback,
+ ObjectSpace space,
+ AllocationAction action);
+ void RemoveMemoryAllocationCallback(MemoryAllocationCallback callback);
+ bool MemoryAllocationCallbackRegistered(MemoryAllocationCallback callback);
// Returns the maximum available bytes of heaps.
- static intptr_t Available() {
- return capacity_ < size_ ? 0 : capacity_ - size_;
- }
+ intptr_t Available() { return capacity_ < size_ ? 0 : capacity_ - size_; }
// Returns allocated spaces in bytes.
- static intptr_t Size() { return size_; }
+ intptr_t Size() { return size_; }
// Returns the maximum available executable bytes of heaps.
- static intptr_t AvailableExecutable() {
+ intptr_t AvailableExecutable() {
if (capacity_executable_ < size_executable_) return 0;
return capacity_executable_ - size_executable_;
}
// Returns allocated executable spaces in bytes.
- static intptr_t SizeExecutable() { return size_executable_; }
+ intptr_t SizeExecutable() { return size_executable_; }
// Returns maximum available bytes that the old space can have.
- static intptr_t MaxAvailable() {
+ intptr_t MaxAvailable() {
return (Available() / Page::kPageSize) * Page::kObjectAreaSize;
}
- // Sanity check on a pointer.
- static bool SafeIsInAPageChunk(Address addr);
-
// Links two pages.
- static inline void SetNextPage(Page* prev, Page* next);
+ inline void SetNextPage(Page* prev, Page* next);
// Returns the next page of a given page.
- static inline Page* GetNextPage(Page* p);
+ inline Page* GetNextPage(Page* p);
// Checks whether a page belongs to a space.
- static inline bool IsPageInSpace(Page* p, PagedSpace* space);
+ inline bool IsPageInSpace(Page* p, PagedSpace* space);
// Returns the space that owns the given page.
- static inline PagedSpace* PageOwner(Page* page);
+ inline PagedSpace* PageOwner(Page* page);
// Finds the first/last page in the same chunk as a given page.
- static Page* FindFirstPageInSameChunk(Page* p);
- static Page* FindLastPageInSameChunk(Page* p);
+ Page* FindFirstPageInSameChunk(Page* p);
+ Page* FindLastPageInSameChunk(Page* p);
// Relinks list of pages owned by space to make it chunk-ordered.
// Returns new first and last pages of space.
// Also returns last page in relinked list which has WasInUsedBeforeMC
// flag set.
- static void RelinkPageListInChunkOrder(PagedSpace* space,
- Page** first_page,
- Page** last_page,
- Page** last_page_in_use);
+ void RelinkPageListInChunkOrder(PagedSpace* space,
+ Page** first_page,
+ Page** last_page,
+ Page** last_page_in_use);
#ifdef ENABLE_HEAP_PROTECTION
// Protect/unprotect a block of memory by marking it read-only/writable.
- static inline void Protect(Address start, size_t size);
- static inline void Unprotect(Address start, size_t size,
- Executability executable);
+ inline void Protect(Address start, size_t size);
+ inline void Unprotect(Address start, size_t size,
+ Executability executable);
// Protect/unprotect a chunk given a page in the chunk.
- static inline void ProtectChunkFromPage(Page* page);
- static inline void UnprotectChunkFromPage(Page* page);
+ inline void ProtectChunkFromPage(Page* page);
+ inline void UnprotectChunkFromPage(Page* page);
#endif
#ifdef DEBUG
// Reports statistic info of the space.
- static void ReportStatistics();
+ void ReportStatistics();
#endif
- static void AddToAllocatedChunks(Address addr, intptr_t size);
- static void RemoveFromAllocatedChunks(Address addr, intptr_t size);
- // Note: This only checks the regular chunks, not the odd-sized initial
- // chunk.
- static bool InAllocatedChunks(Address addr);
-
// Due to encoding limitation, we can only have 8K chunks.
static const int kMaxNofChunks = 1 << kPageSizeBits;
// If a chunk has at least 16 pages, the maximum heap size is about
@@ -678,29 +675,21 @@ class MemoryAllocator : public AllStatic {
#endif
private:
+ MemoryAllocator();
+
static const int kChunkSize = kPagesPerChunk * Page::kPageSize;
static const int kChunkSizeLog2 = kPagesPerChunkLog2 + kPageSizeBits;
- static const int kChunkTableTopLevelEntries =
- 1 << (sizeof(intptr_t) * kBitsPerByte - kChunkSizeLog2 -
- (kChunkTableLevels - 1) * kChunkTableBitsPerLevel);
-
- // The chunks are not chunk-size aligned so for a given chunk-sized area of
- // memory there can be two chunks that cover it.
- static const int kChunkTableFineGrainedWordsPerEntry = 2;
- static const uintptr_t kUnusedChunkTableEntry = 0;
// Maximum space size in bytes.
- static intptr_t capacity_;
+ intptr_t capacity_;
// Maximum subset of capacity_ that can be executable
- static intptr_t capacity_executable_;
-
- // Top level table to track whether memory is part of a chunk or not.
- static uintptr_t chunk_table_[kChunkTableTopLevelEntries];
+ intptr_t capacity_executable_;
// Allocated space size in bytes.
- static intptr_t size_;
+ intptr_t size_;
+
// Allocated executable space size in bytes.
- static intptr_t size_executable_;
+ intptr_t size_executable_;
struct MemoryAllocationCallbackRegistration {
MemoryAllocationCallbackRegistration(MemoryAllocationCallback callback,
@@ -713,11 +702,11 @@ class MemoryAllocator : public AllStatic {
AllocationAction action;
};
// A List of callback that are triggered when memory is allocated or free'd
- static List<MemoryAllocationCallbackRegistration>
+ List<MemoryAllocationCallbackRegistration>
memory_allocation_callbacks_;
// The initial chunk of virtual memory.
- static VirtualMemory* initial_chunk_;
+ VirtualMemory* initial_chunk_;
// Allocated chunk info: chunk start address, chunk size, and owning space.
class ChunkInfo BASE_EMBEDDED {
@@ -725,7 +714,8 @@ class MemoryAllocator : public AllStatic {
ChunkInfo() : address_(NULL),
size_(0),
owner_(NULL),
- executable_(NOT_EXECUTABLE) {}
+ executable_(NOT_EXECUTABLE),
+ owner_identity_(FIRST_SPACE) {}
inline void init(Address a, size_t s, PagedSpace* o);
Address address() { return address_; }
size_t size() { return size_; }
@@ -733,74 +723,60 @@ class MemoryAllocator : public AllStatic {
// We save executability of the owner to allow using it
// when collecting stats after the owner has been destroyed.
Executability executable() const { return executable_; }
+ AllocationSpace owner_identity() const { return owner_identity_; }
private:
Address address_;
size_t size_;
PagedSpace* owner_;
Executability executable_;
+ AllocationSpace owner_identity_;
};
// Chunks_, free_chunk_ids_ and top_ act as a stack of free chunk ids.
- static List<ChunkInfo> chunks_;
- static List<int> free_chunk_ids_;
- static int max_nof_chunks_;
- static int top_;
+ List<ChunkInfo> chunks_;
+ List<int> free_chunk_ids_;
+ int max_nof_chunks_;
+ int top_;
// Push/pop a free chunk id onto/from the stack.
- static void Push(int free_chunk_id);
- static int Pop();
- static bool OutOfChunkIds() { return top_ == 0; }
+ void Push(int free_chunk_id);
+ int Pop();
+ bool OutOfChunkIds() { return top_ == 0; }
// Frees a chunk.
- static void DeleteChunk(int chunk_id);
-
- // Helpers to maintain and query the chunk tables.
- static void AddChunkUsingAddress(
- uintptr_t chunk_start, // Where the chunk starts.
- uintptr_t chunk_index_base); // Used to place the chunk in the tables.
- static void RemoveChunkFoundUsingAddress(
- uintptr_t chunk_start, // Where the chunk starts.
- uintptr_t chunk_index_base); // Used to locate the entry in the tables.
- // Controls whether the lookup creates intermediate levels of tables as
- // needed.
- enum CreateTables { kDontCreateTables, kCreateTablesAsNeeded };
- static uintptr_t* AllocatedChunksFinder(uintptr_t* table,
- uintptr_t address,
- int bit_position,
- CreateTables create_as_needed);
- static void FreeChunkTables(uintptr_t* array, int length, int level);
- static int FineGrainedIndexForAddress(uintptr_t address) {
- int index = ((address >> kChunkSizeLog2) &
- ((1 << kChunkTableBitsPerLevel) - 1));
- return index * kChunkTableFineGrainedWordsPerEntry;
- }
-
+ void DeleteChunk(int chunk_id);
// Basic check whether a chunk id is in the valid range.
- static inline bool IsValidChunkId(int chunk_id);
+ inline bool IsValidChunkId(int chunk_id);
// Checks whether a chunk id identifies an allocated chunk.
- static inline bool IsValidChunk(int chunk_id);
+ inline bool IsValidChunk(int chunk_id);
// Returns the chunk id that a page belongs to.
- static inline int GetChunkId(Page* p);
+ inline int GetChunkId(Page* p);
// True if the address lies in the initial chunk.
- static inline bool InInitialChunk(Address address);
+ inline bool InInitialChunk(Address address);
// Initializes pages in a chunk. Returns the first page address.
// This function and GetChunkId() are provided for the mark-compact
// collector to rebuild page headers in the from space, which is
// used as a marking stack and its page headers are destroyed.
- static Page* InitializePagesInChunk(int chunk_id, int pages_in_chunk,
- PagedSpace* owner);
+ Page* InitializePagesInChunk(int chunk_id, int pages_in_chunk,
+ PagedSpace* owner);
- static Page* RelinkPagesInChunk(int chunk_id,
- Address chunk_start,
- size_t chunk_size,
- Page* prev,
- Page** last_page_in_use);
+ Page* RelinkPagesInChunk(int chunk_id,
+ Address chunk_start,
+ size_t chunk_size,
+ Page* prev,
+ Page** last_page_in_use);
+
+ friend class Isolate;
+
+ Isolate* isolate_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryAllocator);
};
@@ -1048,7 +1024,8 @@ class AllocationStats BASE_EMBEDDED {
class PagedSpace : public Space {
public:
// Creates a space with a maximum capacity, and an id.
- PagedSpace(intptr_t max_capacity,
+ PagedSpace(Heap* heap,
+ intptr_t max_capacity,
AllocationSpace id,
Executability executable);
@@ -1341,7 +1318,7 @@ class HistogramInfo: public NumberAndSizeInfo {
class SemiSpace : public Space {
public:
// Constructor.
- SemiSpace() :Space(NEW_SPACE, NOT_EXECUTABLE) {
+ explicit SemiSpace(Heap* heap) : Space(heap, NEW_SPACE, NOT_EXECUTABLE) {
start_ = NULL;
age_mark_ = NULL;
}
@@ -1508,7 +1485,10 @@ class SemiSpaceIterator : public ObjectIterator {
class NewSpace : public Space {
public:
// Constructor.
- NewSpace() : Space(NEW_SPACE, NOT_EXECUTABLE) {}
+ explicit NewSpace(Heap* heap)
+ : Space(heap, NEW_SPACE, NOT_EXECUTABLE),
+ to_space_(heap),
+ from_space_(heap) {}
// Sets up the new space using the given chunk.
bool Setup(Address start, int size);
@@ -1741,11 +1721,11 @@ class FreeListNode: public HeapObject {
// function also writes a map to the first word of the block so that it
// looks like a heap object to the garbage collector and heap iteration
// functions.
- void set_size(int size_in_bytes);
+ void set_size(Heap* heap, int size_in_bytes);
// Accessors for the next field.
- inline Address next();
- inline void set_next(Address next);
+ inline Address next(Heap* heap);
+ inline void set_next(Heap* heap, Address next);
private:
static const int kNextOffset = POINTER_SIZE_ALIGN(ByteArray::kHeaderSize);
@@ -1757,7 +1737,7 @@ class FreeListNode: public HeapObject {
// The free list for the old space.
class OldSpaceFreeList BASE_EMBEDDED {
public:
- explicit OldSpaceFreeList(AllocationSpace owner);
+ OldSpaceFreeList(Heap* heap, AllocationSpace owner);
// Clear the free list.
void Reset();
@@ -1787,6 +1767,8 @@ class OldSpaceFreeList BASE_EMBEDDED {
static const int kMinBlockSize = 2 * kPointerSize;
static const int kMaxBlockSize = Page::kMaxHeapObjectSize;
+ Heap* heap_;
+
// The identity of the owning space, for building allocation Failure
// objects.
AllocationSpace owner_;
@@ -1861,7 +1843,7 @@ class OldSpaceFreeList BASE_EMBEDDED {
// The free list for the map space.
class FixedSizeFreeList BASE_EMBEDDED {
public:
- FixedSizeFreeList(AllocationSpace owner, int object_size);
+ FixedSizeFreeList(Heap* heap, AllocationSpace owner, int object_size);
// Clear the free list.
void Reset();
@@ -1882,6 +1864,9 @@ class FixedSizeFreeList BASE_EMBEDDED {
void MarkNodes();
private:
+
+ Heap* heap_;
+
// Available bytes on the free list.
intptr_t available_;
@@ -1909,10 +1894,12 @@ class OldSpace : public PagedSpace {
public:
// Creates an old space object with a given maximum capacity.
// The constructor does not allocate pages from OS.
- explicit OldSpace(intptr_t max_capacity,
- AllocationSpace id,
- Executability executable)
- : PagedSpace(max_capacity, id, executable), free_list_(id) {
+ OldSpace(Heap* heap,
+ intptr_t max_capacity,
+ AllocationSpace id,
+ Executability executable)
+ : PagedSpace(heap, max_capacity, id, executable),
+ free_list_(heap, id) {
page_extra_ = 0;
}
@@ -1981,14 +1968,15 @@ class OldSpace : public PagedSpace {
class FixedSpace : public PagedSpace {
public:
- FixedSpace(intptr_t max_capacity,
+ FixedSpace(Heap* heap,
+ intptr_t max_capacity,
AllocationSpace id,
int object_size_in_bytes,
const char* name)
- : PagedSpace(max_capacity, id, NOT_EXECUTABLE),
+ : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE),
object_size_in_bytes_(object_size_in_bytes),
name_(name),
- free_list_(id, object_size_in_bytes) {
+ free_list_(heap, id, object_size_in_bytes) {
page_extra_ = Page::kObjectAreaSize % object_size_in_bytes;
}
@@ -2059,8 +2047,11 @@ class FixedSpace : public PagedSpace {
class MapSpace : public FixedSpace {
public:
// Creates a map space object with a maximum capacity.
- MapSpace(intptr_t max_capacity, int max_map_space_pages, AllocationSpace id)
- : FixedSpace(max_capacity, id, Map::kSize, "map"),
+ MapSpace(Heap* heap,
+ intptr_t max_capacity,
+ int max_map_space_pages,
+ AllocationSpace id)
+ : FixedSpace(heap, max_capacity, id, Map::kSize, "map"),
max_map_space_pages_(max_map_space_pages) {
ASSERT(max_map_space_pages < kMaxMapPageIndex);
}
@@ -2170,8 +2161,9 @@ class MapSpace : public FixedSpace {
class CellSpace : public FixedSpace {
public:
// Creates a property cell space object with a maximum capacity.
- CellSpace(intptr_t max_capacity, AllocationSpace id)
- : FixedSpace(max_capacity, id, JSGlobalPropertyCell::kSize, "cell") {}
+ CellSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
+ : FixedSpace(heap, max_capacity, id, JSGlobalPropertyCell::kSize, "cell")
+ {}
protected:
#ifdef DEBUG
@@ -2246,7 +2238,7 @@ class LargeObjectChunk {
class LargeObjectSpace : public Space {
public:
- explicit LargeObjectSpace(AllocationSpace id);
+ LargeObjectSpace(Heap* heap, AllocationSpace id);
virtual ~LargeObjectSpace() {}
// Initializes internal data structures.
@@ -2263,9 +2255,7 @@ class LargeObjectSpace : public Space {
MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int size_in_bytes);
// Available bytes for objects in this space.
- intptr_t Available() {
- return LargeObjectChunk::ObjectSizeFor(MemoryAllocator::Available());
- }
+ inline intptr_t Available();
virtual intptr_t Size() {
return size_;
@@ -2357,6 +2347,22 @@ class LargeObjectIterator: public ObjectIterator {
};
+#ifdef DEBUG
+struct CommentStatistic {
+ const char* comment;
+ int size;
+ int count;
+ void Clear() {
+ comment = NULL;
+ size = 0;
+ count = 0;
+ }
+ // Must be small, since an iteration is used for lookup.
+ static const int kMaxComments = 64;
+};
+#endif
+
+
} } // namespace v8::internal
#endif // V8_SPACES_H_
diff --git a/src/string-search.cc b/src/string-search.cc
index 56874432..3ae68b5d 100644
--- a/src/string-search.cc
+++ b/src/string-search.cc
@@ -33,8 +33,9 @@ namespace internal {
// Storage for constants used by string-search.
-int StringSearchBase::kBadCharShiftTable[kUC16AlphabetSize];
-int StringSearchBase::kGoodSuffixShiftTable[kBMMaxShift + 1];
-int StringSearchBase::kSuffixTable[kBMMaxShift + 1];
+// Now in Isolate:
+// bad_char_shift_table()
+// good_suffix_shift_table()
+// suffix_table()
}} // namespace v8::internal
diff --git a/src/string-search.h b/src/string-search.h
index 5de3c095..1223db0f 100644
--- a/src/string-search.h
+++ b/src/string-search.h
@@ -44,7 +44,7 @@ class StringSearchBase {
// limit, we can fix the size of tables. For a needle longer than this limit,
// search will not be optimal, since we only build tables for a suffix
// of the string, but it is a safe approximation.
- static const int kBMMaxShift = 250;
+ static const int kBMMaxShift = Isolate::kBMMaxShift;
// Reduce alphabet to this size.
// One of the tables used by Boyer-Moore and Boyer-Moore-Horspool has size
@@ -54,7 +54,7 @@ class StringSearchBase {
// For needles using only characters in the same Unicode 256-code point page,
// there is no search speed degradation.
static const int kAsciiAlphabetSize = 128;
- static const int kUC16AlphabetSize = 256;
+ static const int kUC16AlphabetSize = Isolate::kUC16AlphabetSize;
// Bad-char shift table stored in the state. It's length is the alphabet size.
// For patterns below this length, the skip length of Boyer-Moore is too short
@@ -69,25 +69,16 @@ class StringSearchBase {
return String::IsAscii(string.start(), string.length());
}
- // The following tables are shared by all searches.
- // TODO(lrn): Introduce a way for a pattern to keep its tables
- // between searches (e.g., for an Atom RegExp).
-
- // Store for the BoyerMoore(Horspool) bad char shift table.
- static int kBadCharShiftTable[kUC16AlphabetSize];
- // Store for the BoyerMoore good suffix shift table.
- static int kGoodSuffixShiftTable[kBMMaxShift + 1];
- // Table used temporarily while building the BoyerMoore good suffix
- // shift table.
- static int kSuffixTable[kBMMaxShift + 1];
+ friend class Isolate;
};
template <typename PatternChar, typename SubjectChar>
class StringSearch : private StringSearchBase {
public:
- explicit StringSearch(Vector<const PatternChar> pattern)
- : pattern_(pattern),
+ StringSearch(Isolate* isolate, Vector<const PatternChar> pattern)
+ : isolate_(isolate),
+ pattern_(pattern),
start_(Max(0, pattern.length() - kBMMaxShift)) {
if (sizeof(PatternChar) > sizeof(SubjectChar)) {
if (!IsAsciiString(pattern_)) {
@@ -175,24 +166,33 @@ class StringSearch : private StringSearchBase {
return bad_char_occurrence[equiv_class];
}
+ // The following tables are shared by all searches.
+ // TODO(lrn): Introduce a way for a pattern to keep its tables
+ // between searches (e.g., for an Atom RegExp).
+
+ // Store for the BoyerMoore(Horspool) bad char shift table.
// Return a table covering the last kBMMaxShift+1 positions of
// pattern.
int* bad_char_table() {
- return kBadCharShiftTable;
+ return isolate_->bad_char_shift_table();
}
+ // Store for the BoyerMoore good suffix shift table.
int* good_suffix_shift_table() {
// Return biased pointer that maps the range [start_..pattern_.length()
// to the kGoodSuffixShiftTable array.
- return kGoodSuffixShiftTable - start_;
+ return isolate_->good_suffix_shift_table() - start_;
}
+ // Table used temporarily while building the BoyerMoore good suffix
+ // shift table.
int* suffix_table() {
// Return biased pointer that maps the range [start_..pattern_.length()
// to the kSuffixTable array.
- return kSuffixTable - start_;
+ return isolate_->suffix_table() - start_;
}
+ Isolate* isolate_;
// The pattern to search for.
Vector<const PatternChar> pattern_;
// Pointer to implementation of the search.
@@ -555,10 +555,11 @@ int StringSearch<PatternChar, SubjectChar>::InitialSearch(
// object should be constructed once and the Search function then called
// for each search.
template <typename SubjectChar, typename PatternChar>
-static int SearchString(Vector<const SubjectChar> subject,
+static int SearchString(Isolate* isolate,
+ Vector<const SubjectChar> subject,
Vector<const PatternChar> pattern,
int start_index) {
- StringSearch<PatternChar, SubjectChar> search(pattern);
+ StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
return search.Search(subject, start_index);
}
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 7abd1bbe..aea14204 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -34,9 +34,6 @@ namespace v8 {
namespace internal {
static const int kMentionedObjectCacheMaxSize = 256;
-static List<HeapObject*, PreallocatedStorage>* debug_object_cache = NULL;
-static Object* current_security_token = NULL;
-
char* HeapStringAllocator::allocate(unsigned bytes) {
space_ = NewArray<char>(bytes);
@@ -195,6 +192,8 @@ void StringStream::PrintObject(Object* o) {
return;
}
if (o->IsHeapObject()) {
+ DebugObjectCache* debug_object_cache = Isolate::Current()->
+ string_stream_debug_object_cache();
for (int i = 0; i < debug_object_cache->length(); i++) {
if ((*debug_object_cache)[i] == o) {
Add("#%d#", i);
@@ -260,7 +259,7 @@ SmartPointer<const char> StringStream::ToCString() const {
void StringStream::Log() {
- LOG(StringEvent("StackDump", buffer_));
+ LOG(ISOLATE, StringEvent("StackDump", buffer_));
}
@@ -281,22 +280,25 @@ void StringStream::OutputToFile(FILE* out) {
Handle<String> StringStream::ToString() {
- return Factory::NewStringFromUtf8(Vector<const char>(buffer_, length_));
+ return FACTORY->NewStringFromUtf8(Vector<const char>(buffer_, length_));
}
void StringStream::ClearMentionedObjectCache() {
- current_security_token = NULL;
- if (debug_object_cache == NULL) {
- debug_object_cache = new List<HeapObject*, PreallocatedStorage>(0);
+ Isolate* isolate = Isolate::Current();
+ isolate->set_string_stream_current_security_token(NULL);
+ if (isolate->string_stream_debug_object_cache() == NULL) {
+ isolate->set_string_stream_debug_object_cache(
+ new List<HeapObject*, PreallocatedStorage>(0));
}
- debug_object_cache->Clear();
+ isolate->string_stream_debug_object_cache()->Clear();
}
#ifdef DEBUG
bool StringStream::IsMentionedObjectCacheClear() {
- return (debug_object_cache->length() == 0);
+ return (
+ Isolate::Current()->string_stream_debug_object_cache()->length() == 0);
}
#endif
@@ -338,7 +340,7 @@ void StringStream::PrintName(Object* name) {
void StringStream::PrintUsingMap(JSObject* js_object) {
Map* map = js_object->map();
- if (!Heap::Contains(map) ||
+ if (!HEAP->Contains(map) ||
!map->IsHeapObject() ||
!map->IsMap()) {
Add("<Invalid map>\n");
@@ -375,9 +377,10 @@ void StringStream::PrintUsingMap(JSObject* js_object) {
void StringStream::PrintFixedArray(FixedArray* array, unsigned int limit) {
+ Heap* heap = HEAP;
for (unsigned int i = 0; i < 10 && i < limit; i++) {
Object* element = array->get(i);
- if (element != Heap::the_hole_value()) {
+ if (element != heap->the_hole_value()) {
for (int len = 1; len < 18; len++)
Put(' ');
Add("%d: %o\n", i, array->get(i));
@@ -412,6 +415,8 @@ void StringStream::PrintByteArray(ByteArray* byte_array) {
void StringStream::PrintMentionedObjectCache() {
+ DebugObjectCache* debug_object_cache =
+ Isolate::Current()->string_stream_debug_object_cache();
Add("==== Key ============================================\n\n");
for (int i = 0; i < debug_object_cache->length(); i++) {
HeapObject* printee = (*debug_object_cache)[i];
@@ -444,12 +449,14 @@ void StringStream::PrintMentionedObjectCache() {
void StringStream::PrintSecurityTokenIfChanged(Object* f) {
- if (!f->IsHeapObject() || !Heap::Contains(HeapObject::cast(f))) {
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+ if (!f->IsHeapObject() || !heap->Contains(HeapObject::cast(f))) {
return;
}
Map* map = HeapObject::cast(f)->map();
if (!map->IsHeapObject() ||
- !Heap::Contains(map) ||
+ !heap->Contains(map) ||
!map->IsMap() ||
!f->IsJSFunction()) {
return;
@@ -458,17 +465,17 @@ void StringStream::PrintSecurityTokenIfChanged(Object* f) {
JSFunction* fun = JSFunction::cast(f);
Object* perhaps_context = fun->unchecked_context();
if (perhaps_context->IsHeapObject() &&
- Heap::Contains(HeapObject::cast(perhaps_context)) &&
+ heap->Contains(HeapObject::cast(perhaps_context)) &&
perhaps_context->IsContext()) {
Context* context = fun->context();
- if (!Heap::Contains(context)) {
+ if (!heap->Contains(context)) {
Add("(Function context is outside heap)\n");
return;
}
Object* token = context->global_context()->security_token();
- if (token != current_security_token) {
+ if (token != isolate->string_stream_current_security_token()) {
Add("Security context: %o\n", token);
- current_security_token = token;
+ isolate->set_string_stream_current_security_token(token);
}
} else {
Add("(Function context is corrupt)\n");
@@ -478,8 +485,8 @@ void StringStream::PrintSecurityTokenIfChanged(Object* f) {
void StringStream::PrintFunction(Object* f, Object* receiver, Code** code) {
if (f->IsHeapObject() &&
- Heap::Contains(HeapObject::cast(f)) &&
- Heap::Contains(HeapObject::cast(f)->map()) &&
+ HEAP->Contains(HeapObject::cast(f)) &&
+ HEAP->Contains(HeapObject::cast(f)->map()) &&
HeapObject::cast(f)->map()->IsMap()) {
if (f->IsJSFunction()) {
JSFunction* fun = JSFunction::cast(f);
@@ -506,11 +513,11 @@ void StringStream::PrintFunction(Object* f, Object* receiver, Code** code) {
Add("/* warning: 'function' was not a heap object */ ");
return;
}
- if (!Heap::Contains(HeapObject::cast(f))) {
+ if (!HEAP->Contains(HeapObject::cast(f))) {
Add("/* warning: 'function' was not on the heap */ ");
return;
}
- if (!Heap::Contains(HeapObject::cast(f)->map())) {
+ if (!HEAP->Contains(HeapObject::cast(f)->map())) {
Add("/* warning: function's map was not on the heap */ ");
return;
}
@@ -526,10 +533,11 @@ void StringStream::PrintFunction(Object* f, Object* receiver, Code** code) {
void StringStream::PrintPrototype(JSFunction* fun, Object* receiver) {
Object* name = fun->shared()->name();
bool print_name = false;
- for (Object* p = receiver; p != Heap::null_value(); p = p->GetPrototype()) {
+ Heap* heap = HEAP;
+ for (Object* p = receiver; p != heap->null_value(); p = p->GetPrototype()) {
if (p->IsJSObject()) {
Object* key = JSObject::cast(p)->SlowReverseLookup(fun);
- if (key != Heap::undefined_value()) {
+ if (key != heap->undefined_value()) {
if (!name->IsString() ||
!key->IsString() ||
!String::cast(name)->Equals(String::cast(key))) {
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index f23f3825..435e71d1 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -41,8 +41,12 @@ namespace internal {
// StubCache implementation.
-StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize];
-StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize];
+StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
+ ASSERT(isolate == Isolate::Current());
+ memset(primary_, 0, sizeof(primary_[0]) * StubCache::kPrimaryTableSize);
+ memset(secondary_, 0, sizeof(secondary_[0]) * StubCache::kSecondaryTableSize);
+}
+
void StubCache::Initialize(bool create_heap_objects) {
ASSERT(IsPowerOf2(kPrimaryTableSize));
@@ -60,7 +64,7 @@ Code* StubCache::Set(String* name, Map* map, Code* code) {
// Validate that the name does not move on scavenge, and that we
// can use identity checks instead of string equality checks.
- ASSERT(!Heap::InNewSpace(name));
+ ASSERT(!heap()->InNewSpace(name));
ASSERT(name->IsSymbol());
// The state bits are not important to the hash function because
@@ -80,7 +84,7 @@ Code* StubCache::Set(String* name, Map* map, Code* code) {
// If the primary entry has useful data in it, we retire it to the
// secondary cache before overwriting it.
- if (hit != Builtins::builtin(Builtins::Illegal)) {
+ if (hit != isolate_->builtins()->builtin(Builtins::kIllegal)) {
Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
int secondary_offset =
SecondaryOffset(primary->key, primary_flags, primary_offset);
@@ -104,10 +108,10 @@ MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
// there are global objects involved, we need to check global
// property cells in the stub and therefore the stub will be
// specific to the name.
- String* cache_name = Heap::empty_string();
+ String* cache_name = heap()->empty_string();
if (receiver->IsGlobalObject()) cache_name = name;
JSObject* last = receiver;
- while (last->GetPrototype() != Heap::null_value()) {
+ while (last->GetPrototype() != heap()->null_value()) {
last = JSObject::cast(last->GetPrototype());
if (last->IsGlobalObject()) cache_name = name;
}
@@ -122,7 +126,8 @@ MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
compiler.CompileLoadNonexistent(cache_name, receiver, last);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -147,7 +152,8 @@ MaybeObject* StubCache::ComputeLoadField(String* name,
compiler.CompileLoadField(receiver, holder, field_index, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -173,7 +179,8 @@ MaybeObject* StubCache::ComputeLoadCallback(String* name,
compiler.CompileLoadCallback(name, receiver, holder, callback);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -199,7 +206,8 @@ MaybeObject* StubCache::ComputeLoadConstant(String* name,
compiler.CompileLoadConstant(receiver, holder, value, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -223,7 +231,8 @@ MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
compiler.CompileLoadInterceptor(receiver, holder, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -236,7 +245,7 @@ MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
MaybeObject* StubCache::ComputeLoadNormal() {
- return Builtins::builtin(Builtins::LoadIC_Normal);
+ return isolate_->builtins()->builtin(Builtins::kLoadIC_Normal);
}
@@ -257,7 +266,8 @@ MaybeObject* StubCache::ComputeLoadGlobal(String* name,
is_dont_delete);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -282,7 +292,8 @@ MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
compiler.CompileLoadField(name, receiver, holder, field_index);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -308,7 +319,8 @@ MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
compiler.CompileLoadConstant(name, receiver, holder, value);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -333,7 +345,8 @@ MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
compiler.CompileLoadInterceptor(receiver, holder, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -359,7 +372,8 @@ MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
compiler.CompileLoadCallback(name, receiver, holder, callback);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -383,7 +397,8 @@ MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
{ MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -406,7 +421,8 @@ MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
{ MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
@@ -428,7 +444,8 @@ MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
{ MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -449,41 +466,15 @@ MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) {
// keyed loads that are not array elements go through a generic builtin stub.
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
- String* name = Heap::KeyedLoadSpecialized_symbol();
+ String* name = heap()->KeyedLoadSpecialized_symbol();
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
KeyedLoadStubCompiler compiler;
{ MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
- return code;
-}
-
-
-MaybeObject* StubCache::ComputeKeyedLoadPixelArray(JSObject* receiver) {
- // Using NORMAL as the PropertyType for array element loads is a misuse. The
- // generated stub always accesses fast elements, not slow-mode fields, but
- // some property type is required for the stub lookup. Note that overloading
- // the NORMAL PropertyType is only safe as long as no stubs are generated for
- // other keyed field loads. This is guaranteed to be the case since all field
- // keyed loads that are not array elements go through a generic builtin stub.
- Code::Flags flags =
- Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
- String* name = Heap::KeyedLoadPixelArray_symbol();
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedLoadStubCompiler compiler;
- { MaybeObject* maybe_code = compiler.CompileLoadPixelArray(receiver);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
Object* result;
{ MaybeObject* maybe_result =
receiver->UpdateMapCodeCache(name, Code::cast(code));
@@ -509,7 +500,8 @@ MaybeObject* StubCache::ComputeStoreField(String* name,
compiler.CompileStoreField(receiver, field_index, transition, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -526,43 +518,15 @@ MaybeObject* StubCache::ComputeKeyedStoreSpecialized(
StrictModeFlag strict_mode) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
- String* name = Heap::KeyedStoreSpecialized_symbol();
+ String* name = heap()->KeyedStoreSpecialized_symbol();
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
KeyedStoreStubCompiler compiler(strict_mode);
{ MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
- Object* result;
- { MaybeObject* maybe_result =
- receiver->UpdateMapCodeCache(name, Code::cast(code));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
- }
- return code;
-}
-
-
-MaybeObject* StubCache::ComputeKeyedStorePixelArray(
- JSObject* receiver,
- StrictModeFlag strict_mode) {
- // Using NORMAL as the PropertyType for array element stores is a misuse. The
- // generated stub always accesses fast elements, not slow-mode fields, but
- // some property type is required for the stub lookup. Note that overloading
- // the NORMAL PropertyType is only safe as long as no stubs are generated for
- // other keyed field stores. This is guaranteed to be the case since all field
- // keyed stores that are not array elements go through a generic builtin stub.
- Code::Flags flags =
- Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
- String* name = Heap::KeyedStorePixelArray_symbol();
- Object* code = receiver->map()->FindInCodeCache(name, flags);
- if (code->IsUndefined()) {
- KeyedStoreStubCompiler compiler(strict_mode);
- { MaybeObject* maybe_code = compiler.CompileStorePixelArray(receiver);
- if (!maybe_code->ToObject(&code)) return maybe_code;
- }
- PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
Object* result;
{ MaybeObject* maybe_result =
receiver->UpdateMapCodeCache(name, Code::cast(code));
@@ -591,12 +555,64 @@ ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
return kExternalUnsignedIntArray;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
return kExternalFloatArray;
+ case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ return kExternalPixelArray;
default:
UNREACHABLE();
return static_cast<ExternalArrayType>(0);
}
}
+String* ExternalArrayTypeToStubName(Heap* heap,
+ ExternalArrayType array_type,
+ bool is_store) {
+ if (is_store) {
+ switch (array_type) {
+ case kExternalByteArray:
+ return heap->KeyedStoreExternalByteArray_symbol();
+ case kExternalUnsignedByteArray:
+ return heap->KeyedStoreExternalUnsignedByteArray_symbol();
+ case kExternalShortArray:
+ return heap->KeyedStoreExternalShortArray_symbol();
+ case kExternalUnsignedShortArray:
+ return heap->KeyedStoreExternalUnsignedShortArray_symbol();
+ case kExternalIntArray:
+ return heap->KeyedStoreExternalIntArray_symbol();
+ case kExternalUnsignedIntArray:
+ return heap->KeyedStoreExternalUnsignedIntArray_symbol();
+ case kExternalFloatArray:
+ return heap->KeyedStoreExternalFloatArray_symbol();
+ case kExternalPixelArray:
+ return heap->KeyedStoreExternalPixelArray_symbol();
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+ } else {
+ switch (array_type) {
+ case kExternalByteArray:
+ return heap->KeyedLoadExternalByteArray_symbol();
+ case kExternalUnsignedByteArray:
+ return heap->KeyedLoadExternalUnsignedByteArray_symbol();
+ case kExternalShortArray:
+ return heap->KeyedLoadExternalShortArray_symbol();
+ case kExternalUnsignedShortArray:
+ return heap->KeyedLoadExternalUnsignedShortArray_symbol();
+ case kExternalIntArray:
+ return heap->KeyedLoadExternalIntArray_symbol();
+ case kExternalUnsignedIntArray:
+ return heap->KeyedLoadExternalUnsignedIntArray_symbol();
+ case kExternalFloatArray:
+ return heap->KeyedLoadExternalFloatArray_symbol();
+ case kExternalPixelArray:
+ return heap->KeyedLoadExternalPixelArray_symbol();
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+ }
+}
+
} // anonymous namespace
@@ -606,36 +622,35 @@ MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
StrictModeFlag strict_mode) {
Code::Flags flags =
Code::ComputeMonomorphicFlags(
- is_store ? Code::KEYED_STORE_IC : Code::KEYED_LOAD_IC,
+ is_store ? Code::KEYED_EXTERNAL_ARRAY_STORE_IC :
+ Code::KEYED_EXTERNAL_ARRAY_LOAD_IC,
NORMAL,
strict_mode);
ExternalArrayType array_type =
ElementsKindToExternalArrayType(receiver->GetElementsKind());
- String* name =
- is_store ? Heap::KeyedStoreExternalArray_symbol()
- : Heap::KeyedLoadExternalArray_symbol();
- // Use the global maps for the particular external array types,
- // rather than the receiver's map, when looking up the cached code,
- // so that we actually canonicalize these stubs.
- Map* map = Heap::MapForExternalArrayType(array_type);
- Object* code = map->FindInCodeCache(name, flags);
+ String* name = ExternalArrayTypeToStubName(heap(), array_type, is_store);
+ Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
ExternalArrayStubCompiler compiler;
- { MaybeObject* maybe_code = is_store
- ? compiler.CompileKeyedStoreStub(array_type, flags)
- : compiler.CompileKeyedLoadStub(array_type, flags);
+ { MaybeObject* maybe_code =
+ is_store ?
+ compiler.CompileKeyedStoreStub(receiver, array_type, flags) :
+ compiler.CompileKeyedLoadStub(receiver, array_type, flags);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
+ Code::cast(code)->set_external_array_type(array_type);
if (is_store) {
- PROFILE(
- CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG,
+ Code::cast(code), 0));
} else {
- PROFILE(
- CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG,
+ Code::cast(code), 0));
}
Object* result;
{ MaybeObject* maybe_result =
- map->UpdateCodeCache(name, Code::cast(code));
+ receiver->UpdateMapCodeCache(name, Code::cast(code));
if (!maybe_result->ToObject(&result)) return maybe_result;
}
}
@@ -644,9 +659,9 @@ MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
- return Builtins::builtin((strict_mode == kStrictMode)
- ? Builtins::StoreIC_Normal_Strict
- : Builtins::StoreIC_Normal);
+ return isolate_->builtins()->builtin((strict_mode == kStrictMode)
+ ? Builtins::kStoreIC_Normal_Strict
+ : Builtins::kStoreIC_Normal);
}
@@ -663,7 +678,8 @@ MaybeObject* StubCache::ComputeStoreGlobal(String* name,
compiler.CompileStoreGlobal(receiver, cell, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -690,7 +706,8 @@ MaybeObject* StubCache::ComputeStoreCallback(
compiler.CompileStoreCallback(receiver, callback, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -715,7 +732,8 @@ MaybeObject* StubCache::ComputeStoreInterceptor(
compiler.CompileStoreInterceptor(receiver, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate_,
+ CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -742,8 +760,9 @@ MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
compiler.CompileStoreField(receiver, field_index, transition, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
- PROFILE(CodeCreateEvent(
- Logger::KEYED_STORE_IC_TAG, Code::cast(code), name));
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
+ Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
Object* result;
{ MaybeObject* maybe_result =
@@ -802,7 +821,8 @@ MaybeObject* StubCache::ComputeCallConstant(int argc,
}
Code::cast(code)->set_check_type(check);
ASSERT_EQ(flags, Code::cast(code)->flags());
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
+ PROFILE(isolate_,
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
Object* result;
@@ -852,7 +872,8 @@ MaybeObject* StubCache::ComputeCallField(int argc,
if (!maybe_code->ToObject(&code)) return maybe_code;
}
ASSERT_EQ(flags, Code::cast(code)->flags());
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
+ PROFILE(isolate_,
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
Object* result;
@@ -897,7 +918,8 @@ MaybeObject* StubCache::ComputeCallInterceptor(int argc,
if (!maybe_code->ToObject(&code)) return maybe_code;
}
ASSERT_EQ(flags, Code::cast(code)->flags());
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
Object* result;
@@ -954,7 +976,8 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc,
if (!maybe_code->ToObject(&code)) return maybe_code;
}
ASSERT_EQ(flags, Code::cast(code)->flags());
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Code::cast(code), name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
Object* result;
@@ -967,45 +990,48 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc,
}
-static Object* GetProbeValue(Code::Flags flags) {
+static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
// Use raw_unchecked... so we don't get assert failures during GC.
- NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache();
- int entry = dictionary->FindEntry(flags);
+ NumberDictionary* dictionary =
+ isolate->heap()->raw_unchecked_non_monomorphic_cache();
+ int entry = dictionary->FindEntry(isolate, flags);
if (entry != -1) return dictionary->ValueAt(entry);
- return Heap::raw_unchecked_undefined_value();
+ return isolate->heap()->raw_unchecked_undefined_value();
}
-MUST_USE_RESULT static MaybeObject* ProbeCache(Code::Flags flags) {
- Object* probe = GetProbeValue(flags);
- if (probe != Heap::undefined_value()) return probe;
+MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
+ Code::Flags flags) {
+ Heap* heap = isolate->heap();
+ Object* probe = GetProbeValue(isolate, flags);
+ if (probe != heap->undefined_value()) return probe;
// Seed the cache with an undefined value to make sure that any
// generated code object can always be inserted into the cache
// without causing allocation failures.
Object* result;
{ MaybeObject* maybe_result =
- Heap::non_monomorphic_cache()->AtNumberPut(flags,
- Heap::undefined_value());
+ heap->non_monomorphic_cache()->AtNumberPut(flags,
+ heap->undefined_value());
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result));
+ heap->public_set_non_monomorphic_cache(NumberDictionary::cast(result));
return probe;
}
-static MaybeObject* FillCache(MaybeObject* maybe_code) {
+static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) {
Object* code;
if (maybe_code->ToObject(&code)) {
if (code->IsCode()) {
- int entry =
- Heap::non_monomorphic_cache()->FindEntry(
- Code::cast(code)->flags());
+ Heap* heap = isolate->heap();
+ int entry = heap->non_monomorphic_cache()->FindEntry(
+ Code::cast(code)->flags());
// The entry must be present see comment in ProbeCache.
ASSERT(entry != -1);
- ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
- Heap::undefined_value());
- Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
- CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
+ ASSERT(heap->non_monomorphic_cache()->ValueAt(entry) ==
+ heap->undefined_value());
+ heap->non_monomorphic_cache()->ValueAtPut(entry, code);
+ CHECK(GetProbeValue(isolate, Code::cast(code)->flags()) == code);
}
}
return maybe_code;
@@ -1021,8 +1047,8 @@ Code* StubCache::FindCallInitialize(int argc,
Code::kNoExtraICState,
NORMAL,
argc);
- Object* result = ProbeCache(flags)->ToObjectUnchecked();
- ASSERT(!result->IsUndefined());
+ Object* result = ProbeCache(isolate(), flags)->ToObjectUnchecked();
+ ASSERT(result != heap()->undefined_value());
// This might be called during the marking phase of the collector
// hence the unchecked cast.
return reinterpret_cast<Code*>(result);
@@ -1039,12 +1065,12 @@ MaybeObject* StubCache::ComputeCallInitialize(int argc,
NORMAL,
argc);
Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(flags);
+ { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
}
if (!probe->IsUndefined()) return probe;
StubCompiler compiler;
- return FillCache(compiler.CompileCallInitialize(flags));
+ return FillCache(isolate_, compiler.CompileCallInitialize(flags));
}
@@ -1057,7 +1083,8 @@ Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
// that it needs so we need to ensure it is generated already.
ComputeCallInitialize(argc, NOT_IN_LOOP);
}
- CALL_HEAP_FUNCTION(ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
+ CALL_HEAP_FUNCTION(isolate_,
+ ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
}
@@ -1072,6 +1099,7 @@ Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
}
CALL_HEAP_FUNCTION(
+ isolate_,
ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
}
@@ -1086,12 +1114,12 @@ MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
NORMAL,
argc);
Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(flags);
+ { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
}
if (!probe->IsUndefined()) return probe;
StubCompiler compiler;
- return FillCache(compiler.CompileCallPreMonomorphic(flags));
+ return FillCache(isolate_, compiler.CompileCallPreMonomorphic(flags));
}
@@ -1105,12 +1133,12 @@ MaybeObject* StubCache::ComputeCallNormal(int argc,
NORMAL,
argc);
Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(flags);
+ { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
}
if (!probe->IsUndefined()) return probe;
StubCompiler compiler;
- return FillCache(compiler.CompileCallNormal(flags));
+ return FillCache(isolate_, compiler.CompileCallNormal(flags));
}
@@ -1124,12 +1152,12 @@ MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
NORMAL,
argc);
Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(flags);
+ { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
}
if (!probe->IsUndefined()) return probe;
StubCompiler compiler;
- return FillCache(compiler.CompileCallMegamorphic(flags));
+ return FillCache(isolate_, compiler.CompileCallMegamorphic(flags));
}
@@ -1144,12 +1172,12 @@ MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
argc,
OWN_MAP);
Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(flags);
+ { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
}
if (!probe->IsUndefined()) return probe;
StubCompiler compiler;
- return FillCache(compiler.CompileCallMiss(flags));
+ return FillCache(isolate_, compiler.CompileCallMiss(flags));
}
@@ -1162,12 +1190,12 @@ MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
NORMAL,
argc);
Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(flags);
+ { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
}
if (!probe->IsUndefined()) return probe;
StubCompiler compiler;
- return FillCache(compiler.CompileCallDebugBreak(flags));
+ return FillCache(isolate_, compiler.CompileCallDebugBreak(flags));
}
@@ -1180,24 +1208,26 @@ MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
NORMAL,
argc);
Object* probe;
- { MaybeObject* maybe_probe = ProbeCache(flags);
+ { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
}
if (!probe->IsUndefined()) return probe;
StubCompiler compiler;
- return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
+ return FillCache(isolate_, compiler.CompileCallDebugPrepareStepIn(flags));
}
#endif
void StubCache::Clear() {
for (int i = 0; i < kPrimaryTableSize; i++) {
- primary_[i].key = Heap::empty_string();
- primary_[i].value = Builtins::builtin(Builtins::Illegal);
+ primary_[i].key = heap()->empty_string();
+ primary_[i].value = isolate_->builtins()->builtin(
+ Builtins::kIllegal);
}
for (int j = 0; j < kSecondaryTableSize; j++) {
- secondary_[j].key = Heap::empty_string();
- secondary_[j].value = Builtins::builtin(Builtins::Illegal);
+ secondary_[j].key = heap()->empty_string();
+ secondary_[j].value = isolate_->builtins()->builtin(
+ Builtins::kIllegal);
}
}
@@ -1248,7 +1278,8 @@ void StubCache::CollectMatchingMaps(ZoneMapList* types,
// StubCompiler implementation.
-MaybeObject* LoadCallbackProperty(Arguments args) {
+MaybeObject* LoadCallbackProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args[0]->IsJSObject());
ASSERT(args[1]->IsJSObject());
AccessorInfo* callback = AccessorInfo::cast(args[3]);
@@ -1256,21 +1287,22 @@ MaybeObject* LoadCallbackProperty(Arguments args) {
v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
ASSERT(fun != NULL);
v8::AccessorInfo info(&args[0]);
- HandleScope scope;
+ HandleScope scope(isolate);
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
- ExternalCallbackScope call_scope(getter_address);
+ VMState state(isolate, EXTERNAL);
+ ExternalCallbackScope call_scope(isolate, getter_address);
result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
- if (result.IsEmpty()) return Heap::undefined_value();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
+ if (result.IsEmpty()) return HEAP->undefined_value();
return *v8::Utils::OpenHandle(*result);
}
-MaybeObject* StoreCallbackProperty(Arguments args) {
+MaybeObject* StoreCallbackProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
JSObject* recv = JSObject::cast(args[0]);
AccessorInfo* callback = AccessorInfo::cast(args[1]);
Address setter_address = v8::ToCData<Address>(callback->setter());
@@ -1278,17 +1310,17 @@ MaybeObject* StoreCallbackProperty(Arguments args) {
ASSERT(fun != NULL);
Handle<String> name = args.at<String>(2);
Handle<Object> value = args.at<Object>(3);
- HandleScope scope;
- LOG(ApiNamedPropertyAccess("store", recv, *name));
- CustomArguments custom_args(callback->data(), recv, recv);
+ HandleScope scope(isolate);
+ LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
+ CustomArguments custom_args(isolate, callback->data(), recv, recv);
v8::AccessorInfo info(custom_args.end());
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
- ExternalCallbackScope call_scope(setter_address);
+ VMState state(isolate, EXTERNAL);
+ ExternalCallbackScope call_scope(isolate, setter_address);
fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return *value;
}
@@ -1303,7 +1335,8 @@ static const int kAccessorInfoOffsetInInterceptorArgs = 2;
* Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
* provide any value for the given name.
*/
-MaybeObject* LoadPropertyWithInterceptorOnly(Arguments args) {
+MaybeObject* LoadPropertyWithInterceptorOnly(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
Handle<String> name_handle = args.at<String>(0);
Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
@@ -1320,20 +1353,20 @@ MaybeObject* LoadPropertyWithInterceptorOnly(Arguments args) {
// Use the interceptor getter.
v8::AccessorInfo info(args.arguments() -
kAccessorInfoOffsetInInterceptorArgs);
- HandleScope scope;
+ HandleScope scope(isolate);
v8::Handle<v8::Value> r;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
r = getter(v8::Utils::ToLocal(name_handle), info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!r.IsEmpty()) {
return *v8::Utils::OpenHandle(*r);
}
}
- return Heap::no_interceptor_result_sentinel();
+ return isolate->heap()->no_interceptor_result_sentinel();
}
@@ -1341,17 +1374,17 @@ static MaybeObject* ThrowReferenceError(String* name) {
// If the load is non-contextual, just return the undefined result.
// Note that both keyed and non-keyed loads may end up here, so we
// can't use either LoadIC or KeyedLoadIC constructors.
- IC ic(IC::NO_EXTRA_FRAME);
+ IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
- if (!ic.SlowIsContextual()) return Heap::undefined_value();
+ if (!ic.SlowIsContextual()) return HEAP->undefined_value();
// Throw a reference error.
HandleScope scope;
Handle<String> name_handle(name);
Handle<Object> error =
- Factory::NewReferenceError("not_defined",
+ FACTORY->NewReferenceError("not_defined",
HandleVector(&name_handle, 1));
- return Top::Throw(*error);
+ return Isolate::Current()->Throw(*error);
}
@@ -1364,6 +1397,8 @@ static MaybeObject* LoadWithInterceptor(Arguments* args,
Handle<JSObject> holder_handle = args->at<JSObject>(3);
ASSERT(args->length() == 5); // Last arg is data object.
+ Isolate* isolate = receiver_handle->GetIsolate();
+
Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
v8::NamedPropertyGetter getter =
FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
@@ -1373,14 +1408,14 @@ static MaybeObject* LoadWithInterceptor(Arguments* args,
// Use the interceptor getter.
v8::AccessorInfo info(args->arguments() -
kAccessorInfoOffsetInInterceptorArgs);
- HandleScope scope;
+ HandleScope scope(isolate);
v8::Handle<v8::Value> r;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(isolate, EXTERNAL);
r = getter(v8::Utils::ToLocal(name_handle), info);
}
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!r.IsEmpty()) {
*attrs = NONE;
return *v8::Utils::OpenHandle(*r);
@@ -1391,7 +1426,7 @@ static MaybeObject* LoadWithInterceptor(Arguments* args,
*receiver_handle,
*name_handle,
attrs);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return result;
}
@@ -1400,7 +1435,8 @@ static MaybeObject* LoadWithInterceptor(Arguments* args,
* Loads a property with an interceptor performing post interceptor
* lookup if interceptor failed.
*/
-MaybeObject* LoadPropertyWithInterceptorForLoad(Arguments args) {
+MaybeObject* LoadPropertyWithInterceptorForLoad(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
PropertyAttributes attr = NONE;
Object* result;
{ MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
@@ -1413,10 +1449,11 @@ MaybeObject* LoadPropertyWithInterceptorForLoad(Arguments args) {
}
-MaybeObject* LoadPropertyWithInterceptorForCall(Arguments args) {
+MaybeObject* LoadPropertyWithInterceptorForCall(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
PropertyAttributes attr;
MaybeObject* result = LoadWithInterceptor(&args, &attr);
- RETURN_IF_SCHEDULED_EXCEPTION();
+ RETURN_IF_SCHEDULED_EXCEPTION(isolate);
// This is call IC. In this case, we simply return the undefined result which
// will lead to an exception when trying to invoke the result as a
// function.
@@ -1424,7 +1461,8 @@ MaybeObject* LoadPropertyWithInterceptorForCall(Arguments args) {
}
-MaybeObject* StoreInterceptorProperty(Arguments args) {
+MaybeObject* StoreInterceptorProperty(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
ASSERT(args.length() == 4);
JSObject* recv = JSObject::cast(args[0]);
String* name = String::cast(args[1]);
@@ -1440,7 +1478,8 @@ MaybeObject* StoreInterceptorProperty(Arguments args) {
}
-MaybeObject* KeyedLoadPropertyWithInterceptor(Arguments args) {
+MaybeObject* KeyedLoadPropertyWithInterceptor(RUNTIME_CALLING_CONVENTION) {
+ RUNTIME_GET_ISOLATE;
JSObject* receiver = JSObject::cast(args[0]);
ASSERT(Smi::cast(args[1])->value() >= 0);
uint32_t index = Smi::cast(args[1])->value();
@@ -1449,7 +1488,7 @@ MaybeObject* KeyedLoadPropertyWithInterceptor(Arguments args) {
MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
- HandleScope scope;
+ HandleScope scope(isolate());
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
if (kind == Code::CALL_IC) {
@@ -1462,10 +1501,11 @@ MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
GetCodeWithFlags(flags, "CompileCallInitialize");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- Counters::call_initialize_stubs.Increment();
+ isolate()->counters()->call_initialize_stubs()->Increment();
Code* code = Code::cast(result);
USE(code);
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
code, code->arguments_count()));
GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
return result;
@@ -1473,7 +1513,7 @@ MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
- HandleScope scope;
+ HandleScope scope(isolate());
int argc = Code::ExtractArgumentsCountFromFlags(flags);
// The code of the PreMonomorphic stub is the same as the code
// of the Initialized stub. They just differ on the code object flags.
@@ -1488,10 +1528,11 @@ MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- Counters::call_premonomorphic_stubs.Increment();
+ isolate()->counters()->call_premonomorphic_stubs()->Increment();
Code* code = Code::cast(result);
USE(code);
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
code, code->arguments_count()));
GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
return result;
@@ -1499,7 +1540,7 @@ MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
- HandleScope scope;
+ HandleScope scope(isolate());
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
if (kind == Code::CALL_IC) {
@@ -1511,10 +1552,11 @@ MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
{ MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- Counters::call_normal_stubs.Increment();
+ isolate()->counters()->call_normal_stubs()->Increment();
Code* code = Code::cast(result);
USE(code);
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
code, code->arguments_count()));
GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
return result;
@@ -1522,7 +1564,7 @@ MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
- HandleScope scope;
+ HandleScope scope(isolate());
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
if (kind == Code::CALL_IC) {
@@ -1530,16 +1572,16 @@ MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
} else {
KeyedCallIC::GenerateMegamorphic(masm(), argc);
}
-
Object* result;
{ MaybeObject* maybe_result =
GetCodeWithFlags(flags, "CompileCallMegamorphic");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- Counters::call_megamorphic_stubs.Increment();
+ isolate()->counters()->call_megamorphic_stubs()->Increment();
Code* code = Code::cast(result);
USE(code);
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
code, code->arguments_count()));
GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
return result;
@@ -1547,7 +1589,7 @@ MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
- HandleScope scope;
+ HandleScope scope(isolate());
int argc = Code::ExtractArgumentsCountFromFlags(flags);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
if (kind == Code::CALL_IC) {
@@ -1559,10 +1601,11 @@ MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
{ MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- Counters::call_megamorphic_stubs.Increment();
+ isolate()->counters()->call_megamorphic_stubs()->Increment();
Code* code = Code::cast(result);
USE(code);
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
code, code->arguments_count()));
GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
return result;
@@ -1571,7 +1614,7 @@ MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
#ifdef ENABLE_DEBUGGER_SUPPORT
MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
- HandleScope scope;
+ HandleScope scope(isolate());
Debug::GenerateCallICDebugBreak(masm());
Object* result;
{ MaybeObject* maybe_result =
@@ -1582,14 +1625,15 @@ MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
USE(code);
Code::Kind kind = Code::ExtractKindFromFlags(flags);
USE(kind);
- PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
+ PROFILE(isolate(),
+ CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
code, code->arguments_count()));
return result;
}
MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
- HandleScope scope;
+ HandleScope scope(isolate());
// Use the same code for the the step in preparations as we do for
// the miss case.
int argc = Code::ExtractArgumentsCountFromFlags(flags);
@@ -1606,10 +1650,11 @@ MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
}
Code* code = Code::cast(result);
USE(code);
- PROFILE(CodeCreateEvent(
- CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
- code,
- code->arguments_count()));
+ PROFILE(isolate(),
+ CodeCreateEvent(
+ CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
+ code,
+ code->arguments_count()));
return result;
}
#endif
@@ -1624,7 +1669,7 @@ MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
// Create code object in the heap.
CodeDesc desc;
masm_.GetCode(&desc);
- MaybeObject* result = Heap::CreateCode(desc, flags, masm_.CodeObject());
+ MaybeObject* result = heap()->CreateCode(desc, flags, masm_.CodeObject());
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code_stubs && !result->IsFailure()) {
Code::cast(result->ToObjectUnchecked())->Disassemble(name);
@@ -1649,7 +1694,7 @@ void StubCompiler::LookupPostInterceptor(JSObject* holder,
if (!lookup->IsProperty()) {
lookup->NotFound();
Object* proto = holder->GetPrototype();
- if (proto != Heap::null_value()) {
+ if (!proto->IsNull()) {
proto->Lookup(name, lookup);
}
}
@@ -1661,7 +1706,8 @@ MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
- PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG,
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::LOAD_IC_TAG,
Code::cast(result->ToObjectUnchecked()),
name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
@@ -1676,7 +1722,8 @@ MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
- PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
Code::cast(result->ToObjectUnchecked()),
name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
@@ -1692,7 +1739,8 @@ MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
Code::STORE_IC, type, strict_mode_);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
- PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG,
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::STORE_IC_TAG,
Code::cast(result->ToObjectUnchecked()),
name));
GDBJIT(AddCode(GDBJITInterface::STORE_IC,
@@ -1708,7 +1756,8 @@ MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
Code::KEYED_STORE_IC, type, strict_mode_);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
- PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
Code::cast(result->ToObjectUnchecked()),
name));
GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
@@ -1732,32 +1781,51 @@ CallStubCompiler::CallStubCompiler(int argc,
}
-bool CallStubCompiler::HasCustomCallGenerator(BuiltinFunctionId id) {
+bool CallStubCompiler::HasCustomCallGenerator(JSFunction* function) {
+ SharedFunctionInfo* info = function->shared();
+ if (info->HasBuiltinFunctionId()) {
+ BuiltinFunctionId id = info->builtin_function_id();
#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
- CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
+ CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
#undef CALL_GENERATOR_CASE
+ }
+ CallOptimization optimization(function);
+ if (optimization.is_simple_api_call()) {
+ return true;
+ }
return false;
}
-MaybeObject* CallStubCompiler::CompileCustomCall(BuiltinFunctionId id,
- Object* object,
+MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* fname) {
-#define CALL_GENERATOR_CASE(name) \
- if (id == k##name) { \
- return CallStubCompiler::Compile##name##Call(object, \
- holder, \
- cell, \
- function, \
- fname); \
- }
- CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
+ ASSERT(HasCustomCallGenerator(function));
+
+ SharedFunctionInfo* info = function->shared();
+ if (info->HasBuiltinFunctionId()) {
+ BuiltinFunctionId id = info->builtin_function_id();
+#define CALL_GENERATOR_CASE(name) \
+ if (id == k##name) { \
+ return CallStubCompiler::Compile##name##Call(object, \
+ holder, \
+ cell, \
+ function, \
+ fname); \
+ }
+ CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
#undef CALL_GENERATOR_CASE
- ASSERT(!HasCustomCallGenerator(id));
- return Heap::undefined_value();
+ }
+ CallOptimization optimization(function);
+ ASSERT(optimization.is_simple_api_call());
+ return CompileFastApiCall(optimization,
+ object,
+ holder,
+ cell,
+ function,
+ fname);
}
@@ -1790,7 +1858,7 @@ MaybeObject* ConstructStubCompiler::GetCode() {
}
Code* code = Code::cast(result);
USE(code);
- PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
+ PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
return result;
}
@@ -1870,7 +1938,8 @@ MaybeObject* ExternalArrayStubCompiler::GetCode(Code::Flags flags) {
}
Code* code = Code::cast(result);
USE(code);
- PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
return result;
}
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 6927076c..793f5818 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -28,6 +28,7 @@
#ifndef V8_STUB_CACHE_H_
#define V8_STUB_CACHE_H_
+#include "arguments.h"
#include "macro-assembler.h"
#include "zone-inl.h"
@@ -43,50 +44,62 @@ namespace internal {
// invalidate the cache whenever a prototype map is changed. The stub
// validates the map chain as in the mono-morphic case.
-class SCTableReference;
+class StubCache;
+
+class SCTableReference {
+ public:
+ Address address() const { return address_; }
+
+ private:
+ explicit SCTableReference(Address address) : address_(address) {}
+
+ Address address_;
+
+ friend class StubCache;
+};
-class StubCache : public AllStatic {
+class StubCache {
public:
struct Entry {
String* key;
Code* value;
};
+ void Initialize(bool create_heap_objects);
- static void Initialize(bool create_heap_objects);
// Computes the right stub matching. Inserts the result in the
// cache before returning. This might compile a stub if needed.
- MUST_USE_RESULT static MaybeObject* ComputeLoadNonexistent(
+ MUST_USE_RESULT MaybeObject* ComputeLoadNonexistent(
String* name,
JSObject* receiver);
- MUST_USE_RESULT static MaybeObject* ComputeLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
- int field_index);
+ MUST_USE_RESULT MaybeObject* ComputeLoadField(String* name,
+ JSObject* receiver,
+ JSObject* holder,
+ int field_index);
- MUST_USE_RESULT static MaybeObject* ComputeLoadCallback(
+ MUST_USE_RESULT MaybeObject* ComputeLoadCallback(
String* name,
JSObject* receiver,
JSObject* holder,
AccessorInfo* callback);
- MUST_USE_RESULT static MaybeObject* ComputeLoadConstant(String* name,
- JSObject* receiver,
- JSObject* holder,
- Object* value);
+ MUST_USE_RESULT MaybeObject* ComputeLoadConstant(String* name,
+ JSObject* receiver,
+ JSObject* holder,
+ Object* value);
- MUST_USE_RESULT static MaybeObject* ComputeLoadInterceptor(
+ MUST_USE_RESULT MaybeObject* ComputeLoadInterceptor(
String* name,
JSObject* receiver,
JSObject* holder);
- MUST_USE_RESULT static MaybeObject* ComputeLoadNormal();
+ MUST_USE_RESULT MaybeObject* ComputeLoadNormal();
- MUST_USE_RESULT static MaybeObject* ComputeLoadGlobal(
+ MUST_USE_RESULT MaybeObject* ComputeLoadGlobal(
String* name,
JSObject* receiver,
GlobalObject* holder,
@@ -96,108 +109,102 @@ class StubCache : public AllStatic {
// ---
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadField(String* name,
- JSObject* receiver,
- JSObject* holder,
- int field_index);
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadField(String* name,
+ JSObject* receiver,
+ JSObject* holder,
+ int field_index);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadCallback(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadCallback(
String* name,
JSObject* receiver,
JSObject* holder,
AccessorInfo* callback);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadConstant(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadConstant(
String* name,
JSObject* receiver,
JSObject* holder,
Object* value);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadInterceptor(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadInterceptor(
String* name,
JSObject* receiver,
JSObject* holder);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadArrayLength(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadArrayLength(
String* name,
JSArray* receiver);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadStringLength(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadStringLength(
String* name,
String* receiver);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadFunctionPrototype(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadFunctionPrototype(
String* name,
JSFunction* receiver);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadSpecialized(
- JSObject* receiver);
-
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadPixelArray(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadSpecialized(
JSObject* receiver);
// ---
- MUST_USE_RESULT static MaybeObject* ComputeStoreField(
+ MUST_USE_RESULT MaybeObject* ComputeStoreField(
String* name,
JSObject* receiver,
int field_index,
Map* transition,
StrictModeFlag strict_mode);
- MUST_USE_RESULT static MaybeObject* ComputeStoreNormal(
+ MUST_USE_RESULT MaybeObject* ComputeStoreNormal(
StrictModeFlag strict_mode);
- MUST_USE_RESULT static MaybeObject* ComputeStoreGlobal(
+ MUST_USE_RESULT MaybeObject* ComputeStoreGlobal(
String* name,
GlobalObject* receiver,
JSGlobalPropertyCell* cell,
StrictModeFlag strict_mode);
- MUST_USE_RESULT static MaybeObject* ComputeStoreCallback(
+ MUST_USE_RESULT MaybeObject* ComputeStoreCallback(
String* name,
JSObject* receiver,
AccessorInfo* callback,
StrictModeFlag strict_mode);
- MUST_USE_RESULT static MaybeObject* ComputeStoreInterceptor(
+ MUST_USE_RESULT MaybeObject* ComputeStoreInterceptor(
String* name,
JSObject* receiver,
StrictModeFlag strict_mode);
// ---
- MUST_USE_RESULT static MaybeObject* ComputeKeyedStoreField(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedStoreField(
String* name,
JSObject* receiver,
int field_index,
Map* transition,
StrictModeFlag strict_mode);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedStoreSpecialized(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedStoreSpecialized(
JSObject* receiver,
StrictModeFlag strict_mode);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedStorePixelArray(
- JSObject* receiver,
- StrictModeFlag strict_mode);
- MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadOrStoreExternalArray(
+ MUST_USE_RESULT MaybeObject* ComputeKeyedLoadOrStoreExternalArray(
JSObject* receiver,
bool is_store,
StrictModeFlag strict_mode);
// ---
- MUST_USE_RESULT static MaybeObject* ComputeCallField(int argc,
- InLoopFlag in_loop,
- Code::Kind,
- String* name,
- Object* object,
- JSObject* holder,
- int index);
+ MUST_USE_RESULT MaybeObject* ComputeCallField(int argc,
+ InLoopFlag in_loop,
+ Code::Kind,
+ String* name,
+ Object* object,
+ JSObject* holder,
+ int index);
- MUST_USE_RESULT static MaybeObject* ComputeCallConstant(
+ MUST_USE_RESULT MaybeObject* ComputeCallConstant(
int argc,
InLoopFlag in_loop,
Code::Kind,
@@ -207,19 +214,19 @@ class StubCache : public AllStatic {
JSObject* holder,
JSFunction* function);
- MUST_USE_RESULT static MaybeObject* ComputeCallNormal(int argc,
- InLoopFlag in_loop,
- Code::Kind,
- String* name,
- JSObject* receiver);
+ MUST_USE_RESULT MaybeObject* ComputeCallNormal(int argc,
+ InLoopFlag in_loop,
+ Code::Kind,
+ String* name,
+ JSObject* receiver);
- MUST_USE_RESULT static MaybeObject* ComputeCallInterceptor(int argc,
- Code::Kind,
- String* name,
- Object* object,
- JSObject* holder);
+ MUST_USE_RESULT MaybeObject* ComputeCallInterceptor(int argc,
+ Code::Kind,
+ String* name,
+ Object* object,
+ JSObject* holder);
- MUST_USE_RESULT static MaybeObject* ComputeCallGlobal(
+ MUST_USE_RESULT MaybeObject* ComputeCallGlobal(
int argc,
InLoopFlag in_loop,
Code::Kind,
@@ -231,80 +238,105 @@ class StubCache : public AllStatic {
// ---
- MUST_USE_RESULT static MaybeObject* ComputeCallInitialize(int argc,
- InLoopFlag in_loop,
- Code::Kind kind);
+ MUST_USE_RESULT MaybeObject* ComputeCallInitialize(int argc,
+ InLoopFlag in_loop,
+ Code::Kind kind);
- static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
+ Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
- static Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
+ Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
- MUST_USE_RESULT static MaybeObject* ComputeCallPreMonomorphic(
+ MUST_USE_RESULT MaybeObject* ComputeCallPreMonomorphic(
int argc,
InLoopFlag in_loop,
Code::Kind kind);
- MUST_USE_RESULT static MaybeObject* ComputeCallNormal(int argc,
- InLoopFlag in_loop,
- Code::Kind kind);
+ MUST_USE_RESULT MaybeObject* ComputeCallNormal(int argc,
+ InLoopFlag in_loop,
+ Code::Kind kind);
- MUST_USE_RESULT static MaybeObject* ComputeCallMegamorphic(int argc,
- InLoopFlag in_loop,
- Code::Kind kind);
-
- MUST_USE_RESULT static MaybeObject* ComputeCallMiss(int argc,
+ MUST_USE_RESULT MaybeObject* ComputeCallMegamorphic(int argc,
+ InLoopFlag in_loop,
Code::Kind kind);
+ MUST_USE_RESULT MaybeObject* ComputeCallMiss(int argc, Code::Kind kind);
+
// Finds the Code object stored in the Heap::non_monomorphic_cache().
- MUST_USE_RESULT static Code* FindCallInitialize(int argc,
- InLoopFlag in_loop,
- Code::Kind kind);
+ MUST_USE_RESULT Code* FindCallInitialize(int argc,
+ InLoopFlag in_loop,
+ Code::Kind kind);
#ifdef ENABLE_DEBUGGER_SUPPORT
- MUST_USE_RESULT static MaybeObject* ComputeCallDebugBreak(int argc,
- Code::Kind kind);
+ MUST_USE_RESULT MaybeObject* ComputeCallDebugBreak(int argc, Code::Kind kind);
- MUST_USE_RESULT static MaybeObject* ComputeCallDebugPrepareStepIn(
- int argc,
- Code::Kind kind);
+ MUST_USE_RESULT MaybeObject* ComputeCallDebugPrepareStepIn(int argc,
+ Code::Kind kind);
#endif
// Update cache for entry hash(name, map).
- static Code* Set(String* name, Map* map, Code* code);
+ Code* Set(String* name, Map* map, Code* code);
// Clear the lookup table (@ mark compact collection).
- static void Clear();
+ void Clear();
// Collect all maps that match the name and flags.
- static void CollectMatchingMaps(ZoneMapList* types,
- String* name,
- Code::Flags flags);
+ void CollectMatchingMaps(ZoneMapList* types,
+ String* name,
+ Code::Flags flags);
// Generate code for probing the stub cache table.
// Arguments extra and extra2 may be used to pass additional scratch
// registers. Set to no_reg if not needed.
- static void GenerateProbe(MacroAssembler* masm,
- Code::Flags flags,
- Register receiver,
- Register name,
- Register scratch,
- Register extra,
- Register extra2 = no_reg);
+ void GenerateProbe(MacroAssembler* masm,
+ Code::Flags flags,
+ Register receiver,
+ Register name,
+ Register scratch,
+ Register extra,
+ Register extra2 = no_reg);
enum Table {
kPrimary,
kSecondary
};
+
+ SCTableReference key_reference(StubCache::Table table) {
+ return SCTableReference(
+ reinterpret_cast<Address>(&first_entry(table)->key));
+ }
+
+
+ SCTableReference value_reference(StubCache::Table table) {
+ return SCTableReference(
+ reinterpret_cast<Address>(&first_entry(table)->value));
+ }
+
+
+ StubCache::Entry* first_entry(StubCache::Table table) {
+ switch (table) {
+ case StubCache::kPrimary: return StubCache::primary_;
+ case StubCache::kSecondary: return StubCache::secondary_;
+ }
+ UNREACHABLE();
+ return NULL;
+ }
+
+ Isolate* isolate() { return isolate_; }
+ Heap* heap() { return isolate()->heap(); }
+
private:
+ explicit StubCache(Isolate* isolate);
+
+ friend class Isolate;
friend class SCTableReference;
static const int kPrimaryTableSize = 2048;
static const int kSecondaryTableSize = 512;
- static Entry primary_[];
- static Entry secondary_[];
+ Entry primary_[kPrimaryTableSize];
+ Entry secondary_[kSecondaryTableSize];
// Computes the hashed offsets for primary and secondary caches.
- static int PrimaryOffset(String* name, Code::Flags flags, Map* map) {
+ RLYSTC int PrimaryOffset(String* name, Code::Flags flags, Map* map) {
// This works well because the heap object tag size and the hash
// shift are equal. Shifting down the length field to get the
// hash code would effectively throw away two bits of the hash
@@ -327,7 +359,7 @@ class StubCache : public AllStatic {
return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
}
- static int SecondaryOffset(String* name, Code::Flags flags, int seed) {
+ RLYSTC int SecondaryOffset(String* name, Code::Flags flags, int seed) {
// Use the seed from the primary cache in the secondary cache.
uint32_t string_low32bits =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
@@ -344,59 +376,33 @@ class StubCache : public AllStatic {
// ends in String::kHashShift 0s. Then we shift it so it is a multiple
// of sizeof(Entry). This makes it easier to avoid making mistakes
// in the hashed offset computations.
- static Entry* entry(Entry* table, int offset) {
+ RLYSTC Entry* entry(Entry* table, int offset) {
const int shift_amount = kPointerSizeLog2 + 1 - String::kHashShift;
return reinterpret_cast<Entry*>(
reinterpret_cast<Address>(table) + (offset << shift_amount));
}
-};
-
-
-class SCTableReference {
- public:
- static SCTableReference keyReference(StubCache::Table table) {
- return SCTableReference(
- reinterpret_cast<Address>(&first_entry(table)->key));
- }
-
-
- static SCTableReference valueReference(StubCache::Table table) {
- return SCTableReference(
- reinterpret_cast<Address>(&first_entry(table)->value));
- }
- Address address() const { return address_; }
-
- private:
- explicit SCTableReference(Address address) : address_(address) {}
+ Isolate* isolate_;
- static StubCache::Entry* first_entry(StubCache::Table table) {
- switch (table) {
- case StubCache::kPrimary: return StubCache::primary_;
- case StubCache::kSecondary: return StubCache::secondary_;
- }
- UNREACHABLE();
- return NULL;
- }
-
- Address address_;
+ DISALLOW_COPY_AND_ASSIGN(StubCache);
};
+
// ------------------------------------------------------------------------
// Support functions for IC stubs for callbacks.
-MaybeObject* LoadCallbackProperty(Arguments args);
-MaybeObject* StoreCallbackProperty(Arguments args);
+MaybeObject* LoadCallbackProperty(RUNTIME_CALLING_CONVENTION);
+MaybeObject* StoreCallbackProperty(RUNTIME_CALLING_CONVENTION);
// Support functions for IC stubs for interceptors.
-MaybeObject* LoadPropertyWithInterceptorOnly(Arguments args);
-MaybeObject* LoadPropertyWithInterceptorForLoad(Arguments args);
-MaybeObject* LoadPropertyWithInterceptorForCall(Arguments args);
-MaybeObject* StoreInterceptorProperty(Arguments args);
-MaybeObject* CallInterceptorProperty(Arguments args);
-MaybeObject* KeyedLoadPropertyWithInterceptor(Arguments args);
+MaybeObject* LoadPropertyWithInterceptorOnly(RUNTIME_CALLING_CONVENTION);
+MaybeObject* LoadPropertyWithInterceptorForLoad(RUNTIME_CALLING_CONVENTION);
+MaybeObject* LoadPropertyWithInterceptorForCall(RUNTIME_CALLING_CONVENTION);
+MaybeObject* StoreInterceptorProperty(RUNTIME_CALLING_CONVENTION);
+MaybeObject* CallInterceptorProperty(RUNTIME_CALLING_CONVENTION);
+MaybeObject* KeyedLoadPropertyWithInterceptor(RUNTIME_CALLING_CONVENTION);
// The stub compiler compiles stubs for the stub cache.
@@ -554,6 +560,10 @@ class StubCompiler BASE_EMBEDDED {
String* name,
LookupResult* lookup);
+ Isolate* isolate() { return scope_.isolate(); }
+ Heap* heap() { return isolate()->heap(); }
+ Factory* factory() { return isolate()->factory(); }
+
private:
HandleScope scope_;
MacroAssembler masm_;
@@ -623,7 +633,6 @@ class KeyedLoadStubCompiler: public StubCompiler {
MUST_USE_RESULT MaybeObject* CompileLoadFunctionPrototype(String* name);
MUST_USE_RESULT MaybeObject* CompileLoadSpecialized(JSObject* receiver);
- MUST_USE_RESULT MaybeObject* CompileLoadPixelArray(JSObject* receiver);
private:
MaybeObject* GetCode(PropertyType type, String* name);
@@ -669,8 +678,6 @@ class KeyedStoreStubCompiler: public StubCompiler {
MUST_USE_RESULT MaybeObject* CompileStoreSpecialized(JSObject* receiver);
- MUST_USE_RESULT MaybeObject* CompileStorePixelArray(JSObject* receiver);
-
private:
MaybeObject* GetCode(PropertyType type, String* name);
@@ -690,6 +697,8 @@ class KeyedStoreStubCompiler: public StubCompiler {
V(MathAbs)
+class CallOptimization;
+
class CallStubCompiler: public StubCompiler {
public:
CallStubCompiler(int argc,
@@ -716,14 +725,13 @@ class CallStubCompiler: public StubCompiler {
JSFunction* function,
String* name);
- static bool HasCustomCallGenerator(BuiltinFunctionId id);
+ static bool HasCustomCallGenerator(JSFunction* function);
private:
// Compiles a custom call constant/global IC. For constant calls
// cell is NULL. Returns undefined if there is no custom call code
// for the given function or it can't be generated.
- MUST_USE_RESULT MaybeObject* CompileCustomCall(BuiltinFunctionId id,
- Object* object,
+ MUST_USE_RESULT MaybeObject* CompileCustomCall(Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
@@ -738,6 +746,14 @@ class CallStubCompiler: public StubCompiler {
CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR)
#undef DECLARE_CALL_GENERATOR
+ MUST_USE_RESULT MaybeObject* CompileFastApiCall(
+ const CallOptimization& optimization,
+ Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name);
+
const ParameterCount arguments_;
const InLoopFlag in_loop_;
const Code::Kind kind_;
@@ -835,10 +851,10 @@ class ExternalArrayStubCompiler: public StubCompiler {
explicit ExternalArrayStubCompiler() {}
MUST_USE_RESULT MaybeObject* CompileKeyedLoadStub(
- ExternalArrayType array_type, Code::Flags flags);
+ JSObject* receiver, ExternalArrayType array_type, Code::Flags flags);
MUST_USE_RESULT MaybeObject* CompileKeyedStoreStub(
- ExternalArrayType array_type, Code::Flags flags);
+ JSObject* receiver, ExternalArrayType array_type, Code::Flags flags);
private:
MaybeObject* GetCode(Code::Flags flags);
diff --git a/src/token.cc b/src/token.cc
index 488e9097..feca7beb 100644
--- a/src/token.cc
+++ b/src/token.cc
@@ -32,21 +32,21 @@ namespace v8 {
namespace internal {
#define T(name, string, precedence) #name,
-const char* Token::name_[NUM_TOKENS] = {
+const char* const Token::name_[NUM_TOKENS] = {
TOKEN_LIST(T, T, IGNORE_TOKEN)
};
#undef T
#define T(name, string, precedence) string,
-const char* Token::string_[NUM_TOKENS] = {
+const char* const Token::string_[NUM_TOKENS] = {
TOKEN_LIST(T, T, IGNORE_TOKEN)
};
#undef T
#define T(name, string, precedence) precedence,
-int8_t Token::precedence_[NUM_TOKENS] = {
+const int8_t Token::precedence_[NUM_TOKENS] = {
TOKEN_LIST(T, T, IGNORE_TOKEN)
};
#undef T
diff --git a/src/token.h b/src/token.h
index 776d9f3b..a0afbc14 100644
--- a/src/token.h
+++ b/src/token.h
@@ -277,9 +277,9 @@ class Token {
}
private:
- static const char* name_[NUM_TOKENS];
- static const char* string_[NUM_TOKENS];
- static int8_t precedence_[NUM_TOKENS];
+ static const char* const name_[NUM_TOKENS];
+ static const char* const string_[NUM_TOKENS];
+ static const int8_t precedence_[NUM_TOKENS];
static const char token_type[NUM_TOKENS];
};
diff --git a/src/top.cc b/src/top.cc
index 78db26a5..ff29cad4 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -37,31 +37,12 @@
#include "string-stream.h"
#include "vm-state-inl.h"
+// TODO(isolates): move to isolate.cc. This stuff is kept here to
+// simplify merging.
+
namespace v8 {
namespace internal {
-#ifdef ENABLE_LOGGING_AND_PROFILING
-Semaphore* Top::runtime_profiler_semaphore_ = NULL;
-#endif
-ThreadLocalTop Top::thread_local_;
-Mutex* Top::break_access_ = OS::CreateMutex();
-
-NoAllocationStringAllocator* preallocated_message_space = NULL;
-
-bool capture_stack_trace_for_uncaught_exceptions = false;
-int stack_trace_for_uncaught_exceptions_frame_limit = 0;
-StackTrace::StackTraceOptions stack_trace_for_uncaught_exceptions_options =
- StackTrace::kOverview;
-
-Address top_addresses[] = {
-#define C(name) reinterpret_cast<Address>(Top::name()),
- TOP_ADDRESS_LIST(C)
- TOP_ADDRESS_LIST_PROF(C)
-#undef C
- NULL
-};
-
-
v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
}
@@ -72,9 +53,9 @@ void ThreadLocalTop::Initialize() {
handler_ = 0;
#ifdef USE_SIMULATOR
#ifdef V8_TARGET_ARCH_ARM
- simulator_ = Simulator::current();
+ simulator_ = Simulator::current(Isolate::Current());
#elif V8_TARGET_ARCH_MIPS
- simulator_ = assembler::mips::Simulator::current();
+ simulator_ = Simulator::current(Isolate::Current());
#endif
#endif
#ifdef ENABLE_LOGGING_AND_PROFILING
@@ -83,11 +64,10 @@ void ThreadLocalTop::Initialize() {
#endif
#ifdef ENABLE_VMSTATE_TRACKING
current_vm_state_ = EXTERNAL;
- runtime_profiler_state_ = Top::PROF_NOT_IN_JS;
#endif
try_catch_handler_address_ = NULL;
context_ = NULL;
- int id = ThreadManager::CurrentId();
+ int id = Isolate::Current()->thread_manager()->CurrentId();
thread_id_ = (id == 0) ? ThreadManager::kInvalidId : id;
external_caught_exception_ = false;
failed_access_check_callback_ = NULL;
@@ -96,32 +76,32 @@ void ThreadLocalTop::Initialize() {
}
-Address Top::get_address_from_id(Top::AddressId id) {
- return top_addresses[id];
+Address Isolate::get_address_from_id(Isolate::AddressId id) {
+ return isolate_addresses_[id];
}
-char* Top::Iterate(ObjectVisitor* v, char* thread_storage) {
+char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) {
ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
Iterate(v, thread);
return thread_storage + sizeof(ThreadLocalTop);
}
-void Top::IterateThread(ThreadVisitor* v) {
- v->VisitThread(&thread_local_);
+void Isolate::IterateThread(ThreadVisitor* v) {
+ v->VisitThread(thread_local_top());
}
-void Top::IterateThread(ThreadVisitor* v, char* t) {
+void Isolate::IterateThread(ThreadVisitor* v, char* t) {
ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
v->VisitThread(thread);
}
-void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
+void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
// Visit the roots from the top for a given thread.
- Object *pending;
+ Object* pending;
// The pending exception can sometimes be a failure. We can't show
// that to the GC, which only understands objects.
if (thread->pending_exception_->ToObject(&pending)) {
@@ -151,176 +131,13 @@ void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
}
-void Top::Iterate(ObjectVisitor* v) {
- ThreadLocalTop* current_t = &thread_local_;
+void Isolate::Iterate(ObjectVisitor* v) {
+ ThreadLocalTop* current_t = thread_local_top();
Iterate(v, current_t);
}
-void Top::InitializeThreadLocal() {
- thread_local_.Initialize();
- clear_pending_exception();
- clear_pending_message();
- clear_scheduled_exception();
-}
-
-
-// Create a dummy thread that will wait forever on a semaphore. The only
-// purpose for this thread is to have some stack area to save essential data
-// into for use by a stacks only core dump (aka minidump).
-class PreallocatedMemoryThread: public Thread {
- public:
- PreallocatedMemoryThread()
- : Thread("v8:PreallocMem"),
- keep_running_(true) {
- wait_for_ever_semaphore_ = OS::CreateSemaphore(0);
- data_ready_semaphore_ = OS::CreateSemaphore(0);
- }
-
- // When the thread starts running it will allocate a fixed number of bytes
- // on the stack and publish the location of this memory for others to use.
- void Run() {
- EmbeddedVector<char, 15 * 1024> local_buffer;
-
- // Initialize the buffer with a known good value.
- OS::StrNCpy(local_buffer, "Trace data was not generated.\n",
- local_buffer.length());
-
- // Publish the local buffer and signal its availability.
- data_ = local_buffer.start();
- length_ = local_buffer.length();
- data_ready_semaphore_->Signal();
-
- while (keep_running_) {
- // This thread will wait here until the end of time.
- wait_for_ever_semaphore_->Wait();
- }
-
- // Make sure we access the buffer after the wait to remove all possibility
- // of it being optimized away.
- OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n",
- local_buffer.length());
- }
-
- static char* data() {
- if (data_ready_semaphore_ != NULL) {
- // Initial access is guarded until the data has been published.
- data_ready_semaphore_->Wait();
- delete data_ready_semaphore_;
- data_ready_semaphore_ = NULL;
- }
- return data_;
- }
-
- static unsigned length() {
- if (data_ready_semaphore_ != NULL) {
- // Initial access is guarded until the data has been published.
- data_ready_semaphore_->Wait();
- delete data_ready_semaphore_;
- data_ready_semaphore_ = NULL;
- }
- return length_;
- }
-
- static void StartThread() {
- if (the_thread_ != NULL) return;
-
- the_thread_ = new PreallocatedMemoryThread();
- the_thread_->Start();
- }
-
- // Stop the PreallocatedMemoryThread and release its resources.
- static void StopThread() {
- if (the_thread_ == NULL) return;
-
- the_thread_->keep_running_ = false;
- wait_for_ever_semaphore_->Signal();
-
- // Wait for the thread to terminate.
- the_thread_->Join();
-
- if (data_ready_semaphore_ != NULL) {
- delete data_ready_semaphore_;
- data_ready_semaphore_ = NULL;
- }
-
- delete wait_for_ever_semaphore_;
- wait_for_ever_semaphore_ = NULL;
-
- // Done with the thread entirely.
- delete the_thread_;
- the_thread_ = NULL;
- }
-
- private:
- // Used to make sure that the thread keeps looping even for spurious wakeups.
- bool keep_running_;
-
- // The preallocated memory thread singleton.
- static PreallocatedMemoryThread* the_thread_;
- // This semaphore is used by the PreallocatedMemoryThread to wait for ever.
- static Semaphore* wait_for_ever_semaphore_;
- // Semaphore to signal that the data has been initialized.
- static Semaphore* data_ready_semaphore_;
-
- // Location and size of the preallocated memory block.
- static char* data_;
- static unsigned length_;
-
- DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread);
-};
-
-PreallocatedMemoryThread* PreallocatedMemoryThread::the_thread_ = NULL;
-Semaphore* PreallocatedMemoryThread::wait_for_ever_semaphore_ = NULL;
-Semaphore* PreallocatedMemoryThread::data_ready_semaphore_ = NULL;
-char* PreallocatedMemoryThread::data_ = NULL;
-unsigned PreallocatedMemoryThread::length_ = 0;
-
-static bool initialized = false;
-
-void Top::Initialize() {
- CHECK(!initialized);
-
-#ifdef ENABLE_LOGGING_AND_PROFILING
- ASSERT(runtime_profiler_semaphore_ == NULL);
- runtime_profiler_semaphore_ = OS::CreateSemaphore(0);
-#endif
-
- InitializeThreadLocal();
-
- // Only preallocate on the first initialization.
- if (FLAG_preallocate_message_memory && (preallocated_message_space == NULL)) {
- // Start the thread which will set aside some memory.
- PreallocatedMemoryThread::StartThread();
- preallocated_message_space =
- new NoAllocationStringAllocator(PreallocatedMemoryThread::data(),
- PreallocatedMemoryThread::length());
- PreallocatedStorage::Init(PreallocatedMemoryThread::length() / 4);
- }
- initialized = true;
-}
-
-
-void Top::TearDown() {
- if (initialized) {
-#ifdef ENABLE_LOGGING_AND_PROFILING
- delete runtime_profiler_semaphore_;
- runtime_profiler_semaphore_ = NULL;
-#endif
-
- // Remove the external reference to the preallocated stack memory.
- if (preallocated_message_space != NULL) {
- delete preallocated_message_space;
- preallocated_message_space = NULL;
- }
-
- PreallocatedMemoryThread::StopThread();
- initialized = false;
- }
-}
-
-
-void Top::RegisterTryCatchHandler(v8::TryCatch* that) {
+void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
// The ARM simulator has a separate JS stack. We therefore register
// the C++ try catch handler with the simulator and get back an
// address that can be used for comparisons with addresses into the
@@ -328,68 +145,64 @@ void Top::RegisterTryCatchHandler(v8::TryCatch* that) {
// returned will be the address of the C++ try catch handler itself.
Address address = reinterpret_cast<Address>(
SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that)));
- thread_local_.set_try_catch_handler_address(address);
+ thread_local_top()->set_try_catch_handler_address(address);
}
-void Top::UnregisterTryCatchHandler(v8::TryCatch* that) {
- ASSERT(try_catch_handler() == that);
- thread_local_.set_try_catch_handler_address(
+void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
+ ASSERT(thread_local_top()->TryCatchHandler() == that);
+ thread_local_top()->set_try_catch_handler_address(
reinterpret_cast<Address>(that->next_));
- thread_local_.catcher_ = NULL;
+ thread_local_top()->catcher_ = NULL;
SimulatorStack::UnregisterCTryCatch();
}
-
-static int stack_trace_nesting_level = 0;
-static StringStream* incomplete_message = NULL;
-
-
-Handle<String> Top::StackTraceString() {
- if (stack_trace_nesting_level == 0) {
- stack_trace_nesting_level++;
+Handle<String> Isolate::StackTraceString() {
+ if (stack_trace_nesting_level_ == 0) {
+ stack_trace_nesting_level_++;
HeapStringAllocator allocator;
StringStream::ClearMentionedObjectCache();
StringStream accumulator(&allocator);
- incomplete_message = &accumulator;
+ incomplete_message_ = &accumulator;
PrintStack(&accumulator);
Handle<String> stack_trace = accumulator.ToString();
- incomplete_message = NULL;
- stack_trace_nesting_level = 0;
+ incomplete_message_ = NULL;
+ stack_trace_nesting_level_ = 0;
return stack_trace;
- } else if (stack_trace_nesting_level == 1) {
- stack_trace_nesting_level++;
+ } else if (stack_trace_nesting_level_ == 1) {
+ stack_trace_nesting_level_++;
OS::PrintError(
"\n\nAttempt to print stack while printing stack (double fault)\n");
OS::PrintError(
"If you are lucky you may find a partial stack dump on stdout.\n\n");
- incomplete_message->OutputToStdOut();
- return Factory::empty_symbol();
+ incomplete_message_->OutputToStdOut();
+ return factory()->empty_symbol();
} else {
OS::Abort();
// Unreachable
- return Factory::empty_symbol();
+ return factory()->empty_symbol();
}
}
-Handle<JSArray> Top::CaptureCurrentStackTrace(
+Handle<JSArray> Isolate::CaptureCurrentStackTrace(
int frame_limit, StackTrace::StackTraceOptions options) {
// Ensure no negative values.
int limit = Max(frame_limit, 0);
- Handle<JSArray> stack_trace = Factory::NewJSArray(frame_limit);
+ Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit);
- Handle<String> column_key = Factory::LookupAsciiSymbol("column");
- Handle<String> line_key = Factory::LookupAsciiSymbol("lineNumber");
- Handle<String> script_key = Factory::LookupAsciiSymbol("scriptName");
+ Handle<String> column_key = factory()->LookupAsciiSymbol("column");
+ Handle<String> line_key = factory()->LookupAsciiSymbol("lineNumber");
+ Handle<String> script_key = factory()->LookupAsciiSymbol("scriptName");
Handle<String> name_or_source_url_key =
- Factory::LookupAsciiSymbol("nameOrSourceURL");
+ factory()->LookupAsciiSymbol("nameOrSourceURL");
Handle<String> script_name_or_source_url_key =
- Factory::LookupAsciiSymbol("scriptNameOrSourceURL");
- Handle<String> function_key = Factory::LookupAsciiSymbol("functionName");
- Handle<String> eval_key = Factory::LookupAsciiSymbol("isEval");
- Handle<String> constructor_key = Factory::LookupAsciiSymbol("isConstructor");
+ factory()->LookupAsciiSymbol("scriptNameOrSourceURL");
+ Handle<String> function_key = factory()->LookupAsciiSymbol("functionName");
+ Handle<String> eval_key = factory()->LookupAsciiSymbol("isEval");
+ Handle<String> constructor_key =
+ factory()->LookupAsciiSymbol("isConstructor");
StackTraceFrameIterator it;
int frames_seen = 0;
@@ -400,7 +213,7 @@ Handle<JSArray> Top::CaptureCurrentStackTrace(
frame->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) {
// Create a JSObject to hold the information for the StackFrame.
- Handle<JSObject> stackFrame = Factory::NewJSObject(object_function());
+ Handle<JSObject> stackFrame = factory()->NewJSObject(object_function());
Handle<JSFunction> fun = frames[i].function();
Handle<Script> script(Script::cast(fun->shared()->script()));
@@ -429,12 +242,12 @@ Handle<JSArray> Top::CaptureCurrentStackTrace(
}
if (options & StackTrace::kScriptName) {
- Handle<Object> script_name(script->name());
+ Handle<Object> script_name(script->name(), this);
SetLocalPropertyNoThrow(stackFrame, script_key, script_name);
}
if (options & StackTrace::kScriptNameOrSourceURL) {
- Handle<Object> script_name(script->name());
+ Handle<Object> script_name(script->name(), this);
Handle<JSValue> script_wrapper = GetScriptWrapper(script);
Handle<Object> property = GetProperty(script_wrapper,
name_or_source_url_key);
@@ -444,16 +257,16 @@ Handle<JSArray> Top::CaptureCurrentStackTrace(
Handle<Object> result = Execution::TryCall(method, script_wrapper, 0,
NULL, &caught_exception);
if (caught_exception) {
- result = Factory::undefined_value();
+ result = factory()->undefined_value();
}
SetLocalPropertyNoThrow(stackFrame, script_name_or_source_url_key,
result);
}
if (options & StackTrace::kFunctionName) {
- Handle<Object> fun_name(fun->shared()->name());
+ Handle<Object> fun_name(fun->shared()->name(), this);
if (fun_name->ToBoolean()->IsFalse()) {
- fun_name = Handle<Object>(fun->shared()->inferred_name());
+ fun_name = Handle<Object>(fun->shared()->inferred_name(), this);
}
SetLocalPropertyNoThrow(stackFrame, function_key, fun_name);
}
@@ -461,13 +274,13 @@ Handle<JSArray> Top::CaptureCurrentStackTrace(
if (options & StackTrace::kIsEval) {
int type = Smi::cast(script->compilation_type())->value();
Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ?
- Factory::true_value() : Factory::false_value();
+ factory()->true_value() : factory()->false_value();
SetLocalPropertyNoThrow(stackFrame, eval_key, is_eval);
}
if (options & StackTrace::kIsConstructor) {
Handle<Object> is_constructor = (frames[i].is_constructor()) ?
- Factory::true_value() : Factory::false_value();
+ factory()->true_value() : factory()->false_value();
SetLocalPropertyNoThrow(stackFrame, constructor_key, is_constructor);
}
@@ -482,41 +295,36 @@ Handle<JSArray> Top::CaptureCurrentStackTrace(
}
-void Top::PrintStack() {
- if (stack_trace_nesting_level == 0) {
- stack_trace_nesting_level++;
+void Isolate::PrintStack() {
+ if (stack_trace_nesting_level_ == 0) {
+ stack_trace_nesting_level_++;
StringAllocator* allocator;
- if (preallocated_message_space == NULL) {
+ if (preallocated_message_space_ == NULL) {
allocator = new HeapStringAllocator();
} else {
- allocator = preallocated_message_space;
+ allocator = preallocated_message_space_;
}
- NativeAllocationChecker allocation_checker(
- !FLAG_preallocate_message_memory ?
- NativeAllocationChecker::ALLOW :
- NativeAllocationChecker::DISALLOW);
-
StringStream::ClearMentionedObjectCache();
StringStream accumulator(allocator);
- incomplete_message = &accumulator;
+ incomplete_message_ = &accumulator;
PrintStack(&accumulator);
accumulator.OutputToStdOut();
accumulator.Log();
- incomplete_message = NULL;
- stack_trace_nesting_level = 0;
- if (preallocated_message_space == NULL) {
+ incomplete_message_ = NULL;
+ stack_trace_nesting_level_ = 0;
+ if (preallocated_message_space_ == NULL) {
// Remove the HeapStringAllocator created above.
delete allocator;
}
- } else if (stack_trace_nesting_level == 1) {
- stack_trace_nesting_level++;
+ } else if (stack_trace_nesting_level_ == 1) {
+ stack_trace_nesting_level_++;
OS::PrintError(
"\n\nAttempt to print stack while printing stack (double fault)\n");
OS::PrintError(
"If you are lucky you may find a partial stack dump on stdout.\n\n");
- incomplete_message->OutputToStdOut();
+ incomplete_message_->OutputToStdOut();
}
}
@@ -530,13 +338,20 @@ static void PrintFrames(StringStream* accumulator,
}
-void Top::PrintStack(StringStream* accumulator) {
+void Isolate::PrintStack(StringStream* accumulator) {
+ if (!IsInitialized()) {
+ accumulator->Add(
+ "\n==== Stack trace is not available ==========================\n\n");
+ accumulator->Add(
+ "\n==== Isolate for the thread is not initialized =============\n\n");
+ return;
+ }
// The MentionedObjectCache is not GC-proof at the moment.
AssertNoAllocation nogc;
ASSERT(StringStream::IsMentionedObjectCacheClear());
// Avoid printing anything if there are no frames.
- if (c_entry_fp(GetCurrentThread()) == 0) return;
+ if (c_entry_fp(thread_local_top()) == 0) return;
accumulator->Add(
"\n==== Stack trace ============================================\n\n");
@@ -551,28 +366,29 @@ void Top::PrintStack(StringStream* accumulator) {
}
-void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) {
- thread_local_.failed_access_check_callback_ = callback;
+void Isolate::SetFailedAccessCheckCallback(
+ v8::FailedAccessCheckCallback callback) {
+ thread_local_top()->failed_access_check_callback_ = callback;
}
-void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
- if (!thread_local_.failed_access_check_callback_) return;
+void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
+ if (!thread_local_top()->failed_access_check_callback_) return;
ASSERT(receiver->IsAccessCheckNeeded());
- ASSERT(Top::context());
+ ASSERT(context());
// Get the data object from access check info.
JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
if (!constructor->shared()->IsApiFunction()) return;
Object* data_obj =
constructor->shared()->get_api_func_data()->access_check_info();
- if (data_obj == Heap::undefined_value()) return;
+ if (data_obj == heap_.undefined_value()) return;
HandleScope scope;
Handle<JSObject> receiver_handle(receiver);
Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
- thread_local_.failed_access_check_callback_(
+ thread_local_top()->failed_access_check_callback_(
v8::Utils::ToLocal(receiver_handle),
type,
v8::Utils::ToLocal(data));
@@ -584,18 +400,19 @@ enum MayAccessDecision {
};
-static MayAccessDecision MayAccessPreCheck(JSObject* receiver,
+static MayAccessDecision MayAccessPreCheck(Isolate* isolate,
+ JSObject* receiver,
v8::AccessType type) {
// During bootstrapping, callback functions are not enabled yet.
- if (Bootstrapper::IsActive()) return YES;
+ if (isolate->bootstrapper()->IsActive()) return YES;
if (receiver->IsJSGlobalProxy()) {
Object* receiver_context = JSGlobalProxy::cast(receiver)->context();
if (!receiver_context->IsContext()) return NO;
// Get the global context of current top context.
- // avoid using Top::global_context() because it uses Handle.
- Context* global_context = Top::context()->global()->global_context();
+ // avoid using Isolate::global_context() because it uses Handle.
+ Context* global_context = isolate->context()->global()->global_context();
if (receiver_context == global_context) return YES;
if (Context::cast(receiver_context)->security_token() ==
@@ -607,7 +424,8 @@ static MayAccessDecision MayAccessPreCheck(JSObject* receiver,
}
-bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
+bool Isolate::MayNamedAccess(JSObject* receiver, Object* key,
+ v8::AccessType type) {
ASSERT(receiver->IsAccessCheckNeeded());
// The callers of this method are not expecting a GC.
@@ -615,13 +433,13 @@ bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
// Skip checks for hidden properties access. Note, we do not
// require existence of a context in this case.
- if (key == Heap::hidden_symbol()) return true;
+ if (key == heap_.hidden_symbol()) return true;
// Check for compatibility between the security tokens in the
// current lexical context and the accessed object.
- ASSERT(Top::context());
+ ASSERT(context());
- MayAccessDecision decision = MayAccessPreCheck(receiver, type);
+ MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
if (decision != UNKNOWN) return decision == YES;
// Get named access check callback
@@ -630,7 +448,7 @@ bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
Object* data_obj =
constructor->shared()->get_api_func_data()->access_check_info();
- if (data_obj == Heap::undefined_value()) return false;
+ if (data_obj == heap_.undefined_value()) return false;
Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
v8::NamedSecurityCallback callback =
@@ -638,15 +456,15 @@ bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
if (!callback) return false;
- HandleScope scope;
- Handle<JSObject> receiver_handle(receiver);
- Handle<Object> key_handle(key);
- Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
- LOG(ApiNamedSecurityCheck(key));
+ HandleScope scope(this);
+ Handle<JSObject> receiver_handle(receiver, this);
+ Handle<Object> key_handle(key, this);
+ Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this);
+ LOG(this, ApiNamedSecurityCheck(key));
bool result = false;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(this, EXTERNAL);
result = callback(v8::Utils::ToLocal(receiver_handle),
v8::Utils::ToLocal(key_handle),
type,
@@ -656,17 +474,15 @@ bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
}
-bool Top::MayIndexedAccess(JSObject* receiver,
- uint32_t index,
- v8::AccessType type) {
+bool Isolate::MayIndexedAccess(JSObject* receiver,
+ uint32_t index,
+ v8::AccessType type) {
ASSERT(receiver->IsAccessCheckNeeded());
// Check for compatibility between the security tokens in the
// current lexical context and the accessed object.
- ASSERT(Top::context());
- // The callers of this method are not expecting a GC.
- AssertNoAllocation no_gc;
+ ASSERT(context());
- MayAccessDecision decision = MayAccessPreCheck(receiver, type);
+ MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
if (decision != UNKNOWN) return decision == YES;
// Get indexed access check callback
@@ -675,7 +491,7 @@ bool Top::MayIndexedAccess(JSObject* receiver,
Object* data_obj =
constructor->shared()->get_api_func_data()->access_check_info();
- if (data_obj == Heap::undefined_value()) return false;
+ if (data_obj == heap_.undefined_value()) return false;
Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
v8::IndexedSecurityCallback callback =
@@ -683,14 +499,14 @@ bool Top::MayIndexedAccess(JSObject* receiver,
if (!callback) return false;
- HandleScope scope;
- Handle<JSObject> receiver_handle(receiver);
- Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
- LOG(ApiIndexedSecurityCheck(index));
+ HandleScope scope(this);
+ Handle<JSObject> receiver_handle(receiver, this);
+ Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this);
+ LOG(this, ApiIndexedSecurityCheck(index));
bool result = false;
{
// Leaving JavaScript.
- VMState state(EXTERNAL);
+ VMState state(this, EXTERNAL);
result = callback(v8::Utils::ToLocal(receiver_handle),
index,
type,
@@ -700,15 +516,15 @@ bool Top::MayIndexedAccess(JSObject* receiver,
}
-const char* Top::kStackOverflowMessage =
+const char* const Isolate::kStackOverflowMessage =
"Uncaught RangeError: Maximum call stack size exceeded";
-Failure* Top::StackOverflow() {
+Failure* Isolate::StackOverflow() {
HandleScope scope;
- Handle<String> key = Factory::stack_overflow_symbol();
+ Handle<String> key = factory()->stack_overflow_symbol();
Handle<JSObject> boilerplate =
- Handle<JSObject>::cast(GetProperty(Top::builtins(), key));
+ Handle<JSObject>::cast(GetProperty(js_builtins_object(), key));
Handle<Object> exception = Copy(boilerplate);
// TODO(1240995): To avoid having to call JavaScript code to compute
// the message for stack overflow exceptions which is very likely to
@@ -719,23 +535,23 @@ Failure* Top::StackOverflow() {
}
-Failure* Top::TerminateExecution() {
- DoThrow(Heap::termination_exception(), NULL, NULL);
+Failure* Isolate::TerminateExecution() {
+ DoThrow(heap_.termination_exception(), NULL, NULL);
return Failure::Exception();
}
-Failure* Top::Throw(Object* exception, MessageLocation* location) {
+Failure* Isolate::Throw(Object* exception, MessageLocation* location) {
DoThrow(exception, location, NULL);
return Failure::Exception();
}
-Failure* Top::ReThrow(MaybeObject* exception, MessageLocation* location) {
+Failure* Isolate::ReThrow(MaybeObject* exception, MessageLocation* location) {
bool can_be_caught_externally = false;
ShouldReportException(&can_be_caught_externally,
is_catchable_by_javascript(exception));
- thread_local_.catcher_ = can_be_caught_externally ?
+ thread_local_top()->catcher_ = can_be_caught_externally ?
try_catch_handler() : NULL;
// Set the exception being re-thrown.
@@ -744,22 +560,22 @@ Failure* Top::ReThrow(MaybeObject* exception, MessageLocation* location) {
}
-Failure* Top::ThrowIllegalOperation() {
- return Throw(Heap::illegal_access_symbol());
+Failure* Isolate::ThrowIllegalOperation() {
+ return Throw(heap_.illegal_access_symbol());
}
-void Top::ScheduleThrow(Object* exception) {
+void Isolate::ScheduleThrow(Object* exception) {
// When scheduling a throw we first throw the exception to get the
// error reporting if it is uncaught before rescheduling it.
Throw(exception);
- thread_local_.scheduled_exception_ = pending_exception();
- thread_local_.external_caught_exception_ = false;
+ thread_local_top()->scheduled_exception_ = pending_exception();
+ thread_local_top()->external_caught_exception_ = false;
clear_pending_exception();
}
-Failure* Top::PromoteScheduledException() {
+Failure* Isolate::PromoteScheduledException() {
MaybeObject* thrown = scheduled_exception();
clear_scheduled_exception();
// Re-throw the exception to avoid getting repeated error reporting.
@@ -767,13 +583,13 @@ Failure* Top::PromoteScheduledException() {
}
-void Top::PrintCurrentStackTrace(FILE* out) {
+void Isolate::PrintCurrentStackTrace(FILE* out) {
StackTraceFrameIterator it;
while (!it.done()) {
HandleScope scope;
// Find code position if recorded in relocation info.
JavaScriptFrame* frame = it.frame();
- int pos = frame->code()->SourcePosition(frame->pc());
+ int pos = frame->LookupCode(this)->SourcePosition(frame->pc());
Handle<Object> pos_obj(Smi::FromInt(pos));
// Fetch function and receiver.
Handle<JSFunction> fun(JSFunction::cast(frame->function()));
@@ -782,8 +598,8 @@ void Top::PrintCurrentStackTrace(FILE* out) {
// current frame is the top-level frame.
it.Advance();
Handle<Object> is_top_level = it.done()
- ? Factory::true_value()
- : Factory::false_value();
+ ? factory()->true_value()
+ : factory()->false_value();
// Generate and print stack trace line.
Handle<String> line =
Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
@@ -795,8 +611,8 @@ void Top::PrintCurrentStackTrace(FILE* out) {
}
-void Top::ComputeLocation(MessageLocation* target) {
- *target = MessageLocation(Handle<Script>(Heap::empty_script()), -1, -1);
+void Isolate::ComputeLocation(MessageLocation* target) {
+ *target = MessageLocation(Handle<Script>(heap_.empty_script()), -1, -1);
StackTraceFrameIterator it;
if (!it.done()) {
JavaScriptFrame* frame = it.frame();
@@ -804,7 +620,7 @@ void Top::ComputeLocation(MessageLocation* target) {
Object* script = fun->shared()->script();
if (script->IsScript() &&
!(Script::cast(script)->source()->IsUndefined())) {
- int pos = frame->code()->SourcePosition(frame->pc());
+ int pos = frame->LookupCode(this)->SourcePosition(frame->pc());
// Compute the location from the function and the reloc info.
Handle<Script> casted_script(Script::cast(script));
*target = MessageLocation(casted_script, pos, pos + 1);
@@ -813,18 +629,19 @@ void Top::ComputeLocation(MessageLocation* target) {
}
-bool Top::ShouldReportException(bool* can_be_caught_externally,
- bool catchable_by_javascript) {
+bool Isolate::ShouldReportException(bool* can_be_caught_externally,
+ bool catchable_by_javascript) {
// Find the top-most try-catch handler.
StackHandler* handler =
- StackHandler::FromAddress(Top::handler(Top::GetCurrentThread()));
+ StackHandler::FromAddress(Isolate::handler(thread_local_top()));
while (handler != NULL && !handler->is_try_catch()) {
handler = handler->next();
}
// Get the address of the external handler so we can compare the address to
// determine which one is closer to the top of the stack.
- Address external_handler_address = thread_local_.try_catch_handler_address();
+ Address external_handler_address =
+ thread_local_top()->try_catch_handler_address();
// The exception has been externally caught if and only if there is
// an external handler which is on top of the top-most try-catch
@@ -843,9 +660,9 @@ bool Top::ShouldReportException(bool* can_be_caught_externally,
}
-void Top::DoThrow(MaybeObject* exception,
- MessageLocation* location,
- const char* message) {
+void Isolate::DoThrow(MaybeObject* exception,
+ MessageLocation* location,
+ const char* message) {
ASSERT(!has_pending_exception());
HandleScope scope;
@@ -865,7 +682,7 @@ void Top::DoThrow(MaybeObject* exception,
#ifdef ENABLE_DEBUGGER_SUPPORT
// Notify debugger of exception.
if (catchable_by_javascript) {
- Debugger::OnException(exception_handle, report_exception);
+ debugger_->OnException(exception_handle, report_exception);
}
#endif
@@ -881,17 +698,17 @@ void Top::DoThrow(MaybeObject* exception,
ComputeLocation(&potential_computed_location);
location = &potential_computed_location;
}
- if (!Bootstrapper::IsActive()) {
+ if (!bootstrapper()->IsActive()) {
// It's not safe to try to make message objects or collect stack
// traces while the bootstrapper is active since the infrastructure
// may not have been properly initialized.
Handle<String> stack_trace;
if (FLAG_trace_exception) stack_trace = StackTraceString();
Handle<JSArray> stack_trace_object;
- if (report_exception && capture_stack_trace_for_uncaught_exceptions) {
- stack_trace_object = Top::CaptureCurrentStackTrace(
- stack_trace_for_uncaught_exceptions_frame_limit,
- stack_trace_for_uncaught_exceptions_options);
+ if (report_exception && capture_stack_trace_for_uncaught_exceptions_) {
+ stack_trace_object = CaptureCurrentStackTrace(
+ stack_trace_for_uncaught_exceptions_frame_limit_,
+ stack_trace_for_uncaught_exceptions_options_);
}
ASSERT(is_object); // Can't use the handle unless there's a real object.
message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
@@ -901,20 +718,20 @@ void Top::DoThrow(MaybeObject* exception,
}
// Save the message for reporting if the the exception remains uncaught.
- thread_local_.has_pending_message_ = report_exception;
- thread_local_.pending_message_ = message;
+ thread_local_top()->has_pending_message_ = report_exception;
+ thread_local_top()->pending_message_ = message;
if (!message_obj.is_null()) {
- thread_local_.pending_message_obj_ = *message_obj;
+ thread_local_top()->pending_message_obj_ = *message_obj;
if (location != NULL) {
- thread_local_.pending_message_script_ = *location->script();
- thread_local_.pending_message_start_pos_ = location->start_pos();
- thread_local_.pending_message_end_pos_ = location->end_pos();
+ thread_local_top()->pending_message_script_ = *location->script();
+ thread_local_top()->pending_message_start_pos_ = location->start_pos();
+ thread_local_top()->pending_message_end_pos_ = location->end_pos();
}
}
// Do not forget to clean catcher_ if currently thrown exception cannot
// be caught. If necessary, ReThrow will update the catcher.
- thread_local_.catcher_ = can_be_caught_externally ?
+ thread_local_top()->catcher_ = can_be_caught_externally ?
try_catch_handler() : NULL;
// NOTE: Notifying the debugger or generating the message
@@ -930,11 +747,11 @@ void Top::DoThrow(MaybeObject* exception,
}
-bool Top::IsExternallyCaught() {
+bool Isolate::IsExternallyCaught() {
ASSERT(has_pending_exception());
- if ((thread_local_.catcher_ == NULL) ||
- (try_catch_handler() != thread_local_.catcher_)) {
+ if ((thread_local_top()->catcher_ == NULL) ||
+ (try_catch_handler() != thread_local_top()->catcher_)) {
// When throwing the exception, we found no v8::TryCatch
// which should care about this exception.
return false;
@@ -946,7 +763,8 @@ bool Top::IsExternallyCaught() {
// Get the address of the external handler so we can compare the address to
// determine which one is closer to the top of the stack.
- Address external_handler_address = thread_local_.try_catch_handler_address();
+ Address external_handler_address =
+ thread_local_top()->try_catch_handler_address();
ASSERT(external_handler_address != NULL);
// The exception has been externally caught if and only if there is
@@ -959,7 +777,7 @@ bool Top::IsExternallyCaught() {
// aborted by jumps in control flow like return, break, etc. and we'll
// have another chances to set proper v8::TryCatch.
StackHandler* handler =
- StackHandler::FromAddress(Top::handler(Top::GetCurrentThread()));
+ StackHandler::FromAddress(Isolate::handler(thread_local_top()));
while (handler != NULL && handler->address() < external_handler_address) {
ASSERT(!handler->is_try_catch());
if (handler->is_try_finally()) return false;
@@ -971,46 +789,48 @@ bool Top::IsExternallyCaught() {
}
-void Top::ReportPendingMessages() {
+void Isolate::ReportPendingMessages() {
ASSERT(has_pending_exception());
// If the pending exception is OutOfMemoryException set out_of_memory in
// the global context. Note: We have to mark the global context here
// since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
// set it.
bool external_caught = IsExternallyCaught();
- thread_local_.external_caught_exception_ = external_caught;
- HandleScope scope;
- if (thread_local_.pending_exception_ == Failure::OutOfMemoryException()) {
+ thread_local_top()->external_caught_exception_ = external_caught;
+ HandleScope scope(this);
+ if (thread_local_top()->pending_exception_ ==
+ Failure::OutOfMemoryException()) {
context()->mark_out_of_memory();
- } else if (thread_local_.pending_exception_ ==
- Heap::termination_exception()) {
+ } else if (thread_local_top()->pending_exception_ ==
+ heap_.termination_exception()) {
if (external_caught) {
try_catch_handler()->can_continue_ = false;
- try_catch_handler()->exception_ = Heap::null_value();
+ try_catch_handler()->exception_ = heap_.null_value();
}
} else {
// At this point all non-object (failure) exceptions have
// been dealt with so this shouldn't fail.
Object* pending_exception_object = pending_exception()->ToObjectUnchecked();
Handle<Object> exception(pending_exception_object);
- thread_local_.external_caught_exception_ = false;
+ thread_local_top()->external_caught_exception_ = false;
if (external_caught) {
try_catch_handler()->can_continue_ = true;
- try_catch_handler()->exception_ = thread_local_.pending_exception_;
- if (!thread_local_.pending_message_obj_->IsTheHole()) {
- try_catch_handler()->message_ = thread_local_.pending_message_obj_;
+ try_catch_handler()->exception_ = thread_local_top()->pending_exception_;
+ if (!thread_local_top()->pending_message_obj_->IsTheHole()) {
+ try_catch_handler()->message_ =
+ thread_local_top()->pending_message_obj_;
}
}
- if (thread_local_.has_pending_message_) {
- thread_local_.has_pending_message_ = false;
- if (thread_local_.pending_message_ != NULL) {
- MessageHandler::ReportMessage(thread_local_.pending_message_);
- } else if (!thread_local_.pending_message_obj_->IsTheHole()) {
- Handle<Object> message_obj(thread_local_.pending_message_obj_);
- if (thread_local_.pending_message_script_ != NULL) {
- Handle<Script> script(thread_local_.pending_message_script_);
- int start_pos = thread_local_.pending_message_start_pos_;
- int end_pos = thread_local_.pending_message_end_pos_;
+ if (thread_local_top()->has_pending_message_) {
+ thread_local_top()->has_pending_message_ = false;
+ if (thread_local_top()->pending_message_ != NULL) {
+ MessageHandler::ReportMessage(thread_local_top()->pending_message_);
+ } else if (!thread_local_top()->pending_message_obj_->IsTheHole()) {
+ Handle<Object> message_obj(thread_local_top()->pending_message_obj_);
+ if (thread_local_top()->pending_message_script_ != NULL) {
+ Handle<Script> script(thread_local_top()->pending_message_script_);
+ int start_pos = thread_local_top()->pending_message_start_pos_;
+ int end_pos = thread_local_top()->pending_message_end_pos_;
MessageLocation location(script, start_pos, end_pos);
MessageHandler::ReportMessage(&location, message_obj);
} else {
@@ -1018,40 +838,40 @@ void Top::ReportPendingMessages() {
}
}
}
- thread_local_.external_caught_exception_ = external_caught;
+ thread_local_top()->external_caught_exception_ = external_caught;
set_pending_exception(*exception);
}
clear_pending_message();
}
-void Top::TraceException(bool flag) {
- FLAG_trace_exception = flag;
+void Isolate::TraceException(bool flag) {
+ FLAG_trace_exception = flag; // TODO(isolates): This is an unfortunate use.
}
-bool Top::OptionalRescheduleException(bool is_bottom_call) {
+bool Isolate::OptionalRescheduleException(bool is_bottom_call) {
// Allways reschedule out of memory exceptions.
if (!is_out_of_memory()) {
bool is_termination_exception =
- pending_exception() == Heap::termination_exception();
+ pending_exception() == heap_.termination_exception();
// Do not reschedule the exception if this is the bottom call.
bool clear_exception = is_bottom_call;
if (is_termination_exception) {
if (is_bottom_call) {
- thread_local_.external_caught_exception_ = false;
+ thread_local_top()->external_caught_exception_ = false;
clear_pending_exception();
return false;
}
- } else if (thread_local_.external_caught_exception_) {
+ } else if (thread_local_top()->external_caught_exception_) {
// If the exception is externally caught, clear it if there are no
// JavaScript frames on the way to the C++ frame that has the
// external handler.
- ASSERT(thread_local_.try_catch_handler_address() != NULL);
+ ASSERT(thread_local_top()->try_catch_handler_address() != NULL);
Address external_handler_address =
- thread_local_.try_catch_handler_address();
+ thread_local_top()->try_catch_handler_address();
JavaScriptFrameIterator it;
if (it.done() || (it.frame()->sp() > external_handler_address)) {
clear_exception = true;
@@ -1060,30 +880,30 @@ bool Top::OptionalRescheduleException(bool is_bottom_call) {
// Clear the exception if needed.
if (clear_exception) {
- thread_local_.external_caught_exception_ = false;
+ thread_local_top()->external_caught_exception_ = false;
clear_pending_exception();
return false;
}
}
// Reschedule the exception.
- thread_local_.scheduled_exception_ = pending_exception();
+ thread_local_top()->scheduled_exception_ = pending_exception();
clear_pending_exception();
return true;
}
-void Top::SetCaptureStackTraceForUncaughtExceptions(
+void Isolate::SetCaptureStackTraceForUncaughtExceptions(
bool capture,
int frame_limit,
StackTrace::StackTraceOptions options) {
- capture_stack_trace_for_uncaught_exceptions = capture;
- stack_trace_for_uncaught_exceptions_frame_limit = frame_limit;
- stack_trace_for_uncaught_exceptions_options = options;
+ capture_stack_trace_for_uncaught_exceptions_ = capture;
+ stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit;
+ stack_trace_for_uncaught_exceptions_options_ = options;
}
-bool Top::is_out_of_memory() {
+bool Isolate::is_out_of_memory() {
if (has_pending_exception()) {
MaybeObject* e = pending_exception();
if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
@@ -1100,20 +920,20 @@ bool Top::is_out_of_memory() {
}
-Handle<Context> Top::global_context() {
- GlobalObject* global = thread_local_.context_->global();
+Handle<Context> Isolate::global_context() {
+ GlobalObject* global = thread_local_top()->context_->global();
return Handle<Context>(global->global_context());
}
-Handle<Context> Top::GetCallingGlobalContext() {
+Handle<Context> Isolate::GetCallingGlobalContext() {
JavaScriptFrameIterator it;
#ifdef ENABLE_DEBUGGER_SUPPORT
- if (Debug::InDebugger()) {
+ if (debug_->InDebugger()) {
while (!it.done()) {
JavaScriptFrame* frame = it.frame();
Context* context = Context::cast(frame->context());
- if (context->global_context() == *Debug::debug_context()) {
+ if (context->global_context() == *debug_->debug_context()) {
it.Advance();
} else {
break;
@@ -1128,25 +948,33 @@ Handle<Context> Top::GetCallingGlobalContext() {
}
-char* Top::ArchiveThread(char* to) {
- memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_));
+char* Isolate::ArchiveThread(char* to) {
+ if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
+ RuntimeProfiler::IsolateExitedJS(this);
+ }
+ memcpy(to, reinterpret_cast<char*>(thread_local_top()),
+ sizeof(ThreadLocalTop));
InitializeThreadLocal();
- return to + sizeof(thread_local_);
+ return to + sizeof(ThreadLocalTop);
}
-char* Top::RestoreThread(char* from) {
- memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(thread_local_));
+char* Isolate::RestoreThread(char* from) {
+ memcpy(reinterpret_cast<char*>(thread_local_top()), from,
+ sizeof(ThreadLocalTop));
// This might be just paranoia, but it seems to be needed in case a
// thread_local_ is restored on a separate OS thread.
#ifdef USE_SIMULATOR
#ifdef V8_TARGET_ARCH_ARM
- thread_local_.simulator_ = Simulator::current();
+ thread_local_top()->simulator_ = Simulator::current(this);
#elif V8_TARGET_ARCH_MIPS
- thread_local_.simulator_ = assembler::mips::Simulator::current();
+ thread_local_top()->simulator_ = Simulator::current(this);
#endif
#endif
- return from + sizeof(thread_local_);
+ if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
+ RuntimeProfiler::IsolateEnteredJS(this);
+ }
+ return from + sizeof(ThreadLocalTop);
}
} } // namespace v8::internal
diff --git a/src/top.h b/src/top.h
deleted file mode 100644
index 26ae542f..00000000
--- a/src/top.h
+++ /dev/null
@@ -1,608 +0,0 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef V8_TOP_H_
-#define V8_TOP_H_
-
-#include "atomicops.h"
-#include "compilation-cache.h"
-#include "frames-inl.h"
-#include "runtime-profiler.h"
-
-namespace v8 {
-namespace internal {
-
-class Simulator;
-
-#define RETURN_IF_SCHEDULED_EXCEPTION() \
- if (Top::has_scheduled_exception()) return Top::PromoteScheduledException()
-
-#define RETURN_IF_EMPTY_HANDLE_VALUE(call, value) \
- if (call.is_null()) { \
- ASSERT(Top::has_pending_exception()); \
- return value; \
- }
-
-#define RETURN_IF_EMPTY_HANDLE(call) \
- RETURN_IF_EMPTY_HANDLE_VALUE(call, Failure::Exception())
-
-// Top has static variables used for JavaScript execution.
-
-class SaveContext; // Forward declaration.
-class ThreadVisitor; // Defined in v8threads.h
-class VMState; // Defined in vm-state.h
-
-class ThreadLocalTop BASE_EMBEDDED {
- public:
- // Initialize the thread data.
- void Initialize();
-
- // Get the top C++ try catch handler or NULL if none are registered.
- //
- // This method is not guarenteed to return an address that can be
- // used for comparison with addresses into the JS stack. If such an
- // address is needed, use try_catch_handler_address.
- v8::TryCatch* TryCatchHandler();
-
- // Get the address of the top C++ try catch handler or NULL if
- // none are registered.
- //
- // This method always returns an address that can be compared to
- // pointers into the JavaScript stack. When running on actual
- // hardware, try_catch_handler_address and TryCatchHandler return
- // the same pointer. When running on a simulator with a separate JS
- // stack, try_catch_handler_address returns a JS stack address that
- // corresponds to the place on the JS stack where the C++ handler
- // would have been if the stack were not separate.
- inline Address try_catch_handler_address() {
- return try_catch_handler_address_;
- }
-
- // Set the address of the top C++ try catch handler.
- inline void set_try_catch_handler_address(Address address) {
- try_catch_handler_address_ = address;
- }
-
- void Free() {
- ASSERT(!has_pending_message_);
- ASSERT(!external_caught_exception_);
- ASSERT(try_catch_handler_address_ == NULL);
- }
-
- // The context where the current execution method is created and for variable
- // lookups.
- Context* context_;
- int thread_id_;
- MaybeObject* pending_exception_;
- bool has_pending_message_;
- const char* pending_message_;
- Object* pending_message_obj_;
- Script* pending_message_script_;
- int pending_message_start_pos_;
- int pending_message_end_pos_;
- // Use a separate value for scheduled exceptions to preserve the
- // invariants that hold about pending_exception. We may want to
- // unify them later.
- MaybeObject* scheduled_exception_;
- bool external_caught_exception_;
- SaveContext* save_context_;
- v8::TryCatch* catcher_;
-
- // Stack.
- Address c_entry_fp_; // the frame pointer of the top c entry frame
- Address handler_; // try-blocks are chained through the stack
-
-#ifdef USE_SIMULATOR
-#ifdef V8_TARGET_ARCH_ARM
- Simulator* simulator_;
-#elif V8_TARGET_ARCH_MIPS
- assembler::mips::Simulator* simulator_;
-#endif
-#endif // USE_SIMULATOR
-
-#ifdef ENABLE_LOGGING_AND_PROFILING
- Address js_entry_sp_; // the stack pointer of the bottom js entry frame
- Address external_callback_; // the external callback we're currently in
-#endif
-
-#ifdef ENABLE_VMSTATE_TRACKING
- StateTag current_vm_state_;
-
- // Used for communication with the runtime profiler thread.
- // Possible values are specified in RuntimeProfilerState.
- Atomic32 runtime_profiler_state_;
-#endif
-
- // Generated code scratch locations.
- int32_t formal_count_;
-
- // Call back function to report unsafe JS accesses.
- v8::FailedAccessCheckCallback failed_access_check_callback_;
-
- private:
- Address try_catch_handler_address_;
-};
-
-#define TOP_ADDRESS_LIST(C) \
- C(handler_address) \
- C(c_entry_fp_address) \
- C(context_address) \
- C(pending_exception_address) \
- C(external_caught_exception_address)
-
-#ifdef ENABLE_LOGGING_AND_PROFILING
-#define TOP_ADDRESS_LIST_PROF(C) \
- C(js_entry_sp_address)
-#else
-#define TOP_ADDRESS_LIST_PROF(C)
-#endif
-
-
-class Top {
- public:
- enum AddressId {
-#define C(name) k_##name,
- TOP_ADDRESS_LIST(C)
- TOP_ADDRESS_LIST_PROF(C)
-#undef C
- k_top_address_count
- };
-
- static Address get_address_from_id(AddressId id);
-
- // Access to top context (where the current function object was created).
- static Context* context() { return thread_local_.context_; }
- static void set_context(Context* context) {
- thread_local_.context_ = context;
- }
- static Context** context_address() { return &thread_local_.context_; }
-
- static SaveContext* save_context() {return thread_local_.save_context_; }
- static void set_save_context(SaveContext* save) {
- thread_local_.save_context_ = save;
- }
-
- // Access to current thread id.
- static int thread_id() { return thread_local_.thread_id_; }
- static void set_thread_id(int id) { thread_local_.thread_id_ = id; }
-
- // Interface to pending exception.
- static MaybeObject* pending_exception() {
- ASSERT(has_pending_exception());
- return thread_local_.pending_exception_;
- }
- static bool external_caught_exception() {
- return thread_local_.external_caught_exception_;
- }
- static void set_pending_exception(MaybeObject* exception) {
- thread_local_.pending_exception_ = exception;
- }
- static void clear_pending_exception() {
- thread_local_.pending_exception_ = Heap::the_hole_value();
- }
-
- static MaybeObject** pending_exception_address() {
- return &thread_local_.pending_exception_;
- }
- static bool has_pending_exception() {
- return !thread_local_.pending_exception_->IsTheHole();
- }
- static void clear_pending_message() {
- thread_local_.has_pending_message_ = false;
- thread_local_.pending_message_ = NULL;
- thread_local_.pending_message_obj_ = Heap::the_hole_value();
- thread_local_.pending_message_script_ = NULL;
- }
- static v8::TryCatch* try_catch_handler() {
- return thread_local_.TryCatchHandler();
- }
- static Address try_catch_handler_address() {
- return thread_local_.try_catch_handler_address();
- }
- // This method is called by the api after operations that may throw
- // exceptions. If an exception was thrown and not handled by an external
- // handler the exception is scheduled to be rethrown when we return to running
- // JavaScript code. If an exception is scheduled true is returned.
- static bool OptionalRescheduleException(bool is_bottom_call);
-
-
- static bool* external_caught_exception_address() {
- return &thread_local_.external_caught_exception_;
- }
-
- static MaybeObject** scheduled_exception_address() {
- return &thread_local_.scheduled_exception_;
- }
-
- static MaybeObject* scheduled_exception() {
- ASSERT(has_scheduled_exception());
- return thread_local_.scheduled_exception_;
- }
- static bool has_scheduled_exception() {
- return !thread_local_.scheduled_exception_->IsTheHole();
- }
- static void clear_scheduled_exception() {
- thread_local_.scheduled_exception_ = Heap::the_hole_value();
- }
-
- static bool IsExternallyCaught();
-
- static void SetCaptureStackTraceForUncaughtExceptions(
- bool capture,
- int frame_limit,
- StackTrace::StackTraceOptions options);
-
- // Tells whether the current context has experienced an out of memory
- // exception.
- static bool is_out_of_memory();
-
- static bool is_catchable_by_javascript(MaybeObject* exception) {
- return (exception != Failure::OutOfMemoryException()) &&
- (exception != Heap::termination_exception());
- }
-
- // JS execution stack (see frames.h).
- static Address c_entry_fp(ThreadLocalTop* thread) {
- return thread->c_entry_fp_;
- }
- static Address handler(ThreadLocalTop* thread) { return thread->handler_; }
-
- static inline Address* c_entry_fp_address() {
- return &thread_local_.c_entry_fp_;
- }
- static inline Address* handler_address() { return &thread_local_.handler_; }
-
-#ifdef ENABLE_LOGGING_AND_PROFILING
- // Bottom JS entry (see StackTracer::Trace in log.cc).
- static Address js_entry_sp(ThreadLocalTop* thread) {
- return thread->js_entry_sp_;
- }
- static inline Address* js_entry_sp_address() {
- return &thread_local_.js_entry_sp_;
- }
-
- static Address external_callback() {
- return thread_local_.external_callback_;
- }
- static void set_external_callback(Address callback) {
- thread_local_.external_callback_ = callback;
- }
-#endif
-
-#ifdef ENABLE_VMSTATE_TRACKING
- static StateTag current_vm_state() {
- return thread_local_.current_vm_state_;
- }
-
- static void SetCurrentVMState(StateTag state) {
- if (RuntimeProfiler::IsEnabled()) {
- if (state == JS) {
- // JS or non-JS -> JS transition.
- RuntimeProfilerState old_state = SwapRuntimeProfilerState(PROF_IN_JS);
- if (old_state == PROF_NOT_IN_JS_WAITING_FOR_JS) {
- // If the runtime profiler was waiting, we reset the eager
- // optimizing data in the compilation cache to get a fresh
- // start after not running JavaScript code for a while and
- // signal the runtime profiler so it can resume.
- CompilationCache::ResetEagerOptimizingData();
- runtime_profiler_semaphore_->Signal();
- }
- } else if (thread_local_.current_vm_state_ == JS) {
- // JS -> non-JS transition. Update the runtime profiler state.
- ASSERT(IsInJSState());
- SetRuntimeProfilerState(PROF_NOT_IN_JS);
- }
- }
- thread_local_.current_vm_state_ = state;
- }
-
- // Called in the runtime profiler thread.
- // Returns whether the current VM state is set to JS.
- static bool IsInJSState() {
- ASSERT(RuntimeProfiler::IsEnabled());
- return static_cast<RuntimeProfilerState>(
- NoBarrier_Load(&thread_local_.runtime_profiler_state_)) == PROF_IN_JS;
- }
-
- // Called in the runtime profiler thread.
- // Waits for the VM state to transtion from non-JS to JS. Returns
- // true when notified of the transition, false when the current
- // state is not the expected non-JS state.
- static bool WaitForJSState() {
- ASSERT(RuntimeProfiler::IsEnabled());
- // Try to switch to waiting state.
- RuntimeProfilerState old_state = CompareAndSwapRuntimeProfilerState(
- PROF_NOT_IN_JS, PROF_NOT_IN_JS_WAITING_FOR_JS);
- if (old_state == PROF_NOT_IN_JS) {
- runtime_profiler_semaphore_->Wait();
- return true;
- }
- return false;
- }
-
- // When shutting down we join the profiler thread. Doing so while
- // it's waiting on a semaphore will cause a deadlock, so we have to
- // wake it up first.
- static void WakeUpRuntimeProfilerThreadBeforeShutdown() {
- runtime_profiler_semaphore_->Signal();
- }
-#endif
-
- // Generated code scratch locations.
- static void* formal_count_address() { return &thread_local_.formal_count_; }
-
- static void PrintCurrentStackTrace(FILE* out);
- static void PrintStackTrace(FILE* out, char* thread_data);
- static void PrintStack(StringStream* accumulator);
- static void PrintStack();
- static Handle<String> StackTraceString();
- static Handle<JSArray> CaptureCurrentStackTrace(
- int frame_limit,
- StackTrace::StackTraceOptions options);
-
- // Returns if the top context may access the given global object. If
- // the result is false, the pending exception is guaranteed to be
- // set.
- static bool MayNamedAccess(JSObject* receiver,
- Object* key,
- v8::AccessType type);
- static bool MayIndexedAccess(JSObject* receiver,
- uint32_t index,
- v8::AccessType type);
-
- static void SetFailedAccessCheckCallback(
- v8::FailedAccessCheckCallback callback);
- static void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
-
- // Exception throwing support. The caller should use the result
- // of Throw() as its return value.
- static Failure* Throw(Object* exception, MessageLocation* location = NULL);
- // Re-throw an exception. This involves no error reporting since
- // error reporting was handled when the exception was thrown
- // originally.
- static Failure* ReThrow(MaybeObject* exception,
- MessageLocation* location = NULL);
- static void ScheduleThrow(Object* exception);
- static void ReportPendingMessages();
- static Failure* ThrowIllegalOperation();
-
- // Promote a scheduled exception to pending. Asserts has_scheduled_exception.
- static Failure* PromoteScheduledException();
- static void DoThrow(MaybeObject* exception,
- MessageLocation* location,
- const char* message);
- // Checks if exception should be reported and finds out if it's
- // caught externally.
- static bool ShouldReportException(bool* can_be_caught_externally,
- bool catchable_by_javascript);
-
- // Attempts to compute the current source location, storing the
- // result in the target out parameter.
- static void ComputeLocation(MessageLocation* target);
-
- // Override command line flag.
- static void TraceException(bool flag);
-
- // Out of resource exception helpers.
- static Failure* StackOverflow();
- static Failure* TerminateExecution();
-
- // Administration
- static void Initialize();
- static void TearDown();
- static void Iterate(ObjectVisitor* v);
- static void Iterate(ObjectVisitor* v, ThreadLocalTop* t);
- static char* Iterate(ObjectVisitor* v, char* t);
- static void IterateThread(ThreadVisitor* v);
- static void IterateThread(ThreadVisitor* v, char* t);
-
- // Returns the global object of the current context. It could be
- // a builtin object, or a js global object.
- static Handle<GlobalObject> global() {
- return Handle<GlobalObject>(context()->global());
- }
-
- // Returns the global proxy object of the current context.
- static Object* global_proxy() {
- return context()->global_proxy();
- }
-
- // Returns the current global context.
- static Handle<Context> global_context();
-
- // Returns the global context of the calling JavaScript code. That
- // is, the global context of the top-most JavaScript frame.
- static Handle<Context> GetCallingGlobalContext();
-
- static Handle<JSBuiltinsObject> builtins() {
- return Handle<JSBuiltinsObject>(thread_local_.context_->builtins());
- }
-
- static void RegisterTryCatchHandler(v8::TryCatch* that);
- static void UnregisterTryCatchHandler(v8::TryCatch* that);
-
-#define TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR(index, type, name) \
- static Handle<type> name() { \
- return Handle<type>(context()->global_context()->name()); \
- }
- GLOBAL_CONTEXT_FIELDS(TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR)
-#undef TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR
-
- static inline ThreadLocalTop* GetCurrentThread() { return &thread_local_; }
- static int ArchiveSpacePerThread() { return sizeof(ThreadLocalTop); }
- static char* ArchiveThread(char* to);
- static char* RestoreThread(char* from);
- static void FreeThreadResources() { thread_local_.Free(); }
-
- static const char* kStackOverflowMessage;
-
- private:
-#ifdef ENABLE_VMSTATE_TRACKING
- // Set of states used when communicating with the runtime profiler.
- //
- // The set of possible transitions is divided between the VM and the
- // profiler threads.
- //
- // The VM thread can perform these transitions:
- // o IN_JS -> NOT_IN_JS
- // o NOT_IN_JS -> IN_JS
- // o NOT_IN_JS_WAITING_FOR_JS -> IN_JS notifying the profiler thread
- // using the semaphore.
- // All the above transitions are caused by VM state changes.
- //
- // The profiler thread can only perform a single transition
- // NOT_IN_JS -> NOT_IN_JS_WAITING_FOR_JS before it starts waiting on
- // the semaphore.
- enum RuntimeProfilerState {
- PROF_NOT_IN_JS,
- PROF_NOT_IN_JS_WAITING_FOR_JS,
- PROF_IN_JS
- };
-
- static void SetRuntimeProfilerState(RuntimeProfilerState state) {
- NoBarrier_Store(&thread_local_.runtime_profiler_state_, state);
- }
-
- static RuntimeProfilerState SwapRuntimeProfilerState(
- RuntimeProfilerState state) {
- return static_cast<RuntimeProfilerState>(
- NoBarrier_AtomicExchange(&thread_local_.runtime_profiler_state_,
- state));
- }
-
- static RuntimeProfilerState CompareAndSwapRuntimeProfilerState(
- RuntimeProfilerState old_state,
- RuntimeProfilerState state) {
- return static_cast<RuntimeProfilerState>(
- NoBarrier_CompareAndSwap(&thread_local_.runtime_profiler_state_,
- old_state,
- state));
- }
-
- static Semaphore* runtime_profiler_semaphore_;
-#endif // ENABLE_VMSTATE_TRACKING
-
- // The context that initiated this JS execution.
- static ThreadLocalTop thread_local_;
- static void InitializeThreadLocal();
- static void PrintStackTrace(FILE* out, ThreadLocalTop* thread);
- static void MarkCompactPrologue(bool is_compacting,
- ThreadLocalTop* archived_thread_data);
- static void MarkCompactEpilogue(bool is_compacting,
- ThreadLocalTop* archived_thread_data);
-
- // Debug.
- // Mutex for serializing access to break control structures.
- static Mutex* break_access_;
-
- friend class SaveContext;
- friend class AssertNoContextChange;
- friend class ExecutionAccess;
- friend class ThreadLocalTop;
-
- static void FillCache();
-};
-
-
-// If the GCC version is 4.1.x or 4.2.x an additional field is added to the
-// class as a work around for a bug in the generated code found with these
-// versions of GCC. See V8 issue 122 for details.
-class SaveContext BASE_EMBEDDED {
- public:
- SaveContext()
- : context_(Top::context()),
-#if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300
- dummy_(Top::context()),
-#endif
- prev_(Top::save_context()) {
- Top::set_save_context(this);
-
- // If there is no JS frame under the current C frame, use the value 0.
- JavaScriptFrameIterator it;
- js_sp_ = it.done() ? 0 : it.frame()->sp();
- }
-
- ~SaveContext() {
- Top::set_context(*context_);
- Top::set_save_context(prev_);
- }
-
- Handle<Context> context() { return context_; }
- SaveContext* prev() { return prev_; }
-
- // Returns true if this save context is below a given JavaScript frame.
- bool below(JavaScriptFrame* frame) {
- return (js_sp_ == 0) || (frame->sp() < js_sp_);
- }
-
- private:
- Handle<Context> context_;
-#if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300
- Handle<Context> dummy_;
-#endif
- SaveContext* prev_;
- Address js_sp_; // The top JS frame's sp when saving context.
-};
-
-
-class AssertNoContextChange BASE_EMBEDDED {
-#ifdef DEBUG
- public:
- AssertNoContextChange() :
- context_(Top::context()) {
- }
-
- ~AssertNoContextChange() {
- ASSERT(Top::context() == *context_);
- }
-
- private:
- HandleScope scope_;
- Handle<Context> context_;
-#else
- public:
- AssertNoContextChange() { }
-#endif
-};
-
-
-class ExecutionAccess BASE_EMBEDDED {
- public:
- ExecutionAccess() { Lock(); }
- ~ExecutionAccess() { Unlock(); }
-
- static void Lock() { Top::break_access_->Lock(); }
- static void Unlock() { Top::break_access_->Unlock(); }
-
- static bool TryLock() {
- return Top::break_access_->TryLock();
- }
-};
-
-} } // namespace v8::internal
-
-#endif // V8_TOP_H_
diff --git a/src/type-info.cc b/src/type-info.cc
index 3438ff8f..78f693c2 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -64,42 +64,70 @@ STATIC_ASSERT(DEFAULT_STRING_STUB == Code::kNoExtraICState);
TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code,
Handle<Context> global_context) {
global_context_ = global_context;
- Initialize(code);
+ PopulateMap(code);
+ ASSERT(reinterpret_cast<Address>(*dictionary_.location()) != kHandleZapValue);
}
-void TypeFeedbackOracle::Initialize(Handle<Code> code) {
- ASSERT(map_.is_null()); // Only initialize once.
- map_ = Factory::NewJSObject(Top::object_function());
- PopulateMap(code);
+Handle<Object> TypeFeedbackOracle::GetInfo(int pos) {
+ int entry = dictionary_->FindEntry(pos);
+ return entry != NumberDictionary::kNotFound
+ ? Handle<Object>(dictionary_->ValueAt(entry))
+ : Isolate::Current()->factory()->undefined_value();
}
bool TypeFeedbackOracle::LoadIsMonomorphic(Property* expr) {
- return GetElement(map_, expr->position())->IsMap();
+ Handle<Object> map_or_code(GetInfo(expr->position()));
+ if (map_or_code->IsMap()) return true;
+ if (map_or_code->IsCode()) {
+ Handle<Code> code(Code::cast(*map_or_code));
+ return code->kind() == Code::KEYED_EXTERNAL_ARRAY_LOAD_IC &&
+ code->FindFirstMap() != NULL;
+ }
+ return false;
}
-bool TypeFeedbackOracle:: StoreIsMonomorphic(Assignment* expr) {
- return GetElement(map_, expr->position())->IsMap();
+bool TypeFeedbackOracle::StoreIsMonomorphic(Assignment* expr) {
+ Handle<Object> map_or_code(GetInfo(expr->position()));
+ if (map_or_code->IsMap()) return true;
+ if (map_or_code->IsCode()) {
+ Handle<Code> code(Code::cast(*map_or_code));
+ return code->kind() == Code::KEYED_EXTERNAL_ARRAY_STORE_IC &&
+ code->FindFirstMap() != NULL;
+ }
+ return false;
}
bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) {
- Handle<Object> value = GetElement(map_, expr->position());
+ Handle<Object> value = GetInfo(expr->position());
return value->IsMap() || value->IsSmi();
}
Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) {
ASSERT(LoadIsMonomorphic(expr));
- return Handle<Map>::cast(GetElement(map_, expr->position()));
+ Handle<Object> map_or_code(
+ Handle<HeapObject>::cast(GetInfo(expr->position())));
+ if (map_or_code->IsCode()) {
+ Handle<Code> code(Code::cast(*map_or_code));
+ return Handle<Map>(code->FindFirstMap());
+ }
+ return Handle<Map>(Map::cast(*map_or_code));
}
Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Assignment* expr) {
ASSERT(StoreIsMonomorphic(expr));
- return Handle<Map>::cast(GetElement(map_, expr->position()));
+ Handle<HeapObject> map_or_code(
+ Handle<HeapObject>::cast(GetInfo(expr->position())));
+ if (map_or_code->IsCode()) {
+ Handle<Code> code(Code::cast(*map_or_code));
+ return Handle<Map>(code->FindFirstMap());
+ }
+ return Handle<Map>(Map::cast(*map_or_code));
}
@@ -135,13 +163,26 @@ ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr,
CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
- Handle<Object> value = GetElement(map_, expr->position());
+ Handle<Object> value = GetInfo(expr->position());
if (!value->IsSmi()) return RECEIVER_MAP_CHECK;
CheckType check = static_cast<CheckType>(Smi::cast(*value)->value());
ASSERT(check != RECEIVER_MAP_CHECK);
return check;
}
+ExternalArrayType TypeFeedbackOracle::GetKeyedLoadExternalArrayType(
+ Property* expr) {
+ Handle<Object> stub = GetInfo(expr->position());
+ ASSERT(stub->IsCode());
+ return Code::cast(*stub)->external_array_type();
+}
+
+ExternalArrayType TypeFeedbackOracle::GetKeyedStoreExternalArrayType(
+ Assignment* expr) {
+ Handle<Object> stub = GetInfo(expr->position());
+ ASSERT(stub->IsCode());
+ return Code::cast(*stub)->external_array_type();
+}
Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
CheckType check) {
@@ -166,13 +207,13 @@ Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) {
- Handle<Object> object = GetElement(map_, expr->position());
- return *object == Builtins::builtin(id);
+ return *GetInfo(expr->position()) ==
+ Isolate::Current()->builtins()->builtin(id);
}
TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) {
- Handle<Object> object = GetElement(map_, expr->position());
+ Handle<Object> object = GetInfo(expr->position());
TypeInfo unknown = TypeInfo::Unknown();
if (!object->IsCode()) return unknown;
Handle<Code> code = Handle<Code>::cast(object);
@@ -199,7 +240,7 @@ TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) {
TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) {
- Handle<Object> object = GetElement(map_, expr->position());
+ Handle<Object> object = GetInfo(expr->position());
TypeInfo unknown = TypeInfo::Unknown();
if (!object->IsCode()) return unknown;
Handle<Code> code = Handle<Code>::cast(object);
@@ -261,7 +302,7 @@ TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) {
TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) {
- Handle<Object> object = GetElement(map_, clause->position());
+ Handle<Object> object = GetInfo(clause->position());
TypeInfo unknown = TypeInfo::Unknown();
if (!object->IsCode()) return unknown;
Handle<Code> code = Handle<Code>::cast(object);
@@ -290,10 +331,11 @@ TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) {
ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(int position,
Handle<String> name,
Code::Flags flags) {
- Handle<Object> object = GetElement(map_, position);
+ Isolate* isolate = Isolate::Current();
+ Handle<Object> object = GetInfo(position);
if (object->IsUndefined() || object->IsSmi()) return NULL;
- if (*object == Builtins::builtin(Builtins::StoreIC_GlobalProxy)) {
+ if (*object == isolate->builtins()->builtin(Builtins::kStoreIC_GlobalProxy)) {
// TODO(fschneider): We could collect the maps and signal that
// we need a generic store (or load) here.
ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC);
@@ -305,7 +347,7 @@ ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(int position,
} else if (Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
ZoneMapList* types = new ZoneMapList(4);
ASSERT(object->IsCode());
- StubCache::CollectMatchingMaps(types, *name, flags);
+ isolate->stub_cache()->CollectMatchingMaps(types, *name, flags);
return types->length() > 0 ? types : NULL;
} else {
return NULL;
@@ -314,52 +356,70 @@ ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(int position,
void TypeFeedbackOracle::PopulateMap(Handle<Code> code) {
- HandleScope scope;
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
const int kInitialCapacity = 16;
List<int> code_positions(kInitialCapacity);
List<int> source_positions(kInitialCapacity);
CollectPositions(*code, &code_positions, &source_positions);
+ ASSERT(dictionary_.is_null()); // Only initialize once.
+ dictionary_ = isolate->factory()->NewNumberDictionary(
+ code_positions.length());
+
int length = code_positions.length();
ASSERT(source_positions.length() == length);
for (int i = 0; i < length; i++) {
+ HandleScope loop_scope(isolate);
RelocInfo info(code->instruction_start() + code_positions[i],
RelocInfo::CODE_TARGET, 0);
Handle<Code> target(Code::GetCodeFromTargetAddress(info.target_address()));
int position = source_positions[i];
InlineCacheState state = target->ic_state();
Code::Kind kind = target->kind();
+ Handle<Object> value;
if (kind == Code::BINARY_OP_IC ||
kind == Code::TYPE_RECORDING_BINARY_OP_IC ||
kind == Code::COMPARE_IC) {
// TODO(kasperl): Avoid having multiple ICs with the same
// position by making sure that we have position information
// recorded for all binary ICs.
- if (GetElement(map_, position)->IsUndefined()) {
- SetElement(map_, position, target, kNonStrictMode);
+ int entry = dictionary_->FindEntry(position);
+ if (entry == NumberDictionary::kNotFound) {
+ value = target;
}
} else if (state == MONOMORPHIC) {
- if (target->kind() != Code::CALL_IC ||
+ if (kind == Code::KEYED_EXTERNAL_ARRAY_LOAD_IC ||
+ kind == Code::KEYED_EXTERNAL_ARRAY_STORE_IC) {
+ value = target;
+ } else if (target->kind() != Code::CALL_IC ||
target->check_type() == RECEIVER_MAP_CHECK) {
- Handle<Map> map = Handle<Map>(target->FindFirstMap());
- if (*map == NULL) {
- SetElement(map_, position, target, kNonStrictMode);
+ Map* map = target->FindFirstMap();
+ if (map == NULL) {
+ value = target;
} else {
- SetElement(map_, position, map, kNonStrictMode);
+ value = Handle<Map>(map);
}
} else {
ASSERT(target->kind() == Code::CALL_IC);
CheckType check = target->check_type();
ASSERT(check != RECEIVER_MAP_CHECK);
- SetElement(map_, position,
- Handle<Object>(Smi::FromInt(check)), kNonStrictMode);
- ASSERT(Smi::cast(*GetElement(map_, position))->value() == check);
+ value = Handle<Object>(Smi::FromInt(check));
}
} else if (state == MEGAMORPHIC) {
- SetElement(map_, position, target, kNonStrictMode);
+ value = target;
+ }
+
+ if (!value.is_null()) {
+ Handle<NumberDictionary> new_dict =
+ isolate->factory()->DictionaryAtNumberPut(
+ dictionary_, position, value);
+ dictionary_ = loop_scope.CloseAndEscape(new_dict);
}
}
+ // Allocate handle in the parent scope.
+ dictionary_ = scope.CloseAndEscape(dictionary_);
}
diff --git a/src/type-info.h b/src/type-info.h
index 34ff5845..c068489e 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -249,6 +249,9 @@ class TypeFeedbackOracle BASE_EMBEDDED {
ZoneMapList* StoreReceiverTypes(Assignment* expr, Handle<String> name);
ZoneMapList* CallReceiverTypes(Call* expr, Handle<String> name);
+ ExternalArrayType GetKeyedLoadExternalArrayType(Property* expr);
+ ExternalArrayType GetKeyedStoreExternalArrayType(Assignment* expr);
+
CheckType GetCallCheckType(Call* expr);
Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
@@ -260,8 +263,6 @@ class TypeFeedbackOracle BASE_EMBEDDED {
TypeInfo SwitchType(CaseClause* clause);
private:
- void Initialize(Handle<Code> code);
-
ZoneMapList* CollectReceiverTypes(int position,
Handle<String> name,
Code::Flags flags);
@@ -272,8 +273,12 @@ class TypeFeedbackOracle BASE_EMBEDDED {
List<int>* code_positions,
List<int>* source_positions);
+ // Returns an element from the backing store. Returns undefined if
+ // there is no information.
+ Handle<Object> GetInfo(int pos);
+
Handle<Context> global_context_;
- Handle<JSObject> map_;
+ Handle<NumberDictionary> dictionary_;
DISALLOW_COPY_AND_ASSIGN(TypeFeedbackOracle);
};
diff --git a/src/unicode.cc b/src/unicode.cc
index 346f673f..6e0ac1a3 100644
--- a/src/unicode.cc
+++ b/src/unicode.cc
@@ -1572,7 +1572,7 @@ int CanonicalizationRange::Convert(uchar c,
}
-uchar UnicodeData::kMaxCodePoint = 65533;
+const uchar UnicodeData::kMaxCodePoint = 65533;
int UnicodeData::GetByteCount() {
return kUppercaseTable0Size * sizeof(int32_t) // NOLINT
diff --git a/src/unicode.h b/src/unicode.h
index 9d1d6832..39fc3496 100644
--- a/src/unicode.h
+++ b/src/unicode.h
@@ -97,7 +97,7 @@ class UnicodeData {
private:
friend class Test;
static int GetByteCount();
- static uchar kMaxCodePoint;
+ static const uchar kMaxCodePoint;
};
// --- U t f 8 ---
diff --git a/src/utils.h b/src/utils.h
index 219343b7..b89f2849 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -784,6 +784,9 @@ struct BitCastHelper<Dest, Source*> {
};
template <class Dest, class Source>
+INLINE(Dest BitCast(const Source& source));
+
+template <class Dest, class Source>
inline Dest BitCast(const Source& source) {
return BitCastHelper<Dest, Source>::cast(source);
}
diff --git a/src/v8-counters.cc b/src/v8-counters.cc
index de2ce669..c6aa9cb7 100644
--- a/src/v8-counters.cc
+++ b/src/v8-counters.cc
@@ -32,24 +32,31 @@
namespace v8 {
namespace internal {
+Counters::Counters() {
#define HT(name, caption) \
- HistogramTimer Counters::name = { #caption, NULL, false, 0, 0 }; \
-
- HISTOGRAM_TIMER_LIST(HT)
-#undef SR
+ HistogramTimer name = { #caption, NULL, false, 0, 0 }; \
+ name##_ = name;
+ HISTOGRAM_TIMER_LIST(HT)
+#undef HT
#define SC(name, caption) \
- StatsCounter Counters::name = { "c:" #caption, NULL, false };
+ StatsCounter name = { "c:" #caption, NULL, false };\
+ name##_ = name;
- STATS_COUNTER_LIST_1(SC)
- STATS_COUNTER_LIST_2(SC)
+ STATS_COUNTER_LIST_1(SC)
+ STATS_COUNTER_LIST_2(SC)
#undef SC
-StatsCounter Counters::state_counters[] = {
+ StatsCounter state_counters[] = {
#define COUNTER_NAME(name) \
- { "c:V8.State" #name, NULL, false },
- STATE_TAG_LIST(COUNTER_NAME)
+ { "c:V8.State" #name, NULL, false },
+ STATE_TAG_LIST(COUNTER_NAME)
#undef COUNTER_NAME
-};
+ };
+
+ for (int i = 0; i < kSlidingStateWindowCounterCount; ++i) {
+ state_counters_[i] = state_counters[i];
+ }
+}
} } // namespace v8::internal
diff --git a/src/v8-counters.h b/src/v8-counters.h
index 9b91aceb..04482e80 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -128,7 +128,7 @@ namespace internal {
SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles) \
SC(map_slow_to_fast_elements, V8.MapSlowToFastElements) \
SC(map_fast_to_slow_elements, V8.MapFastToSlowElements) \
- SC(map_to_pixel_array_elements, V8.MapToPixelArrayElements) \
+ SC(map_to_external_array_elements, V8.MapToExternalArrayElements) \
/* How is the generic keyed-load stub used? */ \
SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi) \
SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol) \
@@ -207,8 +207,6 @@ namespace internal {
SC(memcopy_noxmm, V8.MemCopyNoXMM) \
SC(enum_cache_hits, V8.EnumCacheHits) \
SC(enum_cache_misses, V8.EnumCacheMisses) \
- SC(reloc_info_count, V8.RelocInfoCount) \
- SC(reloc_info_size, V8.RelocInfoSize) \
SC(zone_segment_bytes, V8.ZoneSegmentBytes) \
SC(compute_entry_frame, V8.ComputeEntryFrame) \
SC(generic_binary_stub_calls, V8.GenericBinaryStubCalls) \
@@ -254,15 +252,15 @@ namespace internal {
// This file contains all the v8 counters that are in use.
-class Counters : AllStatic {
+class Counters {
public:
#define HT(name, caption) \
- static HistogramTimer name;
+ HistogramTimer* name() { return &name##_; }
HISTOGRAM_TIMER_LIST(HT)
#undef HT
#define SC(name, caption) \
- static StatsCounter name;
+ StatsCounter* name() { return &name##_; }
STATS_COUNTER_LIST_1(SC)
STATS_COUNTER_LIST_2(SC)
#undef SC
@@ -272,17 +270,43 @@ class Counters : AllStatic {
HISTOGRAM_TIMER_LIST(RATE_ID)
#undef RATE_ID
#define COUNTER_ID(name, caption) k_##name,
- STATS_COUNTER_LIST_1(COUNTER_ID)
- STATS_COUNTER_LIST_2(COUNTER_ID)
+ STATS_COUNTER_LIST_1(COUNTER_ID)
+ STATS_COUNTER_LIST_2(COUNTER_ID)
#undef COUNTER_ID
#define COUNTER_ID(name) k_##name,
- STATE_TAG_LIST(COUNTER_ID)
+ STATE_TAG_LIST(COUNTER_ID)
#undef COUNTER_ID
stats_counter_count
};
+ StatsCounter* state_counters(StateTag state) {
+ return &state_counters_[state];
+ }
+
+ private:
+#define HT(name, caption) \
+ HistogramTimer name##_;
+ HISTOGRAM_TIMER_LIST(HT)
+#undef HT
+
+#define SC(name, caption) \
+ StatsCounter name##_;
+ STATS_COUNTER_LIST_1(SC)
+ STATS_COUNTER_LIST_2(SC)
+#undef SC
+
+ enum {
+#define COUNTER_ID(name) __##name,
+ STATE_TAG_LIST(COUNTER_ID)
+#undef COUNTER_ID
+ kSlidingStateWindowCounterCount
+ };
+
// Sliding state window counters.
- static StatsCounter state_counters[];
+ StatsCounter state_counters_[kSlidingStateWindowCounterCount];
+ friend class Isolate;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Counters);
};
} } // namespace v8::internal
diff --git a/src/v8.cc b/src/v8.cc
index 945043da..8153372f 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -27,6 +27,7 @@
#include "v8.h"
+#include "isolate.h"
#include "bootstrapper.h"
#include "debug.h"
#include "deoptimizer.h"
@@ -36,8 +37,6 @@
#include "log.h"
#include "runtime-profiler.h"
#include "serialize.h"
-#include "simulator.h"
-#include "stub-cache.h"
namespace v8 {
namespace internal {
@@ -50,9 +49,24 @@ bool V8::use_crankshaft_ = true;
bool V8::Initialize(Deserializer* des) {
- bool create_heap_objects = des == NULL;
- if (has_been_disposed_ || has_fatal_error_) return false;
- if (IsRunning()) return true;
+ // The current thread may not yet had entered an isolate to run.
+ // Note the Isolate::Current() may be non-null because for various
+ // initialization purposes an initializing thread may be assigned an isolate
+ // but not actually enter it.
+ if (i::Isolate::CurrentPerIsolateThreadData() == NULL) {
+ i::Isolate::EnterDefaultIsolate();
+ }
+
+ ASSERT(i::Isolate::CurrentPerIsolateThreadData() != NULL);
+ ASSERT(i::Isolate::CurrentPerIsolateThreadData()->thread_id() ==
+ i::Thread::GetThreadLocalInt(i::Isolate::thread_id_key()));
+ ASSERT(i::Isolate::CurrentPerIsolateThreadData()->isolate() ==
+ i::Isolate::Current());
+
+ if (IsDead()) return false;
+
+ Isolate* isolate = Isolate::Current();
+ if (isolate->IsInitialized()) return true;
#if defined(V8_TARGET_ARCH_ARM) && !defined(USE_ARM_EABI)
use_crankshaft_ = false;
@@ -62,90 +76,13 @@ bool V8::Initialize(Deserializer* des) {
// Peephole optimization might interfere with deoptimization.
FLAG_peephole_optimization = !use_crankshaft_;
+
is_running_ = true;
has_been_setup_ = true;
has_fatal_error_ = false;
has_been_disposed_ = false;
-#ifdef DEBUG
- // The initialization process does not handle memory exhaustion.
- DisallowAllocationFailure disallow_allocation_failure;
-#endif
-
- // Enable logging before setting up the heap
- Logger::Setup();
-
- CpuProfiler::Setup();
- HeapProfiler::Setup();
-
- // Setup the platform OS support.
- OS::Setup();
- // Initialize other runtime facilities
-#if defined(USE_SIMULATOR)
-#if defined(V8_TARGET_ARCH_ARM)
- Simulator::Initialize();
-#elif defined(V8_TARGET_ARCH_MIPS)
- ::assembler::mips::Simulator::Initialize();
-#endif
-#endif
-
- { // NOLINT
- // Ensure that the thread has a valid stack guard. The v8::Locker object
- // will ensure this too, but we don't have to use lockers if we are only
- // using one thread.
- ExecutionAccess lock;
- StackGuard::InitThread(lock);
- }
-
- // Setup the object heap
- ASSERT(!Heap::HasBeenSetup());
- if (!Heap::Setup(create_heap_objects)) {
- SetFatalError();
- return false;
- }
-
- Bootstrapper::Initialize(create_heap_objects);
- Builtins::Setup(create_heap_objects);
- Top::Initialize();
-
- if (FLAG_preemption) {
- v8::Locker locker;
- v8::Locker::StartPreemption(100);
- }
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
- Debug::Setup(create_heap_objects);
-#endif
- StubCache::Initialize(create_heap_objects);
-
- // If we are deserializing, read the state into the now-empty heap.
- if (des != NULL) {
- des->Deserialize();
- StubCache::Clear();
- }
-
- // Deserializing may put strange things in the root array's copy of the
- // stack guard.
- Heap::SetStackLimits();
-
- // Setup the CPU support. Must be done after heap setup and after
- // any deserialization because we have to have the initial heap
- // objects in place for creating the code object used for probing.
- CPU::Setup();
-
- Deoptimizer::Setup();
- LAllocator::Setup();
- RuntimeProfiler::Setup();
-
- // If we are deserializing, log non-function code objects and compiled
- // functions found in the snapshot.
- if (des != NULL && FLAG_log_code) {
- HandleScope scope;
- LOG(LogCodeObjects());
- LOG(LogCompiledFunctions());
- }
-
- return true;
+ return isolate->Init(des);
}
@@ -156,31 +93,11 @@ void V8::SetFatalError() {
void V8::TearDown() {
- if (!has_been_setup_ || has_been_disposed_) return;
-
- if (FLAG_time_hydrogen) HStatistics::Instance()->Print();
+ Isolate* isolate = Isolate::Current();
+ ASSERT(isolate->IsDefaultIsolate());
- // We must stop the logger before we tear down other components.
- Logger::EnsureTickerStopped();
-
- Deoptimizer::TearDown();
-
- if (FLAG_preemption) {
- v8::Locker locker;
- v8::Locker::StopPreemption();
- }
-
- Builtins::TearDown();
- Bootstrapper::TearDown();
-
- Top::TearDown();
-
- HeapProfiler::TearDown();
- CpuProfiler::TearDown();
- RuntimeProfiler::TearDown();
-
- Logger::TearDown();
- Heap::TearDown();
+ if (!has_been_setup_ || has_been_disposed_) return;
+ isolate->TearDown();
is_running_ = false;
has_been_disposed_ = true;
@@ -218,7 +135,9 @@ static uint32_t random_base(random_state *state) {
// Used by JavaScript APIs
-uint32_t V8::Random() {
+uint32_t V8::Random(Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ // TODO(isolates): move lo and hi to isolate
static random_state state = {0, 0};
return random_base(&state);
}
@@ -227,7 +146,9 @@ uint32_t V8::Random() {
// Used internally by the JIT and memory allocator for security
// purposes. So, we keep a different state to prevent informations
// leaks that could be used in an exploit.
-uint32_t V8::RandomPrivate() {
+uint32_t V8::RandomPrivate(Isolate* isolate) {
+ ASSERT(isolate == Isolate::Current());
+ // TODO(isolates): move lo and hi to isolate
static random_state state = {0, 0};
return random_base(&state);
}
@@ -239,7 +160,7 @@ bool V8::IdleNotification() {
if (!FLAG_use_idle_notification) return true;
// Tell the heap that it may want to adjust.
- return Heap::IdleNotification();
+ return HEAP->IdleNotification();
}
@@ -251,7 +172,7 @@ typedef union {
Object* V8::FillHeapNumberWithRandom(Object* heap_number) {
- uint64_t random_bits = Random();
+ uint64_t random_bits = Random(Isolate::Current());
// Make a double* from address (heap_number + sizeof(double)).
double_int_union* r = reinterpret_cast<double_int_union*>(
reinterpret_cast<char*>(heap_number) +
diff --git a/src/v8.h b/src/v8.h
index cc1673e1..e7ca0d2e 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -86,6 +86,7 @@ class V8 : public AllStatic {
static bool UseCrankshaft() { return use_crankshaft_; }
static void DisableCrankshaft() { use_crankshaft_ = false; }
// To be dead you have to have lived
+ // TODO(isolates): move IsDead to Isolate.
static bool IsDead() { return has_fatal_error_ || has_been_disposed_; }
static void SetFatalError();
@@ -94,12 +95,12 @@ class V8 : public AllStatic {
bool take_snapshot = false);
// Random number generation support. Not cryptographically safe.
- static uint32_t Random();
+ static uint32_t Random(Isolate* isolate);
// We use random numbers internally in memory allocation and in the
// compilers for security. In order to prevent information leaks we
// use a separate random state for internal random number
// generation.
- static uint32_t RandomPrivate();
+ static uint32_t RandomPrivate(Isolate* isolate);
static Object* FillHeapNumberWithRandom(Object* heap_number);
// Idle notification directly from the API.
diff --git a/src/v8globals.h b/src/v8globals.h
index d11bc383..2a01dfd1 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -318,14 +318,15 @@ enum InlineCacheHolderFlag {
// Must fit in the BitField PropertyDetails::TypeField.
// A copy of this is in mirror-debugger.js.
enum PropertyType {
- NORMAL = 0, // only in slow mode
- FIELD = 1, // only in fast mode
- CONSTANT_FUNCTION = 2, // only in fast mode
- CALLBACKS = 3,
- INTERCEPTOR = 4, // only in lookup results, not in descriptors.
- MAP_TRANSITION = 5, // only in fast mode
- CONSTANT_TRANSITION = 6, // only in fast mode
- NULL_DESCRIPTOR = 7, // only in fast mode
+ NORMAL = 0, // only in slow mode
+ FIELD = 1, // only in fast mode
+ CONSTANT_FUNCTION = 2, // only in fast mode
+ CALLBACKS = 3,
+ INTERCEPTOR = 4, // only in lookup results, not in descriptors.
+ MAP_TRANSITION = 5, // only in fast mode
+ EXTERNAL_ARRAY_TRANSITION = 6,
+ CONSTANT_TRANSITION = 7, // only in fast mode
+ NULL_DESCRIPTOR = 8, // only in fast mode
// All properties before MAP_TRANSITION are real.
FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION,
// There are no IC stubs for NULL_DESCRIPTORS. Therefore,
@@ -443,11 +444,11 @@ enum StateTag {
#define TRACK_MEMORY(name) \
void* operator new(size_t size) { \
void* result = ::operator new(size); \
- Logger::NewEvent(name, result, size); \
+ Logger::NewEventStatic(name, result, size); \
return result; \
} \
void operator delete(void* object) { \
- Logger::DeleteEvent(name, object); \
+ Logger::DeleteEventStatic(name, object); \
::operator delete(object); \
}
#else
@@ -467,12 +468,17 @@ enum CpuFeature { SSE4_1 = 32 + 19, // x86
CPUID = 10, // x86
VFP3 = 1, // ARM
ARMv7 = 2, // ARM
- SAHF = 0}; // x86
+ SAHF = 0, // x86
+ FPU = 1}; // MIPS
// The Strict Mode (ECMA-262 5th edition, 4.2.2).
enum StrictModeFlag {
kNonStrictMode,
- kStrictMode
+ kStrictMode,
+ // This value is never used, but is needed to prevent GCC 4.5 from failing
+ // to compile when we assert that a flag is either kNonStrictMode or
+ // kStrictMode.
+ kInvalidStrictFlag
};
} } // namespace v8::internal
diff --git a/src/memory.h b/src/v8memory.h
index 901e78d2..901e78d2 100644
--- a/src/memory.h
+++ b/src/v8memory.h
diff --git a/src/v8natives.js b/src/v8natives.js
index 563de732..4fcf0ac4 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -251,7 +251,11 @@ function ObjectDefineGetter(name, fun) {
if (!IS_FUNCTION(fun)) {
throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
}
- return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun);
+ var desc = new PropertyDescriptor();
+ desc.setGet(fun);
+ desc.setEnumerable(true);
+ desc.setConfigurable(true);
+ DefineOwnProperty(ToObject(this), ToString(name), desc, false);
}
@@ -271,7 +275,11 @@ function ObjectDefineSetter(name, fun) {
throw new $TypeError(
'Object.prototype.__defineSetter__: Expecting function');
}
- return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun);
+ var desc = new PropertyDescriptor();
+ desc.setSet(fun);
+ desc.setEnumerable(true);
+ desc.setConfigurable(true);
+ DefineOwnProperty(ToObject(this), ToString(name), desc, false);
}
@@ -394,6 +402,10 @@ function PropertyDescriptor() {
this.hasSetter_ = false;
}
+PropertyDescriptor.prototype.__proto__ = null;
+PropertyDescriptor.prototype.toString = function() {
+ return "[object PropertyDescriptor]";
+};
PropertyDescriptor.prototype.setValue = function(value) {
this.value_ = value;
@@ -495,7 +507,7 @@ PropertyDescriptor.prototype.hasSetter = function() {
// property descriptor. For a description of the array layout please
// see the runtime.cc file.
function ConvertDescriptorArrayToDescriptor(desc_array) {
- if (desc_array == false) {
+ if (desc_array === false) {
throw 'Internal error: invalid desc_array';
}
@@ -544,7 +556,7 @@ function GetOwnProperty(obj, p) {
var props = %GetOwnProperty(ToObject(obj), ToString(p));
// A false value here means that access checks failed.
- if (props == false) return void 0;
+ if (props === false) return void 0;
return ConvertDescriptorArrayToDescriptor(props);
}
@@ -554,15 +566,20 @@ function GetOwnProperty(obj, p) {
function DefineOwnProperty(obj, p, desc, should_throw) {
var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
// A false value here means that access checks failed.
- if (current_or_access == false) return void 0;
+ if (current_or_access === false) return void 0;
var current = ConvertDescriptorArrayToDescriptor(current_or_access);
var extensible = %IsExtensible(ToObject(obj));
// Error handling according to spec.
// Step 3
- if (IS_UNDEFINED(current) && !extensible)
- throw MakeTypeError("define_disallowed", ["defineProperty"]);
+ if (IS_UNDEFINED(current) && !extensible) {
+ if (should_throw) {
+ throw MakeTypeError("define_disallowed", ["defineProperty"]);
+ } else {
+ return;
+ }
+ }
if (!IS_UNDEFINED(current)) {
// Step 5 and 6
@@ -587,31 +604,55 @@ function DefineOwnProperty(obj, p, desc, should_throw) {
if (desc.isConfigurable() ||
(desc.hasEnumerable() &&
desc.isEnumerable() != current.isEnumerable())) {
- throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ if (should_throw) {
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ } else {
+ return;
+ }
}
// Step 8
if (!IsGenericDescriptor(desc)) {
// Step 9a
if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
- throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ if (should_throw) {
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ } else {
+ return;
+ }
}
// Step 10a
if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
if (!current.isWritable() && desc.isWritable()) {
- throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ if (should_throw) {
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ } else {
+ return;
+ }
}
if (!current.isWritable() && desc.hasValue() &&
!SameValue(desc.getValue(), current.getValue())) {
- throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ if (should_throw) {
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ } else {
+ return;
+ }
}
}
// Step 11
if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
- throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ if (should_throw) {
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ } else {
+ return;
+ }
}
if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
- throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ if (should_throw) {
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ } else {
+ return;
+ }
}
}
}
diff --git a/src/v8threads.cc b/src/v8threads.cc
index 8a5fe690..cecafaa6 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -36,11 +36,6 @@
namespace v8 {
-static internal::Thread::LocalStorageKey thread_state_key =
- internal::Thread::CreateThreadLocalKey();
-static internal::Thread::LocalStorageKey thread_id_key =
- internal::Thread::CreateThreadLocalKey();
-
// Track whether this V8 instance has ever called v8::Locker. This allows the
// API code to verify that the lock is always held when V8 is being entered.
@@ -50,64 +45,88 @@ bool Locker::active_ = false;
// Constructor for the Locker object. Once the Locker is constructed the
// current thread will be guaranteed to have the big V8 lock.
Locker::Locker() : has_lock_(false), top_level_(true) {
+ // TODO(isolates): When Locker has Isolate parameter and it is provided, grab
+ // that one instead of using the current one.
+ // We pull default isolate for Locker constructor w/o p[arameter.
+ // A thread should not enter an isolate before acquiring a lock,
+ // in cases which mandate using Lockers.
+ // So getting a lock is the first thing threads do in a scenario where
+ // multple threads share an isolate. Hence, we need to access
+ // 'locking isolate' before we can actually enter into default isolate.
+ internal::Isolate* isolate = internal::Isolate::GetDefaultIsolateForLocking();
+ ASSERT(isolate != NULL);
+
// Record that the Locker has been used at least once.
active_ = true;
// Get the big lock if necessary.
- if (!internal::ThreadManager::IsLockedByCurrentThread()) {
- internal::ThreadManager::Lock();
+ if (!isolate->thread_manager()->IsLockedByCurrentThread()) {
+ isolate->thread_manager()->Lock();
has_lock_ = true;
+
+ if (isolate->IsDefaultIsolate()) {
+ // This only enters if not yet entered.
+ internal::Isolate::EnterDefaultIsolate();
+ }
+
+ ASSERT(internal::Thread::HasThreadLocal(
+ internal::Isolate::thread_id_key()));
+
// Make sure that V8 is initialized. Archiving of threads interferes
// with deserialization by adding additional root pointers, so we must
// initialize here, before anyone can call ~Locker() or Unlocker().
- if (!internal::V8::IsRunning()) {
+ if (!isolate->IsInitialized()) {
V8::Initialize();
}
// This may be a locker within an unlocker in which case we have to
// get the saved state for this thread and restore it.
- if (internal::ThreadManager::RestoreThread()) {
+ if (isolate->thread_manager()->RestoreThread()) {
top_level_ = false;
} else {
- internal::ExecutionAccess access;
- internal::StackGuard::ClearThread(access);
- internal::StackGuard::InitThread(access);
+ internal::ExecutionAccess access(isolate);
+ isolate->stack_guard()->ClearThread(access);
+ isolate->stack_guard()->InitThread(access);
}
}
- ASSERT(internal::ThreadManager::IsLockedByCurrentThread());
-
- // Make sure this thread is assigned a thread id.
- internal::ThreadManager::AssignId();
+ ASSERT(isolate->thread_manager()->IsLockedByCurrentThread());
}
bool Locker::IsLocked() {
- return internal::ThreadManager::IsLockedByCurrentThread();
+ return internal::Isolate::Current()->thread_manager()->
+ IsLockedByCurrentThread();
}
Locker::~Locker() {
- ASSERT(internal::ThreadManager::IsLockedByCurrentThread());
+ // TODO(isolate): this should use a field storing the isolate it
+ // locked instead.
+ internal::Isolate* isolate = internal::Isolate::Current();
+ ASSERT(isolate->thread_manager()->IsLockedByCurrentThread());
if (has_lock_) {
if (top_level_) {
- internal::ThreadManager::FreeThreadResources();
+ isolate->thread_manager()->FreeThreadResources();
} else {
- internal::ThreadManager::ArchiveThread();
+ isolate->thread_manager()->ArchiveThread();
}
- internal::ThreadManager::Unlock();
+ isolate->thread_manager()->Unlock();
}
}
Unlocker::Unlocker() {
- ASSERT(internal::ThreadManager::IsLockedByCurrentThread());
- internal::ThreadManager::ArchiveThread();
- internal::ThreadManager::Unlock();
+ internal::Isolate* isolate = internal::Isolate::Current();
+ ASSERT(isolate->thread_manager()->IsLockedByCurrentThread());
+ isolate->thread_manager()->ArchiveThread();
+ isolate->thread_manager()->Unlock();
}
Unlocker::~Unlocker() {
- ASSERT(!internal::ThreadManager::IsLockedByCurrentThread());
- internal::ThreadManager::Lock();
- internal::ThreadManager::RestoreThread();
+ // TODO(isolates): check it's the isolate we unlocked.
+ internal::Isolate* isolate = internal::Isolate::Current();
+ ASSERT(!isolate->thread_manager()->IsLockedByCurrentThread());
+ isolate->thread_manager()->Lock();
+ isolate->thread_manager()->RestoreThread();
}
@@ -130,44 +149,45 @@ bool ThreadManager::RestoreThread() {
// had prepared back in the free list, since we didn't need it after all.
if (lazily_archived_thread_.IsSelf()) {
lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
- ASSERT(Thread::GetThreadLocal(thread_state_key) ==
+ ASSERT(Isolate::CurrentPerIsolateThreadData()->thread_state() ==
lazily_archived_thread_state_);
lazily_archived_thread_state_->set_id(kInvalidId);
lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
lazily_archived_thread_state_ = NULL;
- Thread::SetThreadLocal(thread_state_key, NULL);
+ Isolate::CurrentPerIsolateThreadData()->set_thread_state(NULL);
return true;
}
// Make sure that the preemption thread cannot modify the thread state while
// it is being archived or restored.
- ExecutionAccess access;
+ ExecutionAccess access(isolate_);
// If there is another thread that was lazily archived then we have to really
// archive it now.
if (lazily_archived_thread_.IsValid()) {
EagerlyArchiveThread();
}
- ThreadState* state =
- reinterpret_cast<ThreadState*>(Thread::GetThreadLocal(thread_state_key));
- if (state == NULL) {
+ Isolate::PerIsolateThreadData* per_thread =
+ Isolate::CurrentPerIsolateThreadData();
+ if (per_thread == NULL || per_thread->thread_state() == NULL) {
// This is a new thread.
- StackGuard::InitThread(access);
+ isolate_->stack_guard()->InitThread(access);
return false;
}
+ ThreadState* state = per_thread->thread_state();
char* from = state->data();
- from = HandleScopeImplementer::RestoreThread(from);
- from = Top::RestoreThread(from);
+ from = isolate_->handle_scope_implementer()->RestoreThread(from);
+ from = isolate_->RestoreThread(from);
from = Relocatable::RestoreState(from);
#ifdef ENABLE_DEBUGGER_SUPPORT
- from = Debug::RestoreDebug(from);
+ from = isolate_->debug()->RestoreDebug(from);
#endif
- from = StackGuard::RestoreStackGuard(from);
- from = RegExpStack::RestoreStack(from);
- from = Bootstrapper::RestoreState(from);
- Thread::SetThreadLocal(thread_state_key, NULL);
+ from = isolate_->stack_guard()->RestoreStackGuard(from);
+ from = isolate_->regexp_stack()->RestoreStack(from);
+ from = isolate_->bootstrapper()->RestoreState(from);
+ per_thread->set_thread_state(NULL);
if (state->terminate_on_restore()) {
- StackGuard::TerminateExecution();
+ isolate_->stack_guard()->TerminateExecution();
state->set_terminate_on_restore(false);
}
state->set_id(kInvalidId);
@@ -192,7 +212,7 @@ void ThreadManager::Unlock() {
static int ArchiveSpacePerThread() {
return HandleScopeImplementer::ArchiveSpacePerThread() +
- Top::ArchiveSpacePerThread() +
+ Isolate::ArchiveSpacePerThread() +
#ifdef ENABLE_DEBUGGER_SUPPORT
Debug::ArchiveSpacePerThread() +
#endif
@@ -203,13 +223,12 @@ static int ArchiveSpacePerThread() {
}
-ThreadState* ThreadState::free_anchor_ = new ThreadState();
-ThreadState* ThreadState::in_use_anchor_ = new ThreadState();
-
-
-ThreadState::ThreadState() : id_(ThreadManager::kInvalidId),
- terminate_on_restore_(false),
- next_(this), previous_(this) {
+ThreadState::ThreadState(ThreadManager* thread_manager)
+ : id_(ThreadManager::kInvalidId),
+ terminate_on_restore_(false),
+ next_(this),
+ previous_(this),
+ thread_manager_(thread_manager) {
}
@@ -226,7 +245,8 @@ void ThreadState::Unlink() {
void ThreadState::LinkInto(List list) {
ThreadState* flying_anchor =
- list == FREE_LIST ? free_anchor_ : in_use_anchor_;
+ list == FREE_LIST ? thread_manager_->free_anchor_
+ : thread_manager_->in_use_anchor_;
next_ = flying_anchor->next_;
previous_ = flying_anchor;
flying_anchor->next_ = this;
@@ -234,10 +254,10 @@ void ThreadState::LinkInto(List list) {
}
-ThreadState* ThreadState::GetFree() {
+ThreadState* ThreadManager::GetFreeThreadState() {
ThreadState* gotten = free_anchor_->next_;
if (gotten == free_anchor_) {
- ThreadState* new_thread_state = new ThreadState();
+ ThreadState* new_thread_state = new ThreadState(this);
new_thread_state->AllocateSpace();
return new_thread_state;
}
@@ -246,13 +266,13 @@ ThreadState* ThreadState::GetFree() {
// Gets the first in the list of archived threads.
-ThreadState* ThreadState::FirstInUse() {
+ThreadState* ThreadManager::FirstThreadStateInUse() {
return in_use_anchor_->Next();
}
ThreadState* ThreadState::Next() {
- if (next_ == in_use_anchor_) return NULL;
+ if (next_ == thread_manager_->in_use_anchor_) return NULL;
return next_;
}
@@ -260,19 +280,29 @@ ThreadState* ThreadState::Next() {
// Thread ids must start with 1, because in TLS having thread id 0 can't
// be distinguished from not having a thread id at all (since NULL is
// defined as 0.)
-int ThreadManager::last_id_ = 0;
-Mutex* ThreadManager::mutex_ = OS::CreateMutex();
-ThreadHandle ThreadManager::mutex_owner_(ThreadHandle::INVALID);
-ThreadHandle ThreadManager::lazily_archived_thread_(ThreadHandle::INVALID);
-ThreadState* ThreadManager::lazily_archived_thread_state_ = NULL;
+ThreadManager::ThreadManager()
+ : mutex_(OS::CreateMutex()),
+ mutex_owner_(ThreadHandle::INVALID),
+ lazily_archived_thread_(ThreadHandle::INVALID),
+ lazily_archived_thread_state_(NULL),
+ free_anchor_(NULL),
+ in_use_anchor_(NULL) {
+ free_anchor_ = new ThreadState(this);
+ in_use_anchor_ = new ThreadState(this);
+}
+
+
+ThreadManager::~ThreadManager() {
+ // TODO(isolates): Destroy mutexes.
+}
void ThreadManager::ArchiveThread() {
ASSERT(!lazily_archived_thread_.IsValid());
ASSERT(!IsArchived());
- ThreadState* state = ThreadState::GetFree();
+ ThreadState* state = GetFreeThreadState();
state->Unlink();
- Thread::SetThreadLocal(thread_state_key, reinterpret_cast<void*>(state));
+ Isolate::CurrentPerIsolateThreadData()->set_thread_state(state);
lazily_archived_thread_.Initialize(ThreadHandle::SELF);
lazily_archived_thread_state_ = state;
ASSERT(state->id() == kInvalidId);
@@ -287,84 +317,69 @@ void ThreadManager::EagerlyArchiveThread() {
char* to = state->data();
// Ensure that data containing GC roots are archived first, and handle them
// in ThreadManager::Iterate(ObjectVisitor*).
- to = HandleScopeImplementer::ArchiveThread(to);
- to = Top::ArchiveThread(to);
+ to = isolate_->handle_scope_implementer()->ArchiveThread(to);
+ to = isolate_->ArchiveThread(to);
to = Relocatable::ArchiveState(to);
#ifdef ENABLE_DEBUGGER_SUPPORT
- to = Debug::ArchiveDebug(to);
+ to = isolate_->debug()->ArchiveDebug(to);
#endif
- to = StackGuard::ArchiveStackGuard(to);
- to = RegExpStack::ArchiveStack(to);
- to = Bootstrapper::ArchiveState(to);
+ to = isolate_->stack_guard()->ArchiveStackGuard(to);
+ to = isolate_->regexp_stack()->ArchiveStack(to);
+ to = isolate_->bootstrapper()->ArchiveState(to);
lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
lazily_archived_thread_state_ = NULL;
}
void ThreadManager::FreeThreadResources() {
- HandleScopeImplementer::FreeThreadResources();
- Top::FreeThreadResources();
+ isolate_->handle_scope_implementer()->FreeThreadResources();
+ isolate_->FreeThreadResources();
#ifdef ENABLE_DEBUGGER_SUPPORT
- Debug::FreeThreadResources();
+ isolate_->debug()->FreeThreadResources();
#endif
- StackGuard::FreeThreadResources();
- RegExpStack::FreeThreadResources();
- Bootstrapper::FreeThreadResources();
+ isolate_->stack_guard()->FreeThreadResources();
+ isolate_->regexp_stack()->FreeThreadResources();
+ isolate_->bootstrapper()->FreeThreadResources();
}
bool ThreadManager::IsArchived() {
- return Thread::HasThreadLocal(thread_state_key);
+ Isolate::PerIsolateThreadData* data = Isolate::CurrentPerIsolateThreadData();
+ return data != NULL && data->thread_state() != NULL;
}
void ThreadManager::Iterate(ObjectVisitor* v) {
// Expecting no threads during serialization/deserialization
- for (ThreadState* state = ThreadState::FirstInUse();
+ for (ThreadState* state = FirstThreadStateInUse();
state != NULL;
state = state->Next()) {
char* data = state->data();
data = HandleScopeImplementer::Iterate(v, data);
- data = Top::Iterate(v, data);
+ data = isolate_->Iterate(v, data);
data = Relocatable::Iterate(v, data);
}
}
void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
- for (ThreadState* state = ThreadState::FirstInUse();
+ for (ThreadState* state = FirstThreadStateInUse();
state != NULL;
state = state->Next()) {
char* data = state->data();
data += HandleScopeImplementer::ArchiveSpacePerThread();
- Top::IterateThread(v, data);
+ isolate_->IterateThread(v, data);
}
}
int ThreadManager::CurrentId() {
- return Thread::GetThreadLocalInt(thread_id_key);
-}
-
-
-void ThreadManager::AssignId() {
- if (!HasId()) {
- ASSERT(Locker::IsLocked());
- int thread_id = ++last_id_;
- ASSERT(thread_id > 0); // see the comment near last_id_ definition.
- Thread::SetThreadLocalInt(thread_id_key, thread_id);
- Top::set_thread_id(thread_id);
- }
-}
-
-
-bool ThreadManager::HasId() {
- return Thread::HasThreadLocal(thread_id_key);
+ return Thread::GetThreadLocalInt(Isolate::thread_id_key());
}
void ThreadManager::TerminateExecution(int thread_id) {
- for (ThreadState* state = ThreadState::FirstInUse();
+ for (ThreadState* state = FirstThreadStateInUse();
state != NULL;
state = state->Next()) {
if (thread_id == state->id()) {
@@ -374,13 +389,8 @@ void ThreadManager::TerminateExecution(int thread_id) {
}
-// This is the ContextSwitcher singleton. There is at most a single thread
-// running which delivers preemption events to V8 threads.
-ContextSwitcher* ContextSwitcher::singleton_ = NULL;
-
-
-ContextSwitcher::ContextSwitcher(int every_n_ms)
- : Thread("v8:CtxtSwitcher"),
+ContextSwitcher::ContextSwitcher(Isolate* isolate, int every_n_ms)
+ : Thread(isolate, "v8:CtxtSwitcher"),
keep_going_(true),
sleep_ms_(every_n_ms) {
}
@@ -389,15 +399,16 @@ ContextSwitcher::ContextSwitcher(int every_n_ms)
// Set the scheduling interval of V8 threads. This function starts the
// ContextSwitcher thread if needed.
void ContextSwitcher::StartPreemption(int every_n_ms) {
+ Isolate* isolate = Isolate::Current();
ASSERT(Locker::IsLocked());
- if (singleton_ == NULL) {
+ if (isolate->context_switcher() == NULL) {
// If the ContextSwitcher thread is not running at the moment start it now.
- singleton_ = new ContextSwitcher(every_n_ms);
- singleton_->Start();
+ isolate->set_context_switcher(new ContextSwitcher(isolate, every_n_ms));
+ isolate->context_switcher()->Start();
} else {
// ContextSwitcher thread is already running, so we just change the
// scheduling interval.
- singleton_->sleep_ms_ = every_n_ms;
+ isolate->context_switcher()->sleep_ms_ = every_n_ms;
}
}
@@ -405,15 +416,17 @@ void ContextSwitcher::StartPreemption(int every_n_ms) {
// Disable preemption of V8 threads. If multiple threads want to use V8 they
// must cooperatively schedule amongst them from this point on.
void ContextSwitcher::StopPreemption() {
+ Isolate* isolate = Isolate::Current();
ASSERT(Locker::IsLocked());
- if (singleton_ != NULL) {
+ if (isolate->context_switcher() != NULL) {
// The ContextSwitcher thread is running. We need to stop it and release
// its resources.
- singleton_->keep_going_ = false;
- singleton_->Join(); // Wait for the ContextSwitcher thread to exit.
+ isolate->context_switcher()->keep_going_ = false;
+ // Wait for the ContextSwitcher thread to exit.
+ isolate->context_switcher()->Join();
// Thread has exited, now we can delete it.
- delete(singleton_);
- singleton_ = NULL;
+ delete(isolate->context_switcher());
+ isolate->set_context_switcher(NULL);
}
}
@@ -423,7 +436,7 @@ void ContextSwitcher::StopPreemption() {
void ContextSwitcher::Run() {
while (keep_going_) {
OS::Sleep(sleep_ms_);
- StackGuard::Preempt();
+ isolate()->stack_guard()->Preempt();
}
}
diff --git a/src/v8threads.h b/src/v8threads.h
index da56d052..f1992ad7 100644
--- a/src/v8threads.h
+++ b/src/v8threads.h
@@ -34,8 +34,6 @@ namespace internal {
class ThreadState {
public:
- // Iterate over in-use states.
- static ThreadState* FirstInUse();
// Returns NULL after the last one.
ThreadState* Next();
@@ -44,8 +42,6 @@ class ThreadState {
void LinkInto(List list);
void Unlink();
- static ThreadState* GetFree();
-
// Id of thread.
void set_id(int id) { id_ = id; }
int id() { return id_; }
@@ -59,7 +55,7 @@ class ThreadState {
// Get data area for archiving a thread.
char* data() { return data_; }
private:
- ThreadState();
+ explicit ThreadState(ThreadManager* thread_manager);
void AllocateSpace();
@@ -69,13 +65,9 @@ class ThreadState {
ThreadState* next_;
ThreadState* previous_;
- // In the following two lists there is always at least one object on the list.
- // The first object is a flying anchor that is only there to simplify linking
- // and unlinking.
- // Head of linked list of free states.
- static ThreadState* free_anchor_;
- // Head of linked list of states in use.
- static ThreadState* in_use_anchor_;
+ ThreadManager* thread_manager_;
+
+ friend class ThreadManager;
};
@@ -93,35 +85,52 @@ class ThreadVisitor {
};
-class ThreadManager : public AllStatic {
+class ThreadManager {
public:
- static void Lock();
- static void Unlock();
+ void Lock();
+ void Unlock();
- static void ArchiveThread();
- static bool RestoreThread();
- static void FreeThreadResources();
- static bool IsArchived();
+ void ArchiveThread();
+ bool RestoreThread();
+ void FreeThreadResources();
+ bool IsArchived();
- static void Iterate(ObjectVisitor* v);
- static void IterateArchivedThreads(ThreadVisitor* v);
- static bool IsLockedByCurrentThread() { return mutex_owner_.IsSelf(); }
+ void Iterate(ObjectVisitor* v);
+ void IterateArchivedThreads(ThreadVisitor* v);
+ bool IsLockedByCurrentThread() { return mutex_owner_.IsSelf(); }
- static int CurrentId();
- static void AssignId();
- static bool HasId();
+ int CurrentId();
- static void TerminateExecution(int thread_id);
+ void TerminateExecution(int thread_id);
+
+ // Iterate over in-use states.
+ ThreadState* FirstThreadStateInUse();
+ ThreadState* GetFreeThreadState();
static const int kInvalidId = -1;
private:
- static void EagerlyArchiveThread();
+ ThreadManager();
+ ~ThreadManager();
- static int last_id_; // V8 threads are identified through an integer.
- static Mutex* mutex_;
- static ThreadHandle mutex_owner_;
- static ThreadHandle lazily_archived_thread_;
- static ThreadState* lazily_archived_thread_state_;
+ void EagerlyArchiveThread();
+
+ Mutex* mutex_;
+ ThreadHandle mutex_owner_;
+ ThreadHandle lazily_archived_thread_;
+ ThreadState* lazily_archived_thread_state_;
+
+ // In the following two lists there is always at least one object on the list.
+ // The first object is a flying anchor that is only there to simplify linking
+ // and unlinking.
+ // Head of linked list of free states.
+ ThreadState* free_anchor_;
+ // Head of linked list of states in use.
+ ThreadState* in_use_anchor_;
+
+ Isolate* isolate_;
+
+ friend class Isolate;
+ friend class ThreadState;
};
@@ -142,14 +151,12 @@ class ContextSwitcher: public Thread {
static void PreemptionReceived();
private:
- explicit ContextSwitcher(int every_n_ms);
+ explicit ContextSwitcher(Isolate* isolate, int every_n_ms);
void Run();
bool keep_going_;
int sleep_ms_;
-
- static ContextSwitcher* singleton_;
};
} } // namespace v8::internal
diff --git a/src/variables.h b/src/variables.h
index 5d27a02d..67e1a185 100644
--- a/src/variables.h
+++ b/src/variables.h
@@ -165,7 +165,7 @@ class Variable: public ZoneObject {
// True if the variable is named eval and not known to be shadowed.
bool is_possibly_eval() const {
- return IsVariable(Factory::eval_symbol()) &&
+ return IsVariable(FACTORY->eval_symbol()) &&
(mode_ == DYNAMIC || mode_ == DYNAMIC_GLOBAL);
}
diff --git a/src/version.cc b/src/version.cc
index ac4ab4a4..6104dac9 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,15 +34,36 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 2
-#define BUILD_NUMBER 0
-#define PATCH_LEVEL 1
-#define CANDIDATE_VERSION false
+#define BUILD_NUMBER 6
+#define PATCH_LEVEL 0
+// Use 1 for candidates and 0 otherwise.
+// (Boolean macro values are not supported by all preprocessors.)
+#define IS_CANDIDATE_VERSION 0
// Define SONAME to have the SCons build the put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
// number. This define is mainly used by the SCons build script.
#define SONAME ""
+#if IS_CANDIDATE_VERSION
+#define CANDIDATE_STRING " (candidate)"
+#else
+#define CANDIDATE_STRING ""
+#endif
+
+#define SX(x) #x
+#define S(x) SX(x)
+
+#if PATCH_LEVEL > 0
+#define VERSION_STRING \
+ S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) "." \
+ S(PATCH_LEVEL) CANDIDATE_STRING
+#else
+#define VERSION_STRING \
+ S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) \
+ CANDIDATE_STRING
+#endif
+
namespace v8 {
namespace internal {
@@ -50,9 +71,9 @@ int Version::major_ = MAJOR_VERSION;
int Version::minor_ = MINOR_VERSION;
int Version::build_ = BUILD_NUMBER;
int Version::patch_ = PATCH_LEVEL;
-bool Version::candidate_ = CANDIDATE_VERSION;
+bool Version::candidate_ = (IS_CANDIDATE_VERSION != 0);
const char* Version::soname_ = SONAME;
-
+const char* Version::version_string_ = VERSION_STRING;
// Calculate the V8 version string.
void Version::GetString(Vector<char> str) {
diff --git a/src/version.h b/src/version.h
index c322a2fc..4b3e7e2b 100644
--- a/src/version.h
+++ b/src/version.h
@@ -46,13 +46,17 @@ class Version {
// Calculate the SONAME for the V8 shared library.
static void GetSONAME(Vector<char> str);
+ static const char* GetVersion() { return version_string_; }
+
private:
+ // NOTE: can't make these really const because of test-version.cc.
static int major_;
static int minor_;
static int build_;
static int patch_;
static bool candidate_;
static const char* soname_;
+ static const char* version_string_;
// In test-version.cc.
friend void SetVersion(int major, int minor, int build, int patch,
diff --git a/src/virtual-frame-light-inl.h b/src/virtual-frame-light-inl.h
index 19520a63..681f93fb 100644
--- a/src/virtual-frame-light-inl.h
+++ b/src/virtual-frame-light-inl.h
@@ -83,8 +83,9 @@ void VirtualFrame::PrepareForReturn() {
VirtualFrame::RegisterAllocationScope::RegisterAllocationScope(
CodeGenerator* cgen)
: cgen_(cgen),
- old_is_spilled_(SpilledScope::is_spilled_) {
- SpilledScope::is_spilled_ = false;
+ old_is_spilled_(
+ Isolate::Current()->is_virtual_frame_in_spilled_scope()) {
+ Isolate::Current()->set_is_virtual_frame_in_spilled_scope(false);
if (old_is_spilled_) {
VirtualFrame* frame = cgen->frame();
if (frame != NULL) {
@@ -95,7 +96,7 @@ VirtualFrame::RegisterAllocationScope::RegisterAllocationScope(
VirtualFrame::RegisterAllocationScope::~RegisterAllocationScope() {
- SpilledScope::is_spilled_ = old_is_spilled_;
+ Isolate::Current()->set_is_virtual_frame_in_spilled_scope(old_is_spilled_);
if (old_is_spilled_) {
VirtualFrame* frame = cgen_->frame();
if (frame != NULL) {
@@ -106,7 +107,7 @@ VirtualFrame::RegisterAllocationScope::~RegisterAllocationScope() {
CodeGenerator* VirtualFrame::cgen() const {
- return CodeGeneratorScope::Current();
+ return CodeGeneratorScope::Current(Isolate::Current());
}
diff --git a/src/vm-state-inl.h b/src/vm-state-inl.h
index da912b74..1f363de6 100644
--- a/src/vm-state-inl.h
+++ b/src/vm-state-inl.h
@@ -58,25 +58,27 @@ inline const char* StateToString(StateTag state) {
}
}
-VMState::VMState(StateTag tag) : previous_tag_(Top::current_vm_state()) {
+
+VMState::VMState(Isolate* isolate, StateTag tag)
+ : isolate_(isolate), previous_tag_(isolate->current_vm_state()) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (FLAG_log_state_changes) {
- LOG(UncheckedStringEvent("Entering", StateToString(tag)));
- LOG(UncheckedStringEvent("From", StateToString(previous_tag_)));
+ LOG(isolate, UncheckedStringEvent("Entering", StateToString(tag)));
+ LOG(isolate, UncheckedStringEvent("From", StateToString(previous_tag_)));
}
#endif
- Top::SetCurrentVMState(tag);
+ isolate_->SetCurrentVMState(tag);
#ifdef ENABLE_HEAP_PROTECTION
if (FLAG_protect_heap) {
if (tag == EXTERNAL) {
// We are leaving V8.
ASSERT(previous_tag_ != EXTERNAL);
- Heap::Protect();
+ isolate_->heap()->Protect();
} else if (previous_tag_ = EXTERNAL) {
// We are entering V8.
- Heap::Unprotect();
+ isolate_->heap()->Unprotect();
}
}
#endif
@@ -86,27 +88,29 @@ VMState::VMState(StateTag tag) : previous_tag_(Top::current_vm_state()) {
VMState::~VMState() {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (FLAG_log_state_changes) {
- LOG(UncheckedStringEvent("Leaving",
- StateToString(Top::current_vm_state())));
- LOG(UncheckedStringEvent("To", StateToString(previous_tag_)));
+ LOG(isolate_,
+ UncheckedStringEvent("Leaving",
+ StateToString(isolate_->current_vm_state())));
+ LOG(isolate_,
+ UncheckedStringEvent("To", StateToString(previous_tag_)));
}
#endif // ENABLE_LOGGING_AND_PROFILING
#ifdef ENABLE_HEAP_PROTECTION
- StateTag tag = Top::current_vm_state();
+ StateTag tag = isolate_->current_vm_state();
#endif
- Top::SetCurrentVMState(previous_tag_);
+ isolate_->SetCurrentVMState(previous_tag_);
#ifdef ENABLE_HEAP_PROTECTION
if (FLAG_protect_heap) {
if (tag == EXTERNAL) {
// We are reentering V8.
ASSERT(previous_tag_ != EXTERNAL);
- Heap::Unprotect();
+ isolate_->heap()->Unprotect();
} else if (previous_tag_ == EXTERNAL) {
// We are leaving V8.
- Heap::Protect();
+ isolate_->heap()->Protect();
}
}
#endif // ENABLE_HEAP_PROTECTION
@@ -117,13 +121,13 @@ VMState::~VMState() {
#ifdef ENABLE_LOGGING_AND_PROFILING
-ExternalCallbackScope::ExternalCallbackScope(Address callback)
- : previous_callback_(Top::external_callback()) {
- Top::set_external_callback(callback);
+ExternalCallbackScope::ExternalCallbackScope(Isolate* isolate, Address callback)
+ : isolate_(isolate), previous_callback_(isolate->external_callback()) {
+ isolate_->set_external_callback(callback);
}
ExternalCallbackScope::~ExternalCallbackScope() {
- Top::set_external_callback(previous_callback_);
+ isolate_->set_external_callback(previous_callback_);
}
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/src/vm-state.h b/src/vm-state.h
index df7fb30a..11fc6d67 100644
--- a/src/vm-state.h
+++ b/src/vm-state.h
@@ -28,7 +28,7 @@
#ifndef V8_VM_STATE_H_
#define V8_VM_STATE_H_
-#include "top.h"
+#include "isolate.h"
namespace v8 {
namespace internal {
@@ -36,15 +36,16 @@ namespace internal {
class VMState BASE_EMBEDDED {
#ifdef ENABLE_VMSTATE_TRACKING
public:
- inline explicit VMState(StateTag tag);
+ inline VMState(Isolate* isolate, StateTag tag);
inline ~VMState();
private:
+ Isolate* isolate_;
StateTag previous_tag_;
#else
public:
- explicit VMState(StateTag state) {}
+ VMState(Isolate* isolate, StateTag state) {}
#endif
};
@@ -52,13 +53,14 @@ class VMState BASE_EMBEDDED {
class ExternalCallbackScope BASE_EMBEDDED {
#ifdef ENABLE_LOGGING_AND_PROFILING
public:
- inline explicit ExternalCallbackScope(Address callback);
+ inline ExternalCallbackScope(Isolate* isolate, Address callback);
inline ~ExternalCallbackScope();
private:
+ Isolate* isolate_;
Address previous_callback_;
#else
public:
- explicit ExternalCallbackScope(Address callback) {}
+ ExternalCallbackScope(Isolate* isolate, Address callback) {}
#endif
};
diff --git a/src/win32-headers.h b/src/win32-headers.h
index b51a38a1..fca5c137 100644
--- a/src/win32-headers.h
+++ b/src/win32-headers.h
@@ -66,6 +66,7 @@
#endif // __MINGW32__
#ifndef __MINGW32__
#include <dbghelp.h> // For SymLoadModule64 and al.
+#include <errno.h> // For STRUNCATE
#endif // __MINGW32__
#include <limits.h> // For INT_MAX and al.
#include <tlhelp32.h> // For Module32First and al.
diff --git a/src/x64/assembler-x64-inl.h b/src/x64/assembler-x64-inl.h
index b082624f..439236a9 100644
--- a/src/x64/assembler-x64-inl.h
+++ b/src/x64/assembler-x64-inl.h
@@ -30,7 +30,7 @@
#include "cpu.h"
#include "debug.h"
-#include "memory.h"
+#include "v8memory.h"
namespace v8 {
namespace internal {
@@ -372,11 +372,12 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
visitor->VisitExternalReference(target_reference_address());
CPU::FlushICache(pc_, sizeof(Address));
#ifdef ENABLE_DEBUGGER_SUPPORT
- } else if (Debug::has_break_points() &&
- ((RelocInfo::IsJSReturn(mode) &&
+ // TODO(isolates): Get a cached isolate below.
+ } else if (((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
- IsPatchedDebugBreakSlotSequence()))) {
+ IsPatchedDebugBreakSlotSequence())) &&
+ Isolate::Current()->debug()->has_break_points()) {
visitor->VisitDebugTarget(this);
#endif
} else if (mode == RelocInfo::RUNTIME_ENTRY) {
@@ -386,10 +387,10 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
template<typename StaticVisitor>
-void RelocInfo::Visit() {
+void RelocInfo::Visit(Heap* heap) {
RelocInfo::Mode mode = rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
- StaticVisitor::VisitPointer(target_object_address());
+ StaticVisitor::VisitPointer(heap, target_object_address());
CPU::FlushICache(pc_, sizeof(Address));
} else if (RelocInfo::IsCodeTarget(mode)) {
StaticVisitor::VisitCodeTarget(this);
@@ -399,7 +400,7 @@ void RelocInfo::Visit() {
StaticVisitor::VisitExternalReference(target_reference_address());
CPU::FlushICache(pc_, sizeof(Address));
#ifdef ENABLE_DEBUGGER_SUPPORT
- } else if (Debug::has_break_points() &&
+ } else if (heap->isolate()->debug()->has_break_points() &&
((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 41111a77..0744b8a3 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -38,14 +38,15 @@ namespace internal {
// -----------------------------------------------------------------------------
// Implementation of CpuFeatures
-// The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
-// fpu, tsc, cx8, cmov, mmx, sse, sse2, fxsr, syscall
-uint64_t CpuFeatures::supported_ = kDefaultCpuFeatures;
-uint64_t CpuFeatures::enabled_ = 0;
-uint64_t CpuFeatures::found_by_runtime_probing_ = 0;
+CpuFeatures::CpuFeatures()
+ : supported_(kDefaultCpuFeatures),
+ enabled_(0),
+ found_by_runtime_probing_(0) {
+}
+
void CpuFeatures::Probe(bool portable) {
- ASSERT(Heap::HasBeenSetup());
+ ASSERT(HEAP->HasBeenSetup());
supported_ = kDefaultCpuFeatures;
if (portable && Serializer::enabled()) {
supported_ |= OS::CpuFeaturesImpliedByPlatform();
@@ -118,13 +119,16 @@ void CpuFeatures::Probe(bool portable) {
CodeDesc desc;
assm.GetCode(&desc);
- MaybeObject* maybe_code = Heap::CreateCode(desc,
- Code::ComputeFlags(Code::STUB),
- Handle<Object>());
+ Isolate* isolate = Isolate::Current();
+ MaybeObject* maybe_code =
+ isolate->heap()->CreateCode(desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>());
Object* code;
if (!maybe_code->ToObject(&code)) return;
if (!code->IsCode()) return;
- PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
+ PROFILE(isolate,
+ CodeCreateEvent(Logger::BUILTIN_TAG,
Code::cast(code), "CpuFeatures::Probe"));
typedef uint64_t (*F0)();
F0 probe = FUNCTION_CAST<F0>(Code::cast(code)->entry());
@@ -191,12 +195,12 @@ void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
// Register constants.
const int Register::kRegisterCodeByAllocationIndex[kNumAllocatableRegisters] = {
- // rax, rbx, rdx, rcx, rdi, r8, r9, r11, r14, r12
- 0, 3, 2, 1, 7, 8, 9, 11, 14, 12
+ // rax, rbx, rdx, rcx, rdi, r8, r9, r11, r14, r15
+ 0, 3, 2, 1, 7, 8, 9, 11, 14, 15
};
const int Register::kAllocationIndexByRegisterCode[kNumRegisters] = {
- 0, 3, 2, 1, -1, -1, -1, 4, 5, 6, -1, 7, 9, -1, 8, -1
+ 0, 3, 2, 1, -1, -1, -1, 4, 5, 6, -1, 7, -1, -1, 8, 9
};
@@ -335,18 +339,19 @@ bool Operand::AddressUsesRegister(Register reg) const {
static void InitCoverageLog();
#endif
-byte* Assembler::spare_buffer_ = NULL;
-
Assembler::Assembler(void* buffer, int buffer_size)
- : code_targets_(100), positions_recorder_(this) {
+ : AssemblerBase(Isolate::Current()),
+ code_targets_(100),
+ positions_recorder_(this),
+ emit_debug_code_(FLAG_debug_code) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
buffer_size = kMinimalBufferSize;
- if (spare_buffer_ != NULL) {
- buffer = spare_buffer_;
- spare_buffer_ = NULL;
+ if (isolate()->assembler_spare_buffer() != NULL) {
+ buffer = isolate()->assembler_spare_buffer();
+ isolate()->set_assembler_spare_buffer(NULL);
}
}
if (buffer == NULL) {
@@ -388,8 +393,9 @@ Assembler::Assembler(void* buffer, int buffer_size)
Assembler::~Assembler() {
if (own_buffer_) {
- if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
- spare_buffer_ = buffer_;
+ if (isolate()->assembler_spare_buffer() == NULL &&
+ buffer_size_ == kMinimalBufferSize) {
+ isolate()->set_assembler_spare_buffer(buffer_);
} else {
DeleteArray(buffer_);
}
@@ -409,8 +415,6 @@ void Assembler::GetCode(CodeDesc* desc) {
desc->reloc_size =
static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer.pos());
desc->origin = this;
-
- Counters::reloc_info_size.Increment(desc->reloc_size);
}
@@ -487,7 +491,7 @@ void Assembler::GrowBuffer() {
// Some internal data structures overflow for very large buffers,
// they must ensure that kMaximalBufferSize is not too large.
if ((desc.buffer_size > kMaximalBufferSize) ||
- (desc.buffer_size > Heap::MaxOldGenerationSize())) {
+ (desc.buffer_size > HEAP->MaxOldGenerationSize())) {
V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
}
@@ -512,8 +516,9 @@ void Assembler::GrowBuffer() {
reloc_info_writer.pos(), desc.reloc_size);
// Switch buffers.
- if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
- spare_buffer_ = buffer_;
+ if (isolate()->assembler_spare_buffer() == NULL &&
+ buffer_size_ == kMinimalBufferSize) {
+ isolate()->set_assembler_spare_buffer(buffer_);
} else {
DeleteArray(buffer_);
}
@@ -939,6 +944,12 @@ void Assembler::clc() {
emit(0xF8);
}
+void Assembler::cld() {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ emit(0xFC);
+}
+
void Assembler::cdq() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
@@ -1026,7 +1037,7 @@ void Assembler::cmpb_al(Immediate imm8) {
void Assembler::cpuid() {
- ASSERT(CpuFeatures::IsEnabled(CPUID));
+ ASSERT(isolate()->cpu_features()->IsEnabled(CPUID));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x0F);
@@ -1673,7 +1684,7 @@ void Assembler::movq(Register dst, Handle<Object> value, RelocInfo::Mode mode) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
ASSERT(value->IsHeapObject());
- ASSERT(!Heap::InNewSpace(*value));
+ ASSERT(!HEAP->InNewSpace(*value));
emit_rex_64(dst);
emit(0xB8 | dst.low_bits());
emitq(reinterpret_cast<uintptr_t>(value.location()), mode);
@@ -2377,7 +2388,7 @@ void Assembler::fistp_s(const Operand& adr) {
void Assembler::fisttp_s(const Operand& adr) {
- ASSERT(CpuFeatures::IsEnabled(SSE3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE3));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit_optional_rex_32(adr);
@@ -2387,7 +2398,7 @@ void Assembler::fisttp_s(const Operand& adr) {
void Assembler::fisttp_d(const Operand& adr) {
- ASSERT(CpuFeatures::IsEnabled(SSE3));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE3));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit_optional_rex_32(adr);
@@ -2705,7 +2716,7 @@ void Assembler::movq(Register dst, XMMRegister src) {
void Assembler::movdqa(const Operand& dst, XMMRegister src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x66);
@@ -2717,7 +2728,7 @@ void Assembler::movdqa(const Operand& dst, XMMRegister src) {
void Assembler::movdqa(XMMRegister dst, const Operand& src) {
- ASSERT(CpuFeatures::IsEnabled(SSE2));
+ ASSERT(isolate()->cpu_features()->IsEnabled(SSE2));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x66);
@@ -3114,7 +3125,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Serializer::TooLateToEnableNow();
}
#endif
- if (!Serializer::enabled() && !FLAG_debug_code) {
+ if (!Serializer::enabled() && !emit_debug_code()) {
return;
}
}
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index f6cd5709..52aca637 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -93,8 +93,8 @@ struct Register {
// rbp - frame pointer
// rsi - context register
// r10 - fixed scratch register
+ // r12 - smi constant register
// r13 - root register
- // r15 - smi constant register
static const int kNumRegisters = 16;
static const int kNumAllocatableRegisters = 10;
@@ -120,7 +120,7 @@ struct Register {
"r9",
"r11",
"r14",
- "r12"
+ "r15"
};
return names[index];
}
@@ -395,6 +395,13 @@ class Operand BASE_EMBEDDED {
// Does not check the "reg" part of the Operand.
bool AddressUsesRegister(Register reg) const;
+ // Queries related to the size of the generated instruction.
+ // Whether the generated instruction will have a REX prefix.
+ bool requires_rex() const { return rex_ != 0; }
+ // Size of the ModR/M, SIB and displacement parts of the generated
+ // instruction.
+ int operand_size() const { return len_; }
+
private:
byte rex_;
byte buf_[6];
@@ -427,13 +434,14 @@ class Operand BASE_EMBEDDED {
// } else {
// // Generate standard x87 or SSE2 floating point code.
// }
-class CpuFeatures : public AllStatic {
+class CpuFeatures {
public:
// Detect features of the target CPU. Set safe defaults if the serializer
// is enabled (snapshots must be portable).
- static void Probe(bool portable);
+ void Probe(bool portable);
+
// Check whether a feature is supported by the target CPU.
- static bool IsSupported(CpuFeature f) {
+ bool IsSupported(CpuFeature f) const {
if (f == SSE2 && !FLAG_enable_sse2) return false;
if (f == SSE3 && !FLAG_enable_sse3) return false;
if (f == CMOV && !FLAG_enable_cmov) return false;
@@ -442,39 +450,56 @@ class CpuFeatures : public AllStatic {
return (supported_ & (V8_UINT64_C(1) << f)) != 0;
}
// Check whether a feature is currently enabled.
- static bool IsEnabled(CpuFeature f) {
+ bool IsEnabled(CpuFeature f) const {
return (enabled_ & (V8_UINT64_C(1) << f)) != 0;
}
// Enable a specified feature within a scope.
class Scope BASE_EMBEDDED {
#ifdef DEBUG
public:
- explicit Scope(CpuFeature f) {
+ explicit Scope(CpuFeature f)
+ : cpu_features_(Isolate::Current()->cpu_features()),
+ isolate_(Isolate::Current()) {
uint64_t mask = (V8_UINT64_C(1) << f);
- ASSERT(CpuFeatures::IsSupported(f));
- ASSERT(!Serializer::enabled() || (found_by_runtime_probing_ & mask) == 0);
- old_enabled_ = CpuFeatures::enabled_;
- CpuFeatures::enabled_ |= mask;
+ ASSERT(cpu_features_->IsSupported(f));
+ ASSERT(!Serializer::enabled() ||
+ (cpu_features_->found_by_runtime_probing_ & mask) == 0);
+ old_enabled_ = cpu_features_->enabled_;
+ cpu_features_->enabled_ |= mask;
+ }
+ ~Scope() {
+ ASSERT_EQ(Isolate::Current(), isolate_);
+ cpu_features_->enabled_ = old_enabled_;
}
- ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
private:
uint64_t old_enabled_;
+ CpuFeatures* cpu_features_;
+ Isolate* isolate_;
#else
public:
explicit Scope(CpuFeature f) {}
#endif
};
private:
+ CpuFeatures();
+
// Safe defaults include SSE2 and CMOV for X64. It is always available, if
// anyone checks, but they shouldn't need to check.
+ // The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
+ // fpu, tsc, cx8, cmov, mmx, sse, sse2, fxsr, syscall
static const uint64_t kDefaultCpuFeatures = (1 << SSE2 | 1 << CMOV);
- static uint64_t supported_;
- static uint64_t enabled_;
- static uint64_t found_by_runtime_probing_;
+
+ uint64_t supported_;
+ uint64_t enabled_;
+ uint64_t found_by_runtime_probing_;
+
+ friend class Isolate;
+
+ DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
};
-class Assembler : public Malloced {
+class Assembler : public AssemblerBase {
private:
// We check before assembling an instruction that there is sufficient
// space to write an instruction and its relocation information.
@@ -504,6 +529,9 @@ class Assembler : public Malloced {
Assembler(void* buffer, int buffer_size);
~Assembler();
+ // Overrides the default provided by FLAG_debug_code.
+ void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
+
// GetCode emits any pending (non-emitted) code and fills the descriptor
// desc. GetCode() is idempotent; it returns the same result if no other
// Assembler functions are invoked in between GetCode() calls.
@@ -649,7 +677,7 @@ class Assembler : public Malloced {
// Move sign extended immediate to memory location.
void movq(const Operand& dst, Immediate value);
- // New x64 instructions to load a 64-bit immediate into a register.
+ // Instructions to load a 64-bit immediate into a register.
// All 64-bit immediates must have a relocation mode.
void movq(Register dst, void* ptr, RelocInfo::Mode rmode);
void movq(Register dst, int64_t value, RelocInfo::Mode rmode);
@@ -674,7 +702,7 @@ class Assembler : public Malloced {
void repmovsl();
void repmovsq();
- // New x64 instruction to load from an immediate 64-bit pointer into RAX.
+ // Instruction to load from an immediate 64-bit pointer into RAX.
void load_rax(void* ptr, RelocInfo::Mode rmode);
void load_rax(ExternalReference ext);
@@ -1109,6 +1137,7 @@ class Assembler : public Malloced {
// Miscellaneous
void clc();
+ void cld();
void cpuid();
void hlt();
void int3();
@@ -1343,6 +1372,9 @@ class Assembler : public Malloced {
static const int kMaximalBufferSize = 512*MB;
static const int kMinimalBufferSize = 4*KB;
+ protected:
+ bool emit_debug_code() const { return emit_debug_code_; }
+
private:
byte* addr_at(int pos) { return buffer_ + pos; }
byte byte_at(int pos) { return buffer_[pos]; }
@@ -1536,8 +1568,6 @@ class Assembler : public Malloced {
int buffer_size_;
// True if the assembler owns the buffer, false if buffer is external.
bool own_buffer_;
- // A previously allocated buffer of kMinimalBufferSize bytes, or NULL.
- static byte* spare_buffer_;
// code generation
byte* pc_; // the program counter; moves forward
@@ -1548,6 +1578,9 @@ class Assembler : public Malloced {
byte* last_pc_;
PositionsRecorder positions_recorder_;
+
+ bool emit_debug_code_;
+
friend class PositionsRecorder;
};
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index b545876e..21d3e54a 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -69,7 +69,7 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm,
// JumpToExternalReference expects rax to contain the number of arguments
// including the receiver and the extra arguments.
__ addq(rax, Immediate(num_extra_args + 1));
- __ JumpToExternalReference(ExternalReference(id), 1);
+ __ JumpToExternalReference(ExternalReference(id, masm->isolate()), 1);
}
@@ -98,7 +98,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// Set expected number of arguments to zero (not changing rax).
__ movq(rbx, Immediate(0));
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
- __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
}
@@ -127,7 +127,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
#ifdef ENABLE_DEBUGGER_SUPPORT
ExternalReference debug_step_in_fp =
- ExternalReference::debug_step_in_fp_address();
+ ExternalReference::debug_step_in_fp_address(masm->isolate());
__ movq(kScratchRegister, debug_step_in_fp);
__ cmpq(Operand(kScratchRegister, 0), Immediate(0));
__ j(not_equal, &rt_call);
@@ -339,8 +339,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Call the function.
if (is_api_function) {
__ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
- Handle<Code> code = Handle<Code>(
- Builtins::builtin(Builtins::HandleApiCallConstruct));
+ Handle<Code> code =
+ masm->isolate()->builtins()->HandleApiCallConstruct();
ParameterCount expected(0);
__ InvokeCode(code, expected, expected,
RelocInfo::CODE_TARGET, CALL_FUNCTION);
@@ -379,7 +379,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2);
__ lea(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize));
__ push(rcx);
- __ IncrementCounter(&Counters::constructed_objects, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->constructed_objects(), 1);
__ ret(0);
}
@@ -492,7 +493,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// Invoke the code.
if (is_construct) {
// Expects rdi to hold function pointer.
- __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
+ __ Call(masm->isolate()->builtins()->JSConstructCall(),
RelocInfo::CODE_TARGET);
} else {
ParameterCount actual(rax);
@@ -630,7 +631,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ testq(rax, rax);
__ j(not_zero, &done);
__ pop(rbx);
- __ Push(Factory::undefined_value());
+ __ Push(FACTORY->undefined_value());
__ push(rbx);
__ incq(rax);
__ bind(&done);
@@ -733,7 +734,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ j(not_zero, &function);
__ Set(rbx, 0);
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
- __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
}
@@ -748,7 +749,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
__ cmpq(rax, rbx);
__ j(not_equal,
- Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
ParameterCount expected(0);
@@ -863,7 +864,8 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ movq(rdx, Operand(rbp, kArgumentsOffset)); // load arguments
// Use inline caching to speed up access to arguments.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic =
+ masm->isolate()->builtins()->KeyedLoadIC_Initialize();
__ Call(ic, RelocInfo::CODE_TARGET);
// It is important that we do not have a test instruction after the
// call. A test instruction after the call is used to indicate that
@@ -935,7 +937,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// scratch2: start of next object
__ movq(FieldOperand(result, JSObject::kMapOffset), scratch1);
__ Move(FieldOperand(result, JSArray::kPropertiesOffset),
- Factory::empty_fixed_array());
+ FACTORY->empty_fixed_array());
// Field JSArray::kElementsOffset is initialized later.
__ Move(FieldOperand(result, JSArray::kLengthOffset), Smi::FromInt(0));
@@ -943,7 +945,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// fixed array.
if (initial_capacity == 0) {
__ Move(FieldOperand(result, JSArray::kElementsOffset),
- Factory::empty_fixed_array());
+ FACTORY->empty_fixed_array());
return;
}
@@ -960,7 +962,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// scratch1: elements array
// scratch2: start of next object
__ Move(FieldOperand(scratch1, HeapObject::kMapOffset),
- Factory::fixed_array_map());
+ FACTORY->fixed_array_map());
__ Move(FieldOperand(scratch1, FixedArray::kLengthOffset),
Smi::FromInt(initial_capacity));
@@ -968,7 +970,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
static const int kLoopUnfoldLimit = 4;
ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
- __ Move(scratch3, Factory::the_hole_value());
+ __ Move(scratch3, FACTORY->the_hole_value());
if (initial_capacity <= kLoopUnfoldLimit) {
// Use a scratch register here to have only one reloc info when unfolding
// the loop.
@@ -1052,7 +1054,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// array_size: size of array (smi)
__ bind(&allocated);
__ movq(FieldOperand(result, JSObject::kMapOffset), elements_array);
- __ Move(elements_array, Factory::empty_fixed_array());
+ __ Move(elements_array, FACTORY->empty_fixed_array());
__ movq(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
// Field JSArray::kElementsOffset is initialized later.
__ movq(FieldOperand(result, JSArray::kLengthOffset), array_size);
@@ -1071,7 +1073,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// elements_array_end: start of next object
// array_size: size of array (smi)
__ Move(FieldOperand(elements_array, JSObject::kMapOffset),
- Factory::fixed_array_map());
+ FACTORY->fixed_array_map());
Label not_empty_2, fill_array;
__ SmiTest(array_size);
__ j(not_zero, &not_empty_2);
@@ -1092,7 +1094,7 @@ static void AllocateJSArray(MacroAssembler* masm,
__ bind(&fill_array);
if (fill_with_hole) {
Label loop, entry;
- __ Move(scratch, Factory::the_hole_value());
+ __ Move(scratch, FACTORY->the_hole_value());
__ lea(elements_array, Operand(elements_array,
FixedArray::kHeaderSize - kHeapObjectTag));
__ jmp(&entry);
@@ -1137,7 +1139,8 @@ static void ArrayNativeCode(MacroAssembler* masm,
r8,
kPreallocatedArrayElements,
call_generic_code);
- __ IncrementCounter(&Counters::array_function_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->array_function_native(), 1);
__ movq(rax, rbx);
__ ret(kPointerSize);
@@ -1168,7 +1171,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
r9,
true,
call_generic_code);
- __ IncrementCounter(&Counters::array_function_native, 1);
+ __ IncrementCounter(counters->array_function_native(), 1);
__ movq(rax, rbx);
__ ret(2 * kPointerSize);
@@ -1190,7 +1193,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
r9,
false,
call_generic_code);
- __ IncrementCounter(&Counters::array_function_native, 1);
+ __ IncrementCounter(counters->array_function_native(), 1);
// rax: argc
// rbx: JSArray
@@ -1264,8 +1267,8 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
// Jump to the generic array code in case the specialized code cannot handle
// the construction.
__ bind(&generic_array_code);
- Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
- Handle<Code> array_code(code);
+ Handle<Code> array_code =
+ masm->isolate()->builtins()->ArrayCodeGeneric();
__ Jump(array_code, RelocInfo::CODE_TARGET);
}
@@ -1298,8 +1301,8 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
// Jump to the generic construct code in case the specialized code cannot
// handle the construction.
__ bind(&generic_constructor);
- Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
- Handle<Code> generic_construct_stub(code);
+ Handle<Code> generic_construct_stub =
+ masm->isolate()->builtins()->JSConstructStubGeneric();
__ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
}
@@ -1353,7 +1356,8 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// -----------------------------------
Label invoke, dont_adapt_arguments;
- __ IncrementCounter(&Counters::arguments_adaptors, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->arguments_adaptors(), 1);
Label enough, too_few;
__ cmpq(rax, rbx);
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index eb929782..0fb827bb 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -46,8 +46,8 @@ void ToNumberStub::Generate(MacroAssembler* masm) {
__ Ret();
__ bind(&check_heap_number);
- __ Move(rbx, Factory::heap_number_map());
- __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
+ Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &call_builtin);
__ Ret();
@@ -68,11 +68,15 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
// Get the function info from the stack.
__ movq(rdx, Operand(rsp, 1 * kPointerSize));
+ int map_index = strict_mode_ == kStrictMode
+ ? Context::STRICT_MODE_FUNCTION_MAP_INDEX
+ : Context::FUNCTION_MAP_INDEX;
+
// Compute the function map in the current global context and set that
// as the map of the allocated object.
__ movq(rcx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset));
- __ movq(rcx, Operand(rcx, Context::SlotOffset(Context::FUNCTION_MAP_INDEX)));
+ __ movq(rcx, Operand(rcx, Context::SlotOffset(map_index)));
__ movq(FieldOperand(rax, JSObject::kMapOffset), rcx);
// Initialize the rest of the function. We don't have to update the
@@ -104,7 +108,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
__ pop(rdx);
__ push(rsi);
__ push(rdx);
- __ Push(Factory::false_value());
+ __ PushRoot(Heap::kFalseValueRootIndex);
__ push(rcx); // Restore return address.
__ TailCallRuntime(Runtime::kNewClosure, 3, 1);
}
@@ -280,7 +284,8 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
const char* GenericBinaryOpStub::GetName() {
if (name_ != NULL) return name_;
const int kMaxNameLength = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
+ kMaxNameLength);
if (name_ == NULL) return "OOM";
const char* op_name = Token::Name(op_);
const char* overwrite_name;
@@ -354,7 +359,8 @@ void GenericBinaryOpStub::GenerateCall(
// Update flags to indicate that arguments are in registers.
SetArgsInRegisters();
- __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->generic_binary_stub_calls_regs(), 1);
}
// Call the stub.
@@ -390,7 +396,8 @@ void GenericBinaryOpStub::GenerateCall(
// Update flags to indicate that arguments are in registers.
SetArgsInRegisters();
- __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->generic_binary_stub_calls_regs(), 1);
}
// Call the stub.
@@ -425,7 +432,8 @@ void GenericBinaryOpStub::GenerateCall(
}
// Update flags to indicate that arguments are in registers.
SetArgsInRegisters();
- __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->generic_binary_stub_calls_regs(), 1);
}
// Call the stub.
@@ -995,7 +1003,7 @@ void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
// Perform patching to an appropriate fast case and return the result.
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
+ ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()),
5,
1);
}
@@ -1031,7 +1039,8 @@ void TypeRecordingBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
// Patch the caller to an appropriate specialized stub and return the
// operation result to the caller of the stub.
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch)),
+ ExternalReference(IC_Utility(IC::kTypeRecordingBinaryOp_Patch),
+ masm->isolate()),
5,
1);
}
@@ -1053,6 +1062,9 @@ void TypeRecordingBinaryOpStub::Generate(MacroAssembler* masm) {
case TRBinaryOpIC::HEAP_NUMBER:
GenerateHeapNumberStub(masm);
break;
+ case TRBinaryOpIC::ODDBALL:
+ GenerateOddballStub(masm);
+ break;
case TRBinaryOpIC::STRING:
GenerateStringStub(masm);
break;
@@ -1068,7 +1080,8 @@ void TypeRecordingBinaryOpStub::Generate(MacroAssembler* masm) {
const char* TypeRecordingBinaryOpStub::GetName() {
if (name_ != NULL) return name_;
const int kMaxNameLength = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
+ kMaxNameLength);
if (name_ == NULL) return "OOM";
const char* op_name = Token::Name(op_);
const char* overwrite_name;
@@ -1428,6 +1441,39 @@ void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
}
+void TypeRecordingBinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
+ Label call_runtime;
+
+ if (op_ == Token::ADD) {
+ // Handle string addition here, because it is the only operation
+ // that does not do a ToNumber conversion on the operands.
+ GenerateStringAddCode(masm);
+ }
+
+ // Convert oddball arguments to numbers.
+ NearLabel check, done;
+ __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
+ __ j(not_equal, &check);
+ if (Token::IsBitOp(op_)) {
+ __ xor_(rdx, rdx);
+ } else {
+ __ LoadRoot(rdx, Heap::kNanValueRootIndex);
+ }
+ __ jmp(&done);
+ __ bind(&check);
+ __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
+ __ j(not_equal, &done);
+ if (Token::IsBitOp(op_)) {
+ __ xor_(rax, rax);
+ } else {
+ __ LoadRoot(rax, Heap::kNanValueRootIndex);
+ }
+ __ bind(&done);
+
+ GenerateHeapNumberStub(masm);
+}
+
+
void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
Label gc_required, not_number;
GenerateFloatingPointCode(masm, &gc_required, &not_number);
@@ -1578,15 +1624,18 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ xorl(rcx, rdx);
__ xorl(rax, rdi);
__ xorl(rcx, rax);
- ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
- __ andl(rcx, Immediate(TranscendentalCache::kCacheSize - 1));
+ ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
+ __ andl(rcx, Immediate(TranscendentalCache::SubCache::kCacheSize - 1));
// ST[0] == double value.
// rbx = bits of double value.
// rcx = TranscendentalCache::hash(double value).
- __ movq(rax, ExternalReference::transcendental_cache_array_address());
- // rax points to cache array.
- __ movq(rax, Operand(rax, type_ * sizeof(TranscendentalCache::caches_[0])));
+ ExternalReference cache_array =
+ ExternalReference::transcendental_cache_array_address(masm->isolate());
+ __ movq(rax, cache_array);
+ int cache_array_index =
+ type_ * sizeof(Isolate::Current()->transcendental_cache()->caches_[0]);
+ __ movq(rax, Operand(rax, cache_array_index));
// rax points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
__ testq(rax, rax);
@@ -1594,7 +1643,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
#ifdef DEBUG
// Check that the layout of cache elements match expectations.
{ // NOLINT - doesn't like a single brace on a line.
- TranscendentalCache::Element test_elem[2];
+ TranscendentalCache::SubCache::Element test_elem[2];
char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
@@ -1667,7 +1716,8 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ bind(&runtime_call_clear_stack);
__ fstp(0);
__ bind(&runtime_call);
- __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+ __ TailCallExternalReference(
+ ExternalReference(RuntimeFunction(), masm->isolate()), 1, 1);
} else { // UNTAGGED.
__ bind(&runtime_call_clear_stack);
__ bind(&runtime_call);
@@ -2244,11 +2294,14 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
Label slow;
__ JumpIfNotSmi(rdx, &slow);
- // Check if the calling frame is an arguments adaptor frame.
+ // Check if the calling frame is an arguments adaptor frame. We look at the
+ // context offset, and if the frame is not a regular one, then we find a
+ // Smi instead of the context. We can't use SmiCompare here, because that
+ // only works for comparing two smis.
Label adaptor;
__ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(equal, &adaptor);
// Check index against formal parameters count limit passed in
@@ -2303,8 +2356,8 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(rdx, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(equal, &adaptor_frame);
// Get the length from the frame.
@@ -2331,16 +2384,16 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
__ j(zero, &add_arguments_object);
__ leal(rcx, Operand(rcx, times_pointer_size, FixedArray::kHeaderSize));
__ bind(&add_arguments_object);
- __ addl(rcx, Immediate(Heap::kArgumentsObjectSize));
+ __ addl(rcx, Immediate(GetArgumentsObjectSize()));
// Do the allocation of both objects in one go.
__ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT);
// Get the arguments boilerplate from the current (global) context.
- int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
__ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset));
- __ movq(rdi, Operand(rdi, offset));
+ __ movq(rdi, Operand(rdi,
+ Context::SlotOffset(GetArgumentsBoilerplateIndex())));
// Copy the JS object part.
STATIC_ASSERT(JSObject::kHeaderSize == 3 * kPointerSize);
@@ -2351,15 +2404,21 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
__ movq(FieldOperand(rax, 1 * kPointerSize), rdx);
__ movq(FieldOperand(rax, 2 * kPointerSize), rbx);
- // Setup the callee in-object property.
- ASSERT(Heap::arguments_callee_index == 0);
- __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize));
- __ movq(FieldOperand(rax, JSObject::kHeaderSize), kScratchRegister);
+ if (type_ == NEW_NON_STRICT) {
+ // Setup the callee in-object property.
+ ASSERT(Heap::kArgumentsCalleeIndex == 1);
+ __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize));
+ __ movq(FieldOperand(rax, JSObject::kHeaderSize +
+ Heap::kArgumentsCalleeIndex * kPointerSize),
+ kScratchRegister);
+ }
// Get the length (smi tagged) and set that as an in-object property too.
- ASSERT(Heap::arguments_length_index == 1);
+ ASSERT(Heap::kArgumentsLengthIndex == 0);
__ movq(rcx, Operand(rsp, 1 * kPointerSize));
- __ movq(FieldOperand(rax, JSObject::kHeaderSize + kPointerSize), rcx);
+ __ movq(FieldOperand(rax, JSObject::kHeaderSize +
+ Heap::kArgumentsLengthIndex * kPointerSize),
+ rcx);
// If there are no actual arguments, we're done.
Label done;
@@ -2371,7 +2430,7 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
// Setup the elements pointer in the allocated arguments object and
// initialize the header in the elements fixed array.
- __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize));
+ __ lea(rdi, Operand(rax, GetArgumentsObjectSize()));
__ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi);
__ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
__ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister);
@@ -2423,14 +2482,13 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
static const int kJSRegExpOffset = 4 * kPointerSize;
Label runtime;
-
// Ensure that a RegExp stack is allocated.
+ Isolate* isolate = masm->isolate();
ExternalReference address_of_regexp_stack_memory_address =
- ExternalReference::address_of_regexp_stack_memory_address();
+ ExternalReference::address_of_regexp_stack_memory_address(isolate);
ExternalReference address_of_regexp_stack_memory_size =
- ExternalReference::address_of_regexp_stack_memory_size();
- __ movq(kScratchRegister, address_of_regexp_stack_memory_size);
- __ movq(kScratchRegister, Operand(kScratchRegister, 0));
+ ExternalReference::address_of_regexp_stack_memory_size(isolate);
+ __ Load(kScratchRegister, address_of_regexp_stack_memory_size);
__ testq(kScratchRegister, kScratchRegister);
__ j(zero, &runtime);
@@ -2441,32 +2499,32 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister);
__ j(not_equal, &runtime);
// Check that the RegExp has been compiled (data contains a fixed array).
- __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset));
+ __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset));
if (FLAG_debug_code) {
- Condition is_smi = masm->CheckSmi(rcx);
+ Condition is_smi = masm->CheckSmi(rax);
__ Check(NegateCondition(is_smi),
"Unexpected type for RegExp data, FixedArray expected");
- __ CmpObjectType(rcx, FIXED_ARRAY_TYPE, kScratchRegister);
+ __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister);
__ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
}
- // rcx: RegExp data (FixedArray)
+ // rax: RegExp data (FixedArray)
// Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
- __ SmiToInteger32(rbx, FieldOperand(rcx, JSRegExp::kDataTagOffset));
+ __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset));
__ cmpl(rbx, Immediate(JSRegExp::IRREGEXP));
__ j(not_equal, &runtime);
- // rcx: RegExp data (FixedArray)
+ // rax: RegExp data (FixedArray)
// Check that the number of captures fit in the static offsets vector buffer.
__ SmiToInteger32(rdx,
- FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset));
+ FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset));
// Calculate number of capture registers (number_of_captures + 1) * 2.
__ leal(rdx, Operand(rdx, rdx, times_1, 2));
// Check that the static offsets vector buffer is large enough.
__ cmpl(rdx, Immediate(OffsetsVector::kStaticOffsetsVectorSize));
__ j(above, &runtime);
- // rcx: RegExp data (FixedArray)
+ // rax: RegExp data (FixedArray)
// rdx: Number of capture registers
// Check that the second argument is a string.
__ movq(rdi, Operand(rsp, kSubjectOffset));
@@ -2494,7 +2552,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Check that the JSArray is in fast case.
__ movq(rbx, FieldOperand(rdi, JSArray::kElementsOffset));
__ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
- __ Cmp(rdi, Factory::fixed_array_map());
+ __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
+ Heap::kFixedArrayMapRootIndex);
__ j(not_equal, &runtime);
// Check that the last match info has space for the capture registers and the
// additional information. Ensure no overflow in add.
@@ -2529,8 +2588,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag));
__ j(not_zero, &runtime);
// String is a cons string.
- __ movq(rdx, FieldOperand(rdi, ConsString::kSecondOffset));
- __ Cmp(rdx, Factory::empty_string());
+ __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset),
+ Heap::kEmptyStringRootIndex);
__ j(not_equal, &runtime);
__ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset));
__ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
@@ -2579,15 +2638,24 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// rcx: encoding of subject string (1 if ascii 0 if two_byte);
// r11: code
// All checks done. Now push arguments for native regexp code.
- __ IncrementCounter(&Counters::regexp_entry_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->regexp_entry_native(), 1);
- static const int kRegExpExecuteArguments = 7;
+ // Isolates: note we add an additional parameter here (isolate pointer).
+ static const int kRegExpExecuteArguments = 8;
int argument_slots_on_stack =
masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments);
- __ EnterApiExitFrame(argument_slots_on_stack); // Clobbers rax!
+ __ EnterApiExitFrame(argument_slots_on_stack);
- // Argument 7: Indicate that this is a direct call from JavaScript.
+ // Argument 8: Pass current isolate address.
+ // __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize),
+ // Immediate(ExternalReference::isolate_address()));
+ __ LoadAddress(kScratchRegister, ExternalReference::isolate_address());
__ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize),
+ kScratchRegister);
+
+ // Argument 7: Indicate that this is a direct call from JavaScript.
+ __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kPointerSize),
Immediate(1));
// Argument 6: Start (high end) of backtracking stack memory area.
@@ -2597,14 +2665,15 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ addq(r9, Operand(kScratchRegister, 0));
// Argument 6 passed in r9 on Linux and on the stack on Windows.
#ifdef _WIN64
- __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kPointerSize), r9);
+ __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kPointerSize), r9);
#endif
// Argument 5: static offsets vector buffer.
- __ movq(r8, ExternalReference::address_of_static_offsets_vector());
+ __ LoadAddress(r8,
+ ExternalReference::address_of_static_offsets_vector(isolate));
// Argument 5 passed in r8 on Linux and on the stack on Windows.
#ifdef _WIN64
- __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kPointerSize), r8);
+ __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kPointerSize), r8);
#endif
// First four arguments are passed in registers on both Linux and Windows.
@@ -2705,7 +2774,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi);
// Get the static offsets vector filled by the native regexp code.
- __ movq(rcx, ExternalReference::address_of_static_offsets_vector());
+ __ LoadAddress(rcx,
+ ExternalReference::address_of_static_offsets_vector(isolate));
// rbx: last_match_info backing store (FixedArray)
// rcx: offsets vector
@@ -2737,13 +2807,15 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system.
// TODO(592): Rerunning the RegExp to get the stack overflow exception.
- ExternalReference pending_exception_address(Top::k_pending_exception_address);
- __ movq(rbx, pending_exception_address);
- __ movq(rax, Operand(rbx, 0));
+ ExternalReference pending_exception_address(
+ Isolate::k_pending_exception_address, isolate);
+ Operand pending_exception_operand =
+ masm->ExternalOperand(pending_exception_address, rbx);
+ __ movq(rax, pending_exception_operand);
__ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
__ cmpq(rax, rdx);
__ j(equal, &runtime);
- __ movq(Operand(rbx, 0), rdx);
+ __ movq(pending_exception_operand, rdx);
__ CompareRoot(rax, Heap::kTerminationExceptionRootIndex);
NearLabel termination_exception;
@@ -2794,8 +2866,8 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
__ movq(FieldOperand(rax, HeapObject::kMapOffset), rdx);
// Set empty properties FixedArray.
- __ Move(FieldOperand(rax, JSObject::kPropertiesOffset),
- Factory::empty_fixed_array());
+ __ LoadRoot(kScratchRegister, Heap::kEmptyFixedArrayRootIndex);
+ __ movq(FieldOperand(rax, JSObject::kPropertiesOffset), kScratchRegister);
// Set elements to point to FixedArray allocated right after the JSArray.
__ lea(rcx, Operand(rax, JSRegExpResult::kSize));
@@ -2815,13 +2887,13 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
// rbx: Number of elements in array as int32.
// Set map.
- __ Move(FieldOperand(rcx, HeapObject::kMapOffset),
- Factory::fixed_array_map());
+ __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
+ __ movq(FieldOperand(rcx, HeapObject::kMapOffset), kScratchRegister);
// Set length.
__ Integer32ToSmi(rdx, rbx);
__ movq(FieldOperand(rcx, FixedArray::kLengthOffset), rdx);
// Fill contents of fixed-array with the-hole.
- __ Move(rdx, Factory::the_hole_value());
+ __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
__ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize));
// Fill fixed array elements with hole.
// rax: JSArray.
@@ -2874,7 +2946,7 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
Label load_result_from_cache;
if (!object_is_smi) {
__ JumpIfSmi(object, &is_smi);
- __ CheckMap(object, Factory::heap_number_map(), not_found, true);
+ __ CheckMap(object, FACTORY->heap_number_map(), not_found, true);
STATIC_ASSERT(8 == kDoubleSize);
__ movl(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
@@ -2889,7 +2961,7 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
times_1,
FixedArray::kHeaderSize));
__ JumpIfSmi(probe, not_found);
- ASSERT(CpuFeatures::IsSupported(SSE2));
+ ASSERT(Isolate::Current()->cpu_features()->IsSupported(SSE2));
CpuFeatures::Scope fscope(SSE2);
__ movsd(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
__ movsd(xmm1, FieldOperand(probe, HeapNumber::kValueOffset));
@@ -2919,7 +2991,8 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
index,
times_1,
FixedArray::kHeaderSize + kPointerSize));
- __ IncrementCounter(&Counters::number_to_string_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->number_to_string_native(), 1);
}
@@ -3004,7 +3077,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ bind(&check_for_nan);
}
- // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
+ // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
// so we do the second best thing - test it ourselves.
// Note: if cc_ != equal, never_nan_nan_ is not used.
// We cannot set rax to EQUAL until just before return because
@@ -3017,7 +3090,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
NearLabel heap_number;
// If it's not a heap number, then return equal for (in)equality operator.
__ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
__ j(equal, &heap_number);
if (cc_ != equal) {
// Call runtime on identical JSObjects. Otherwise return equal.
@@ -3062,7 +3135,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
// Check if the non-smi operand is a heap number.
__ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
// If heap number, handle it in the slow case.
__ j(equal, &slow);
// Return non-equal. ebx (the lower half of rbx) is not zero.
@@ -3295,11 +3368,17 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ Set(rax, argc_);
__ Set(rbx, 0);
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
- Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
+ Handle<Code> adaptor =
+ Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline();
__ Jump(adaptor, RelocInfo::CODE_TARGET);
}
+bool CEntryStub::NeedsImmovableCode() {
+ return false;
+}
+
+
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
// Throw exception in eax.
__ Throw(rax);
@@ -3317,7 +3396,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
// rbp: frame pointer (restored after C call).
// rsp: stack pointer (restored after C call).
// r14: number of arguments including receiver (C callee-saved).
- // r12: pointer to the first argument (C callee-saved).
+ // r15: pointer to the first argument (C callee-saved).
// This pointer is reused in LeaveExitFrame(), so it is stored in a
// callee-saved register.
@@ -3347,10 +3426,10 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
}
ExternalReference scope_depth =
- ExternalReference::heap_always_allocate_scope_depth();
+ ExternalReference::heap_always_allocate_scope_depth(masm->isolate());
if (always_allocate_scope) {
- __ movq(kScratchRegister, scope_depth);
- __ incl(Operand(kScratchRegister, 0));
+ Operand scope_depth_operand = masm->ExternalOperand(scope_depth);
+ __ incl(scope_depth_operand);
}
// Call C function.
@@ -3358,30 +3437,33 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
// Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9
// Store Arguments object on stack, below the 4 WIN64 ABI parameter slots.
__ movq(StackSpaceOperand(0), r14); // argc.
- __ movq(StackSpaceOperand(1), r12); // argv.
+ __ movq(StackSpaceOperand(1), r15); // argv.
if (result_size_ < 2) {
// Pass a pointer to the Arguments object as the first argument.
// Return result in single register (rax).
__ lea(rcx, StackSpaceOperand(0));
+ __ LoadAddress(rdx, ExternalReference::isolate_address());
} else {
ASSERT_EQ(2, result_size_);
// Pass a pointer to the result location as the first argument.
__ lea(rcx, StackSpaceOperand(2));
// Pass a pointer to the Arguments object as the second argument.
__ lea(rdx, StackSpaceOperand(0));
+ __ LoadAddress(r8, ExternalReference::isolate_address());
}
#else // _WIN64
// GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9.
__ movq(rdi, r14); // argc.
- __ movq(rsi, r12); // argv.
+ __ movq(rsi, r15); // argv.
+ __ movq(rdx, ExternalReference::isolate_address());
#endif
__ call(rbx);
// Result is in rax - do not destroy this register!
if (always_allocate_scope) {
- __ movq(kScratchRegister, scope_depth);
- __ decl(Operand(kScratchRegister, 0));
+ Operand scope_depth_operand = masm->ExternalOperand(scope_depth);
+ __ decl(scope_depth_operand);
}
// Check for failure result.
@@ -3422,12 +3504,13 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ j(equal, throw_out_of_memory_exception);
// Retrieve the pending exception and clear the variable.
- ExternalReference pending_exception_address(Top::k_pending_exception_address);
- __ movq(kScratchRegister, pending_exception_address);
- __ movq(rax, Operand(kScratchRegister, 0));
- __ movq(rdx, ExternalReference::the_hole_value_location());
- __ movq(rdx, Operand(rdx, 0));
- __ movq(Operand(kScratchRegister, 0), rdx);
+ ExternalReference pending_exception_address(
+ Isolate::k_pending_exception_address, masm->isolate());
+ Operand pending_exception_operand =
+ masm->ExternalOperand(pending_exception_address);
+ __ movq(rax, pending_exception_operand);
+ __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ movq(pending_exception_operand, rdx);
// Special handling of termination exceptions which are uncatchable
// by javascript code.
@@ -3478,7 +3561,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// rbp: frame pointer of exit frame (restored after C call).
// rsp: stack pointer (restored after C call).
// r14: number of arguments including receiver (C callee-saved).
- // r12: argv pointer (C callee-saved).
+ // r15: argv pointer (C callee-saved).
Label throw_normal_exception;
Label throw_termination_exception;
@@ -3526,52 +3609,58 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
#ifdef ENABLE_LOGGING_AND_PROFILING
Label not_outermost_js, not_outermost_js_2;
#endif
-
- // Setup frame.
- __ push(rbp);
- __ movq(rbp, rsp);
-
- // Push the stack frame type marker twice.
- int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
- // Scratch register is neither callee-save, nor an argument register on any
- // platform. It's free to use at this point.
- // Cannot use smi-register for loading yet.
- __ movq(kScratchRegister,
- reinterpret_cast<uint64_t>(Smi::FromInt(marker)),
- RelocInfo::NONE);
- __ push(kScratchRegister); // context slot
- __ push(kScratchRegister); // function slot
- // Save callee-saved registers (X64/Win64 calling conventions).
- __ push(r12);
- __ push(r13);
- __ push(r14);
- __ push(r15);
+ { // NOLINT. Scope block confuses linter.
+ MacroAssembler::NoRootArrayScope uninitialized_root_register(masm);
+ // Setup frame.
+ __ push(rbp);
+ __ movq(rbp, rsp);
+
+ // Push the stack frame type marker twice.
+ int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
+ // Scratch register is neither callee-save, nor an argument register on any
+ // platform. It's free to use at this point.
+ // Cannot use smi-register for loading yet.
+ __ movq(kScratchRegister,
+ reinterpret_cast<uint64_t>(Smi::FromInt(marker)),
+ RelocInfo::NONE);
+ __ push(kScratchRegister); // context slot
+ __ push(kScratchRegister); // function slot
+ // Save callee-saved registers (X64/Win64 calling conventions).
+ __ push(r12);
+ __ push(r13);
+ __ push(r14);
+ __ push(r15);
#ifdef _WIN64
- __ push(rdi); // Only callee save in Win64 ABI, argument in AMD64 ABI.
- __ push(rsi); // Only callee save in Win64 ABI, argument in AMD64 ABI.
+ __ push(rdi); // Only callee save in Win64 ABI, argument in AMD64 ABI.
+ __ push(rsi); // Only callee save in Win64 ABI, argument in AMD64 ABI.
#endif
- __ push(rbx);
- // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are
- // callee save as well.
+ __ push(rbx);
+ // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are
+ // callee save as well.
+
+ // Set up the roots and smi constant registers.
+ // Needs to be done before any further smi loads.
+ __ InitializeSmiConstantRegister();
+ __ InitializeRootRegister();
+ }
- // Save copies of the top frame descriptor on the stack.
- ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
- __ load_rax(c_entry_fp);
- __ push(rax);
+ Isolate* isolate = masm->isolate();
- // Set up the roots and smi constant registers.
- // Needs to be done before any further smi loads.
- __ InitializeRootRegister();
- __ InitializeSmiConstantRegister();
+ // Save copies of the top frame descriptor on the stack.
+ ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, isolate);
+ {
+ Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
+ __ push(c_entry_fp_operand);
+ }
#ifdef ENABLE_LOGGING_AND_PROFILING
// If this is the outermost JS call, set js_entry_sp value.
- ExternalReference js_entry_sp(Top::k_js_entry_sp_address);
- __ load_rax(js_entry_sp);
+ ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate);
+ __ Load(rax, js_entry_sp);
__ testq(rax, rax);
__ j(not_zero, &not_outermost_js);
__ movq(rax, rbp);
- __ store_rax(js_entry_sp);
+ __ Store(js_entry_sp, rax);
__ bind(&not_outermost_js);
#endif
@@ -3580,8 +3669,9 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Caught exception: Store result (exception) in the pending
// exception field in the JSEnv and return a failure sentinel.
- ExternalReference pending_exception(Top::k_pending_exception_address);
- __ store_rax(pending_exception);
+ ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ isolate);
+ __ Store(pending_exception, rax);
__ movq(rax, Failure::Exception(), RelocInfo::NONE);
__ jmp(&exit);
@@ -3590,8 +3680,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
__ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
// Clear any pending exceptions.
- __ load_rax(ExternalReference::the_hole_value_location());
- __ store_rax(pending_exception);
+ __ LoadRoot(rax, Heap::kTheHoleValueRootIndex);
+ __ Store(pending_exception, rax);
// Fake a receiver (NULL).
__ push(Immediate(0)); // receiver
@@ -3602,18 +3692,21 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// directly in the code, because the builtin stubs may not have been
// generated yet at the time this code is generated.
if (is_construct) {
- ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
- __ load_rax(construct_entry);
+ ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
+ isolate);
+ __ Load(rax, construct_entry);
} else {
- ExternalReference entry(Builtins::JSEntryTrampoline);
- __ load_rax(entry);
+ ExternalReference entry(Builtins::kJSEntryTrampoline, isolate);
+ __ Load(rax, entry);
}
__ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize));
__ call(kScratchRegister);
// Unlink this frame from the handler chain.
- __ movq(kScratchRegister, ExternalReference(Top::k_handler_address));
- __ pop(Operand(kScratchRegister, 0));
+ Operand handler_operand =
+ masm->ExternalOperand(ExternalReference(Isolate::k_handler_address,
+ isolate));
+ __ pop(handler_operand);
// Pop next_sp.
__ addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize));
@@ -3629,8 +3722,10 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Restore the top frame descriptor from the stack.
__ bind(&exit);
- __ movq(kScratchRegister, ExternalReference(Top::k_c_entry_fp_address));
- __ pop(Operand(kScratchRegister, 0));
+ {
+ Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
+ __ pop(c_entry_fp_operand);
+ }
// Restore callee-saved registers (X64 conventions).
__ pop(rbx);
@@ -3653,20 +3748,39 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
void InstanceofStub::Generate(MacroAssembler* masm) {
// Implements "value instanceof function" operator.
- // Expected input state:
+ // Expected input state with no inline cache:
// rsp[0] : return address
// rsp[1] : function pointer
// rsp[2] : value
+ // Expected input state with an inline one-element cache:
+ // rsp[0] : return address
+ // rsp[1] : offset from return address to location of inline cache
+ // rsp[2] : function pointer
+ // rsp[3] : value
// Returns a bitwise zero to indicate that the value
// is and instance of the function and anything else to
// indicate that the value is not an instance.
- // None of the flags are supported on X64.
- ASSERT(flags_ == kNoFlags);
+ static const int kOffsetToMapCheckValue = 5;
+ static const int kOffsetToResultValue = 21;
+ // The last 4 bytes of the instruction sequence
+ // movq(rax, FieldOperand(rdi, HeapObject::kMapOffset)
+ // Move(kScratchRegister, FACTORY->the_hole_value())
+ // in front of the hole value address.
+ static const unsigned int kWordBeforeMapCheckValue = 0xBA49FF78;
+ // The last 4 bytes of the instruction sequence
+ // __ j(not_equal, &cache_miss);
+ // __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
+ // before the offset of the hole value in the root array.
+ static const unsigned int kWordBeforeResultValue = 0x458B4909;
+ // Only the inline check flag is supported on X64.
+ ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck());
+ int extra_stack_space = HasCallSiteInlineCheck() ? kPointerSize : 0;
// Get the object - go slow case if it's a smi.
Label slow;
- __ movq(rax, Operand(rsp, 2 * kPointerSize));
+
+ __ movq(rax, Operand(rsp, 2 * kPointerSize + extra_stack_space));
__ JumpIfSmi(rax, &slow);
// Check that the left hand is a JS object. Leave its map in rax.
@@ -3676,19 +3790,23 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ j(above, &slow);
// Get the prototype of the function.
- __ movq(rdx, Operand(rsp, 1 * kPointerSize));
+ __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space));
// rdx is function, rax is map.
- // Look up the function and the map in the instanceof cache.
- NearLabel miss;
- __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
- __ j(not_equal, &miss);
- __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex);
- __ j(not_equal, &miss);
- __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
- __ ret(2 * kPointerSize);
+ // If there is a call site cache don't look in the global cache, but do the
+ // real lookup and update the call site cache.
+ if (!HasCallSiteInlineCheck()) {
+ // Look up the function and the map in the instanceof cache.
+ NearLabel miss;
+ __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
+ __ j(not_equal, &miss);
+ __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex);
+ __ j(not_equal, &miss);
+ __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
+ __ ret(2 * kPointerSize);
+ __ bind(&miss);
+ }
- __ bind(&miss);
__ TryGetFunctionPrototype(rdx, rbx, &slow);
// Check that the function prototype is a JS object.
@@ -3702,8 +3820,19 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// rax is object map.
// rdx is function.
// rbx is function prototype.
- __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
- __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex);
+ if (!HasCallSiteInlineCheck()) {
+ __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
+ __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex);
+ } else {
+ __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
+ __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
+ __ movq(Operand(kScratchRegister, kOffsetToMapCheckValue), rax);
+ if (FLAG_debug_code) {
+ __ movl(rdi, Immediate(kWordBeforeMapCheckValue));
+ __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi);
+ __ Assert(equal, "InstanceofStub unexpected call site cache.");
+ }
+ }
__ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset));
@@ -3722,19 +3851,56 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ jmp(&loop);
__ bind(&is_instance);
- __ xorl(rax, rax);
- // Store bitwise zero in the cache. This is a Smi in GC terms.
- STATIC_ASSERT(kSmiTag == 0);
- __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
- __ ret(2 * kPointerSize);
+ if (!HasCallSiteInlineCheck()) {
+ __ xorl(rax, rax);
+ // Store bitwise zero in the cache. This is a Smi in GC terms.
+ STATIC_ASSERT(kSmiTag == 0);
+ __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
+ } else {
+ // Store offset of true in the root array at the inline check site.
+ ASSERT((Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias
+ == 0xB0 - 0x100);
+ __ movl(rax, Immediate(0xB0)); // TrueValue is at -10 * kPointerSize.
+ __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
+ __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
+ __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
+ if (FLAG_debug_code) {
+ __ movl(rax, Immediate(kWordBeforeResultValue));
+ __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax);
+ __ Assert(equal, "InstanceofStub unexpected call site cache.");
+ }
+ __ xorl(rax, rax);
+ }
+ __ ret(2 * kPointerSize + extra_stack_space);
__ bind(&is_not_instance);
- // We have to store a non-zero value in the cache.
- __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex);
- __ ret(2 * kPointerSize);
+ if (!HasCallSiteInlineCheck()) {
+ // We have to store a non-zero value in the cache.
+ __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex);
+ } else {
+ // Store offset of false in the root array at the inline check site.
+ ASSERT((Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias
+ == 0xB8 - 0x100);
+ __ movl(rax, Immediate(0xB8)); // FalseValue is at -9 * kPointerSize.
+ __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
+ __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
+ __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
+ if (FLAG_debug_code) {
+ __ movl(rax, Immediate(kWordBeforeResultValue));
+ __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax);
+ __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
+ }
+ }
+ __ ret(2 * kPointerSize + extra_stack_space);
// Slow-case: Go through the JavaScript implementation.
__ bind(&slow);
+ if (HasCallSiteInlineCheck()) {
+ // Remove extra value from the stack.
+ __ pop(rcx);
+ __ pop(rax);
+ __ push(rcx);
+ }
__ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
}
@@ -3768,7 +3934,8 @@ const char* CompareStub::GetName() {
if (name_ != NULL) return name_;
const int kMaxNameLength = 100;
- name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
+ name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
+ kMaxNameLength);
if (name_ == NULL) return "OOM";
const char* cc_name;
@@ -3902,7 +4069,7 @@ void StringCharCodeAtGenerator::GenerateSlow(
// Index is not a smi.
__ bind(&index_not_smi_);
// If index is a heap number, try converting it to an integer.
- __ CheckMap(index_, Factory::heap_number_map(), index_not_number_, true);
+ __ CheckMap(index_, FACTORY->heap_number_map(), index_not_number_, true);
call_helper.BeforeCall(masm);
__ push(object_);
__ push(index_);
@@ -4047,7 +4214,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ SmiTest(rcx);
__ j(not_zero, &second_not_zero_length);
// Second string is empty, result is first string which is already in rax.
- __ IncrementCounter(&Counters::string_add_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
__ bind(&second_not_zero_length);
__ movq(rbx, FieldOperand(rax, String::kLengthOffset));
@@ -4055,7 +4223,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ j(not_zero, &both_not_zero_length);
// First string is empty, result is second string which is in rdx.
__ movq(rax, rdx);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
// Both strings are non-empty.
@@ -4081,8 +4249,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// Look at the length of the result of adding the two strings.
STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2);
__ SmiAdd(rbx, rbx, rcx);
- // Use the runtime system when adding two one character strings, as it
- // contains optimizations for this specific case using the symbol table.
+ // Use the symbol table when adding two one character strings, as it
+ // helps later optimizations to return a symbol here.
__ SmiCompare(rbx, Smi::FromInt(2));
__ j(not_equal, &longer_than_two);
@@ -4098,8 +4266,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// just allocate a new one.
Label make_two_character_string, make_flat_ascii_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
- masm, rbx, rcx, r14, r11, rdi, r12, &make_two_character_string);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
__ bind(&make_two_character_string);
@@ -4139,7 +4307,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax);
__ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx);
__ movq(rax, rcx);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
__ bind(&non_ascii);
// At least one of the strings is two-byte. Check whether it happens
@@ -4213,7 +4381,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// rdi: length of second argument
StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, true);
__ movq(rax, rbx);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
// Handle creating a flat two byte result.
@@ -4250,7 +4418,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// rdi: length of second argument
StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false);
__ movq(rax, rbx);
- __ IncrementCounter(&Counters::string_add_native, 1);
+ __ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
// Just jump to runtime to add the two strings.
@@ -4434,15 +4602,14 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
__ decl(mask);
- Register undefined = scratch4;
- __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
+ Register map = scratch4;
// Registers
// chars: two character string, char 1 in byte 0 and char 2 in byte 1.
// hash: hash of two character string (32-bit int)
// symbol_table: symbol table
// mask: capacity mask (32-bit int)
- // undefined: undefined value
+ // map: -
// scratch: -
// Perform a number of probes in the symbol table.
@@ -4457,7 +4624,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
}
__ andl(scratch, mask);
- // Load the entry from the symble table.
+ // Load the entry from the symbol table.
Register candidate = scratch; // Scratch register contains candidate.
STATIC_ASSERT(SymbolTable::kEntrySize == 1);
__ movq(candidate,
@@ -4467,8 +4634,16 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
SymbolTable::kElementsStartOffset));
// If entry is undefined no string with this hash can be found.
- __ cmpq(candidate, undefined);
+ NearLabel is_string;
+ __ CmpObjectType(candidate, ODDBALL_TYPE, map);
+ __ j(not_equal, &is_string);
+
+ __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex);
__ j(equal, not_found);
+ // Must be null (deleted entry).
+ __ jmp(&next_probe[i]);
+
+ __ bind(&is_string);
// If length is not 2 the string is not a candidate.
__ SmiCompare(FieldOperand(candidate, String::kLengthOffset),
@@ -4480,8 +4655,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
Register temp = kScratchRegister;
// Check that the candidate is a non-external ascii string.
- __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset));
- __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
+ __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset));
__ JumpIfInstanceTypeIsNotSequentialAscii(
temp, temp, &next_probe[i]);
@@ -4659,7 +4833,8 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// rsi: character of sub string start
StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true);
__ movq(rsi, rdx); // Restore rsi.
- __ IncrementCounter(&Counters::sub_string_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->sub_string_native(), 1);
__ ret(kArgumentsSize);
__ bind(&non_ascii_flat);
@@ -4696,7 +4871,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ movq(rsi, rdx); // Restore esi.
__ bind(&return_rax);
- __ IncrementCounter(&Counters::sub_string_native, 1);
+ __ IncrementCounter(counters->sub_string_native(), 1);
__ ret(kArgumentsSize);
// Just jump to runtime to create the sub string.
@@ -4810,7 +4985,8 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
__ cmpq(rdx, rax);
__ j(not_equal, &not_same);
__ Move(rax, Smi::FromInt(EQUAL));
- __ IncrementCounter(&Counters::string_compare_native, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->string_compare_native(), 1);
__ ret(2 * kPointerSize);
__ bind(&not_same);
@@ -4819,7 +4995,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
__ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime);
// Inline comparison of ascii strings.
- __ IncrementCounter(&Counters::string_compare_native, 1);
+ __ IncrementCounter(counters->string_compare_native(), 1);
// Drop arguments from the stack
__ pop(rcx);
__ addq(rsp, Immediate(2 * kPointerSize));
@@ -4833,60 +5009,6 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
}
-void StringCharAtStub::Generate(MacroAssembler* masm) {
- // Expects two arguments (object, index) on the stack:
-
- // Stack frame on entry.
- // rsp[0]: return address
- // rsp[8]: index
- // rsp[16]: object
-
- Register object = rbx;
- Register index = rax;
- Register scratch1 = rcx;
- Register scratch2 = rdx;
- Register result = rax;
-
- __ pop(scratch1); // Return address.
- __ pop(index);
- __ pop(object);
- __ push(scratch1);
-
- Label need_conversion;
- Label index_out_of_range;
- Label done;
- StringCharAtGenerator generator(object,
- index,
- scratch1,
- scratch2,
- result,
- &need_conversion,
- &need_conversion,
- &index_out_of_range,
- STRING_INDEX_IS_NUMBER);
- generator.GenerateFast(masm);
- __ jmp(&done);
-
- __ bind(&index_out_of_range);
- // When the index is out of range, the spec requires us to return
- // the empty string.
- __ Move(result, Factory::empty_string());
- __ jmp(&done);
-
- __ bind(&need_conversion);
- // Move smi zero into the result register, which will trigger
- // conversion.
- __ Move(result, Smi::FromInt(0));
- __ jmp(&done);
-
- StubRuntimeCallHelper call_helper;
- generator.GenerateSlow(masm, call_helper);
-
- __ bind(&done);
- __ ret(0);
-}
-
-
void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
ASSERT(state_ == CompareIC::SMIS);
NearLabel miss;
@@ -4982,7 +5104,8 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
__ push(rcx);
// Call the runtime system in a fresh internal frame.
- ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss));
+ ExternalReference miss =
+ ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
__ EnterInternalFrame();
__ push(rdx);
__ push(rax);
@@ -5004,144 +5127,6 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
}
-void GenerateFastPixelArrayLoad(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register elements,
- Register untagged_key,
- Register result,
- Label* not_pixel_array,
- Label* key_not_smi,
- Label* out_of_range) {
- // Register use:
- // receiver - holds the receiver and is unchanged.
- // key - holds the key and is unchanged (must be a smi).
- // elements - is set to the the receiver's element if
- // the receiver doesn't have a pixel array or the
- // key is not a smi, otherwise it's the elements'
- // external pointer.
- // untagged_key - is set to the untagged key
-
- // Some callers already have verified that the key is a smi. key_not_smi is
- // set to NULL as a sentinel for that case. Otherwise, add an explicit check
- // to ensure the key is a smi must be added.
- if (key_not_smi != NULL) {
- __ JumpIfNotSmi(key, key_not_smi);
- } else {
- if (FLAG_debug_code) {
- __ AbortIfNotSmi(key);
- }
- }
- __ SmiToInteger32(untagged_key, key);
-
- __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
- // By passing NULL as not_pixel_array, callers signal that they have already
- // verified that the receiver has pixel array elements.
- if (not_pixel_array != NULL) {
- __ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
- } else {
- if (FLAG_debug_code) {
- // Map check should have already made sure that elements is a pixel array.
- __ Cmp(FieldOperand(elements, HeapObject::kMapOffset),
- Factory::pixel_array_map());
- __ Assert(equal, "Elements isn't a pixel array");
- }
- }
-
- // Check that the smi is in range.
- __ cmpl(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
- __ j(above_equal, out_of_range); // unsigned check handles negative keys.
-
- // Load and tag the element as a smi.
- __ movq(elements, FieldOperand(elements, PixelArray::kExternalPointerOffset));
- __ movzxbq(result, Operand(elements, untagged_key, times_1, 0));
- __ Integer32ToSmi(result, result);
- __ ret(0);
-}
-
-
-// Stores an indexed element into a pixel array, clamping the stored value.
-void GenerateFastPixelArrayStore(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register value,
- Register elements,
- Register scratch1,
- bool load_elements_from_receiver,
- bool key_is_untagged,
- Label* key_not_smi,
- Label* value_not_smi,
- Label* not_pixel_array,
- Label* out_of_range) {
- // Register use:
- // receiver - holds the receiver and is unchanged.
- // key - holds the key (must be a smi) and is unchanged.
- // value - holds the value (must be a smi) and is unchanged.
- // elements - holds the element object of the receiver on entry if
- // load_elements_from_receiver is false, otherwise used
- // internally to store the pixel arrays elements and
- // external array pointer.
- //
- Register external_pointer = elements;
- Register untagged_key = scratch1;
- Register untagged_value = receiver; // Only set once success guaranteed.
-
- // Fetch the receiver's elements if the caller hasn't already done so.
- if (load_elements_from_receiver) {
- __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
- }
-
- // By passing NULL as not_pixel_array, callers signal that they have already
- // verified that the receiver has pixel array elements.
- if (not_pixel_array != NULL) {
- __ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
- } else {
- if (FLAG_debug_code) {
- // Map check should have already made sure that elements is a pixel array.
- __ Cmp(FieldOperand(elements, HeapObject::kMapOffset),
- Factory::pixel_array_map());
- __ Assert(equal, "Elements isn't a pixel array");
- }
- }
-
- // Key must be a smi and it must be in range.
- if (key_is_untagged) {
- untagged_key = key;
- } else {
- // Some callers already have verified that the key is a smi. key_not_smi is
- // set to NULL as a sentinel for that case. Otherwise, add an explicit
- // check to ensure the key is a smi.
- if (key_not_smi != NULL) {
- __ JumpIfNotSmi(key, key_not_smi);
- } else {
- if (FLAG_debug_code) {
- __ AbortIfNotSmi(key);
- }
- }
- __ SmiToInteger32(untagged_key, key);
- }
- __ cmpl(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
- __ j(above_equal, out_of_range); // unsigned check handles negative keys.
-
- // Value must be a smi.
- __ JumpIfNotSmi(value, value_not_smi);
- __ SmiToInteger32(untagged_value, value);
-
- { // Clamp the value to [0..255].
- NearLabel done;
- __ testl(untagged_value, Immediate(0xFFFFFF00));
- __ j(zero, &done);
- __ setcc(negative, untagged_value); // 1 if negative, 0 if positive.
- __ decb(untagged_value); // 0 if negative, 255 if positive.
- __ bind(&done);
- }
-
- __ movq(external_pointer,
- FieldOperand(elements, PixelArray::kExternalPointerOffset));
- __ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value);
- __ ret(0); // Return value in eax.
-}
-
#undef __
} } // namespace v8::internal
diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h
index 32a37b21..246650af 100644
--- a/src/x64/code-stubs-x64.h
+++ b/src/x64/code-stubs-x64.h
@@ -289,6 +289,7 @@ class TypeRecordingBinaryOpStub: public CodeStub {
void GenerateSmiStub(MacroAssembler* masm);
void GenerateInt32Stub(MacroAssembler* masm);
void GenerateHeapNumberStub(MacroAssembler* masm);
+ void GenerateOddballStub(MacroAssembler* masm);
void GenerateStringStub(MacroAssembler* masm);
void GenerateGenericStub(MacroAssembler* masm);
@@ -471,49 +472,6 @@ class NumberToStringStub: public CodeStub {
};
-// Generate code to load an element from a pixel array. The receiver is assumed
-// to not be a smi and to have elements, the caller must guarantee this
-// precondition. If key is not a smi, then the generated code branches to
-// key_not_smi. Callers can specify NULL for key_not_smi to signal that a smi
-// check has already been performed on key so that the smi check is not
-// generated. If key is not a valid index within the bounds of the pixel array,
-// the generated code jumps to out_of_range. receiver, key and elements are
-// unchanged throughout the generated code sequence.
-void GenerateFastPixelArrayLoad(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register elements,
- Register untagged_key,
- Register result,
- Label* not_pixel_array,
- Label* key_not_smi,
- Label* out_of_range);
-
-// Generate code to store an element into a pixel array, clamping values between
-// [0..255]. The receiver is assumed to not be a smi and to have elements, the
-// caller must guarantee this precondition. If key is not a smi, then the
-// generated code branches to key_not_smi. Callers can specify NULL for
-// key_not_smi to signal that a smi check has already been performed on key so
-// that the smi check is not generated. If the value is not a smi, the
-// generated code will branch to value_not_smi. If the receiver
-// doesn't have pixel array elements, the generated code will branch to
-// not_pixel_array, unless not_pixel_array is NULL, in which case the caller
-// must ensure that the receiver has pixel array elements. If key is not a
-// valid index within the bounds of the pixel array, the generated code jumps to
-// out_of_range.
-void GenerateFastPixelArrayStore(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register value,
- Register elements,
- Register scratch1,
- bool load_elements_from_receiver,
- bool key_is_untagged,
- Label* key_not_smi,
- Label* value_not_smi,
- Label* not_pixel_array,
- Label* out_of_range);
-
} } // namespace v8::internal
#endif // V8_X64_CODE_STUBS_X64_H_
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index fc4bc04e..8c338fe6 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -180,7 +180,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
ASSERT_EQ(0, loop_nesting_);
loop_nesting_ = info->is_in_loop() ? 1 : 0;
- JumpTarget::set_compiling_deferred_code(false);
+ Isolate::Current()->set_jump_target_compiling_deferred_code(false);
{
CodeGenState state(this);
@@ -281,7 +281,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Initialize ThisFunction reference if present.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- frame_->Push(Factory::the_hole_value());
+ frame_->Push(FACTORY->the_hole_value());
StoreToSlot(scope()->function()->AsSlot(), NOT_CONST_INIT);
}
@@ -316,7 +316,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
if (!scope()->HasIllegalRedeclaration()) {
Comment cmnt(masm_, "[ function body");
#ifdef DEBUG
- bool is_builtin = Bootstrapper::IsActive();
+ bool is_builtin = Isolate::Current()->bootstrapper()->IsActive();
bool should_trace =
is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
if (should_trace) {
@@ -333,7 +333,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
ASSERT(!function_return_is_shadowed_);
CodeForReturnPosition(info->function());
frame_->PrepareForReturn();
- Result undefined(Factory::undefined_value());
+ Result undefined(FACTORY->undefined_value());
if (function_return_.is_bound()) {
function_return_.Jump(&undefined);
} else {
@@ -365,9 +365,9 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Process any deferred code using the register allocator.
if (!HasStackOverflow()) {
- JumpTarget::set_compiling_deferred_code(true);
+ info->isolate()->set_jump_target_compiling_deferred_code(true);
ProcessDeferred();
- JumpTarget::set_compiling_deferred_code(false);
+ info->isolate()->set_jump_target_compiling_deferred_code(false);
}
// There is no need to delete the register allocator, it is a
@@ -516,12 +516,12 @@ void CodeGenerator::Load(Expression* expr) {
if (dest.false_was_fall_through()) {
// The false target was just bound.
JumpTarget loaded;
- frame_->Push(Factory::false_value());
+ frame_->Push(FACTORY->false_value());
// There may be dangling jumps to the true target.
if (true_target.is_linked()) {
loaded.Jump();
true_target.Bind();
- frame_->Push(Factory::true_value());
+ frame_->Push(FACTORY->true_value());
loaded.Bind();
}
@@ -529,11 +529,11 @@ void CodeGenerator::Load(Expression* expr) {
// There is true, and possibly false, control flow (with true as
// the fall through).
JumpTarget loaded;
- frame_->Push(Factory::true_value());
+ frame_->Push(FACTORY->true_value());
if (false_target.is_linked()) {
loaded.Jump();
false_target.Bind();
- frame_->Push(Factory::false_value());
+ frame_->Push(FACTORY->false_value());
loaded.Bind();
}
@@ -548,14 +548,14 @@ void CodeGenerator::Load(Expression* expr) {
loaded.Jump(); // Don't lose the current TOS.
if (true_target.is_linked()) {
true_target.Bind();
- frame_->Push(Factory::true_value());
+ frame_->Push(FACTORY->true_value());
if (false_target.is_linked()) {
loaded.Jump();
}
}
if (false_target.is_linked()) {
false_target.Bind();
- frame_->Push(Factory::false_value());
+ frame_->Push(FACTORY->false_value());
}
loaded.Bind();
}
@@ -611,11 +611,13 @@ void CodeGenerator::LoadTypeofExpression(Expression* expr) {
ArgumentsAllocationMode CodeGenerator::ArgumentsMode() {
if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION;
- ASSERT(scope()->arguments_shadow() != NULL);
+
+ // In strict mode there is no need for shadow arguments.
+ ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode());
// We don't want to do lazy arguments allocation for functions that
// have heap-allocated contexts, because it interfers with the
// uninitialized const tracking in the context objects.
- return (scope()->num_heap_slots() > 0)
+ return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode())
? EAGER_ARGUMENTS_ALLOCATION
: LAZY_ARGUMENTS_ALLOCATION;
}
@@ -630,9 +632,11 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) {
// When using lazy arguments allocation, we store the arguments marker value
// as a sentinel indicating that the arguments object hasn't been
// allocated yet.
- frame_->Push(Factory::arguments_marker());
+ frame_->Push(FACTORY->arguments_marker());
} else {
- ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+ ArgumentsAccessStub stub(is_strict_mode()
+ ? ArgumentsAccessStub::NEW_STRICT
+ : ArgumentsAccessStub::NEW_NON_STRICT);
frame_->PushFunction();
frame_->PushReceiverSlotAddress();
frame_->Push(Smi::FromInt(scope()->num_parameters()));
@@ -643,7 +647,9 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) {
Variable* arguments = scope()->arguments();
Variable* shadow = scope()->arguments_shadow();
ASSERT(arguments != NULL && arguments->AsSlot() != NULL);
- ASSERT(shadow != NULL && shadow->AsSlot() != NULL);
+ ASSERT((shadow != NULL && shadow->AsSlot() != NULL) ||
+ scope()->is_strict_mode());
+
JumpTarget done;
bool skip_arguments = false;
if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) {
@@ -666,7 +672,9 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) {
StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT);
if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind();
}
- StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT);
+ if (shadow != NULL) {
+ StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT);
+ }
return frame_->Pop();
}
@@ -760,7 +768,7 @@ void CodeGenerator::ToBoolean(ControlDestination* dest) {
__ AbortIfNotNumber(value.reg());
}
// Smi => false iff zero.
- __ SmiCompare(value.reg(), Smi::FromInt(0));
+ __ Cmp(value.reg(), Smi::FromInt(0));
if (value.is_smi()) {
value.Unuse();
dest->Split(not_zero);
@@ -788,7 +796,7 @@ void CodeGenerator::ToBoolean(ControlDestination* dest) {
dest->false_target()->Branch(equal);
// Smi => false iff zero.
- __ SmiCompare(value.reg(), Smi::FromInt(0));
+ __ Cmp(value.reg(), Smi::FromInt(0));
dest->false_target()->Branch(equal);
Condition is_smi = masm_->CheckSmi(value.reg());
dest->true_target()->Branch(is_smi);
@@ -1030,7 +1038,7 @@ void CodeGenerator::GenericBinaryOperation(BinaryOperation* expr,
true, overwrite_mode);
} else {
// Set the flags based on the operation, type and loop nesting level.
- // Bit operations always assume they likely operate on Smis. Still only
+ // Bit operations always assume they likely operate on smis. Still only
// generate the inline Smi check code if this operation is part of a loop.
// For all other operations only inline the Smi check code for likely smis
// if the operation is part of a loop.
@@ -1054,7 +1062,7 @@ void CodeGenerator::GenericBinaryOperation(BinaryOperation* expr,
bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) {
- Object* answer_object = Heap::undefined_value();
+ Object* answer_object = HEAP->undefined_value();
switch (op) {
case Token::ADD:
// Use intptr_t to detect overflow of 32-bit int.
@@ -1128,7 +1136,7 @@ bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) {
UNREACHABLE();
break;
}
- if (answer_object == Heap::undefined_value()) {
+ if (answer_object->IsUndefined()) {
return false;
}
frame_->Push(Handle<Object>(answer_object));
@@ -1363,7 +1371,7 @@ Result CodeGenerator::LikelySmiBinaryOperation(BinaryOperation* expr,
if (!left_type_info.IsNumber()) {
// Branch if not a heapnumber.
__ Cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
deferred->Branch(not_equal);
}
// Load integer value into answer register using truncation.
@@ -2102,7 +2110,7 @@ void CodeGenerator::Comparison(AstNode* node,
if (cc == equal) {
Label comparison_done;
__ SmiCompare(FieldOperand(left_side.reg(), String::kLengthOffset),
- Smi::FromInt(1));
+ Smi::FromInt(1));
__ j(not_equal, &comparison_done);
uint8_t char_value =
static_cast<uint8_t>(String::cast(*right_val)->Get(0));
@@ -2288,7 +2296,7 @@ void CodeGenerator::ConstantSmiComparison(Condition cc,
// CompareStub and the inline code both support all values of cc.
}
// Implement comparison against a constant Smi, inlining the case
- // where both sides are Smis.
+ // where both sides are smis.
left_side->ToRegister();
Register left_reg = left_side->reg();
Smi* constant_smi = Smi::cast(*right_side->handle());
@@ -2298,7 +2306,6 @@ void CodeGenerator::ConstantSmiComparison(Condition cc,
__ AbortIfNotSmi(left_reg);
}
// Test smi equality and comparison by signed int comparison.
- // Both sides are smis, so we can use an Immediate.
__ SmiCompare(left_reg, constant_smi);
left_side->Unuse();
right_side->Unuse();
@@ -2308,7 +2315,7 @@ void CodeGenerator::ConstantSmiComparison(Condition cc,
JumpTarget is_smi;
if (cc == equal) {
// We can do the equality comparison before the smi check.
- __ SmiCompare(left_reg, constant_smi);
+ __ Cmp(left_reg, constant_smi);
dest->true_target()->Branch(equal);
Condition left_is_smi = masm_->CheckSmi(left_reg);
dest->false_target()->Branch(left_is_smi);
@@ -2326,7 +2333,7 @@ void CodeGenerator::ConstantSmiComparison(Condition cc,
// not to be a smi.
JumpTarget not_number;
__ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
not_number.Branch(not_equal, left_side);
__ movsd(xmm1,
FieldOperand(left_reg, HeapNumber::kValueOffset));
@@ -2486,7 +2493,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
// give us a megamorphic load site. Not super, but it works.
Load(applicand);
frame()->Dup();
- Handle<String> name = Factory::LookupAsciiSymbol("apply");
+ Handle<String> name = FACTORY->LookupAsciiSymbol("apply");
frame()->Push(name);
Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET);
__ nop();
@@ -2554,7 +2561,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
__ j(not_equal, &build_args);
__ movq(rcx, FieldOperand(rax, JSFunction::kCodeEntryOffset));
__ subq(rcx, Immediate(Code::kHeaderSize - kHeapObjectTag));
- Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply));
+ Handle<Code> apply_code = Isolate::Current()->builtins()->FunctionApply();
__ Cmp(rcx, apply_code);
__ j(not_equal, &build_args);
@@ -2569,8 +2576,8 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
// adaptor frame below it.
Label invoke, adapted;
__ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(rdx, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(equal, &adapted);
// No arguments adaptor frame. Copy fixed number of arguments.
@@ -2797,7 +2804,7 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
// If we have a function or a constant, we need to initialize the variable.
Expression* val = NULL;
if (node->mode() == Variable::CONST) {
- val = new Literal(Factory::the_hole_value());
+ val = new Literal(FACTORY->the_hole_value());
} else {
val = node->fun(); // NULL if we don't have a function
}
@@ -3851,7 +3858,7 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
__ movq(rbx, rax);
// If the property has been removed while iterating, we just skip it.
- __ SmiCompare(rbx, Smi::FromInt(0));
+ __ Cmp(rbx, Smi::FromInt(0));
node->continue_target()->Branch(equal);
end_del_check.Bind();
@@ -3973,7 +3980,7 @@ void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
function_return_is_shadowed_ = function_return_was_shadowed;
// Get an external reference to the handler address.
- ExternalReference handler_address(Top::k_handler_address);
+ ExternalReference handler_address(Isolate::k_handler_address, isolate());
// Make sure that there's nothing left on the stack above the
// handler structure.
@@ -4102,7 +4109,7 @@ void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
function_return_is_shadowed_ = function_return_was_shadowed;
// Get an external reference to the handler address.
- ExternalReference handler_address(Top::k_handler_address);
+ ExternalReference handler_address(Isolate::k_handler_address, isolate());
// If we can fall off the end of the try block, unlink from the try
// chain and set the state on the frame to FALLING.
@@ -4255,10 +4262,11 @@ void CodeGenerator::InstantiateFunction(
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
- if (scope()->is_function_scope() &&
- function_info->num_literals() == 0 &&
- !pretenure) {
- FastNewClosureStub stub;
+ if (!pretenure &&
+ scope()->is_function_scope() &&
+ function_info->num_literals() == 0) {
+ FastNewClosureStub stub(
+ function_info->strict_mode() ? kStrictMode : kNonStrictMode);
frame_->Push(function_info);
Result answer = frame_->CallStub(&stub, 1);
frame_->Push(&answer);
@@ -4268,8 +4276,8 @@ void CodeGenerator::InstantiateFunction(
frame_->EmitPush(rsi);
frame_->EmitPush(function_info);
frame_->EmitPush(pretenure
- ? Factory::true_value()
- : Factory::false_value());
+ ? FACTORY->true_value()
+ : FACTORY->false_value());
Result result = frame_->CallRuntime(Runtime::kNewClosure, 3);
frame_->Push(&result);
}
@@ -4754,7 +4762,7 @@ class DeferredAllocateInNewSpace: public DeferredCode {
Register target,
int registers_to_save = 0)
: size_(size), target_(target), registers_to_save_(registers_to_save) {
- ASSERT(size >= kPointerSize && size <= Heap::MaxObjectSizeInNewSpace());
+ ASSERT(size >= kPointerSize && size <= HEAP->MaxObjectSizeInNewSpace());
set_comment("[ DeferredAllocateInNewSpace");
}
void Generate();
@@ -4969,11 +4977,12 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
frame_->Push(node->constant_elements());
int length = node->values()->length();
Result clone;
- if (node->constant_elements()->map() == Heap::fixed_cow_array_map()) {
+ if (node->constant_elements()->map() == HEAP->fixed_cow_array_map()) {
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
clone = frame_->CallStub(&stub, 3);
- __ IncrementCounter(&Counters::cow_arrays_created_stub, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->cow_arrays_created_stub(), 1);
} else if (node->depth() > 1) {
clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
@@ -5371,7 +5380,7 @@ void CodeGenerator::VisitCall(Call* node) {
Load(function);
// Allocate a frame slot for the receiver.
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
// Load the arguments.
int arg_count = args->length();
@@ -5403,7 +5412,7 @@ void CodeGenerator::VisitCall(Call* node) {
if (arg_count > 0) {
frame_->PushElementAt(arg_count);
} else {
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
}
frame_->PushParameterAt(-1);
@@ -5425,7 +5434,7 @@ void CodeGenerator::VisitCall(Call* node) {
if (arg_count > 0) {
frame_->PushElementAt(arg_count);
} else {
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
}
frame_->PushParameterAt(-1);
@@ -5714,7 +5723,7 @@ void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) {
}
#endif
// Finally, we're expected to leave a value on the top of the stack.
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
}
@@ -5977,7 +5986,7 @@ void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
Condition is_smi = masm_->CheckSmi(obj.reg());
destination()->false_target()->Branch(is_smi);
- __ Move(kScratchRegister, Factory::null_value());
+ __ Move(kScratchRegister, FACTORY->null_value());
__ cmpq(obj.reg(), kScratchRegister);
destination()->true_target()->Branch(equal);
@@ -6069,7 +6078,7 @@ class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
__ jmp(&entry);
__ bind(&loop);
__ movq(scratch2_, FieldOperand(map_result_, 0));
- __ Cmp(scratch2_, Factory::value_of_symbol());
+ __ Cmp(scratch2_, FACTORY->value_of_symbol());
__ j(equal, &false_result);
__ addq(map_result_, Immediate(kPointerSize));
__ bind(&entry);
@@ -6192,15 +6201,15 @@ void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
// Skip the arguments adaptor frame if it exists.
Label check_frame_marker;
- __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(not_equal, &check_frame_marker);
__ movq(fp.reg(), Operand(fp.reg(), StandardFrameConstants::kCallerFPOffset));
// Check the marker in the calling frame.
__ bind(&check_frame_marker);
- __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset),
- Smi::FromInt(StackFrame::CONSTRUCT));
+ __ Cmp(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset),
+ Smi::FromInt(StackFrame::CONSTRUCT));
fp.Unuse();
destination()->Split(equal);
}
@@ -6220,8 +6229,8 @@ void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
// Check if the calling frame is an arguments adaptor frame.
__ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(not_equal, &exit);
// Arguments adaptor case: Read the arguments length from the
@@ -6281,17 +6290,17 @@ void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
// Functions have class 'Function'.
function.Bind();
- frame_->Push(Factory::function_class_symbol());
+ frame_->Push(FACTORY->function_class_symbol());
leave.Jump();
// Objects with a non-function constructor have class 'Object'.
non_function_constructor.Bind();
- frame_->Push(Factory::Object_symbol());
+ frame_->Push(FACTORY->Object_symbol());
leave.Jump();
// Non-JS objects have class null.
null.Bind();
- frame_->Push(Factory::null_value());
+ frame_->Push(FACTORY->null_value());
// All done.
leave.Bind();
@@ -6430,7 +6439,7 @@ void CodeGenerator::GenerateRandomHeapNumber(
// Return a random uint32 number in rax.
// The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
__ PrepareCallCFunction(0);
- __ CallCFunction(ExternalReference::random_uint32_function(), 0);
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 0);
// Convert 32 random bits in rax to 0.(32 random bits) in a double
// by computing:
@@ -6660,10 +6669,10 @@ void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) {
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
Handle<FixedArray> jsfunction_result_caches(
- Top::global_context()->jsfunction_result_caches());
+ Isolate::Current()->global_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort("Attempt to use undefined cache.");
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
return;
}
@@ -6777,8 +6786,8 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
// Fetch the map and check if array is in fast case.
// Check that object doesn't require security checks and
// has no indexed interceptor.
- __ CmpObjectType(object.reg(), FIRST_JS_OBJECT_TYPE, tmp1.reg());
- deferred->Branch(below);
+ __ CmpObjectType(object.reg(), JS_ARRAY_TYPE, tmp1.reg());
+ deferred->Branch(not_equal);
__ testb(FieldOperand(tmp1.reg(), Map::kBitFieldOffset),
Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
deferred->Branch(not_zero);
@@ -6820,7 +6829,7 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
Label done;
__ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done);
- // Possible optimization: do a check that both values are Smis
+ // Possible optimization: do a check that both values are smis
// (or them and test against Smi mask.)
__ movq(tmp2.reg(), tmp1.reg());
@@ -6829,7 +6838,7 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
__ bind(&done);
deferred->BindExit();
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
}
@@ -7173,7 +7182,7 @@ void CodeGenerator::GenerateGetCachedArrayIndex(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) {
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
}
@@ -7184,7 +7193,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments();
Comment cmnt(masm_, "[ CallRuntime");
- Runtime::Function* function = node->function();
+ const Runtime::Function* function = node->function();
if (function == NULL) {
// Push the builtins object found in the current global object.
@@ -7268,12 +7277,12 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
} else {
// Default: Result of deleting non-global, not dynamically
// introduced variables is false.
- frame_->Push(Factory::false_value());
+ frame_->Push(FACTORY->false_value());
}
} else {
// Default: Result of deleting expressions is true.
Load(node->expression()); // may have side-effects
- frame_->SetElementAt(0, Factory::true_value());
+ frame_->SetElementAt(0, FACTORY->true_value());
}
} else if (op == Token::TYPEOF) {
@@ -7294,10 +7303,10 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
expression->AsLiteral()->IsNull())) {
// Omit evaluating the value of the primitive literal.
// It will be discarded anyway, and can have no side effect.
- frame_->Push(Factory::undefined_value());
+ frame_->Push(FACTORY->undefined_value());
} else {
Load(node->expression());
- frame_->SetElementAt(0, Factory::undefined_value());
+ frame_->SetElementAt(0, FACTORY->undefined_value());
}
} else {
@@ -7769,7 +7778,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
Result answer = frame_->Pop();
answer.ToRegister();
- if (check->Equals(Heap::number_symbol())) {
+ if (check->Equals(HEAP->number_symbol())) {
Condition is_smi = masm_->CheckSmi(answer.reg());
destination()->true_target()->Branch(is_smi);
frame_->Spill(answer.reg());
@@ -7778,7 +7787,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
answer.Unuse();
destination()->Split(equal);
- } else if (check->Equals(Heap::string_symbol())) {
+ } else if (check->Equals(HEAP->string_symbol())) {
Condition is_smi = masm_->CheckSmi(answer.reg());
destination()->false_target()->Branch(is_smi);
@@ -7792,14 +7801,14 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
answer.Unuse();
destination()->Split(below); // Unsigned byte comparison needed.
- } else if (check->Equals(Heap::boolean_symbol())) {
+ } else if (check->Equals(HEAP->boolean_symbol())) {
__ CompareRoot(answer.reg(), Heap::kTrueValueRootIndex);
destination()->true_target()->Branch(equal);
__ CompareRoot(answer.reg(), Heap::kFalseValueRootIndex);
answer.Unuse();
destination()->Split(equal);
- } else if (check->Equals(Heap::undefined_symbol())) {
+ } else if (check->Equals(HEAP->undefined_symbol())) {
__ CompareRoot(answer.reg(), Heap::kUndefinedValueRootIndex);
destination()->true_target()->Branch(equal);
@@ -7814,7 +7823,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
answer.Unuse();
destination()->Split(not_zero);
- } else if (check->Equals(Heap::function_symbol())) {
+ } else if (check->Equals(HEAP->function_symbol())) {
Condition is_smi = masm_->CheckSmi(answer.reg());
destination()->false_target()->Branch(is_smi);
frame_->Spill(answer.reg());
@@ -7825,7 +7834,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
answer.Unuse();
destination()->Split(equal);
- } else if (check->Equals(Heap::object_symbol())) {
+ } else if (check->Equals(HEAP->object_symbol())) {
Condition is_smi = masm_->CheckSmi(answer.reg());
destination()->false_target()->Branch(is_smi);
__ CompareRoot(answer.reg(), Heap::kNullValueRootIndex);
@@ -7955,7 +7964,7 @@ bool CodeGenerator::HasValidEntryRegisters() {
&& (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0))
&& (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0))
&& (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0))
- && (allocator()->count(r12) == (frame()->is_used(r12) ? 1 : 0));
+ && (allocator()->count(r15) == (frame()->is_used(r15) ? 1 : 0));
}
#endif
@@ -7989,7 +7998,7 @@ void DeferredReferenceGetNamedValue::Generate() {
__ movq(rax, receiver_);
}
__ Move(rcx, name_);
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = Isolate::Current()->builtins()->LoadIC_Initialize();
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a test rax instruction to indicate
// that the inobject property case was inlined.
@@ -8001,7 +8010,8 @@ void DeferredReferenceGetNamedValue::Generate() {
// Here we use masm_-> instead of the __ macro because this is the
// instruction that gets patched and coverage code gets in the way.
masm_->testl(rax, Immediate(-delta_to_patch_site));
- __ IncrementCounter(&Counters::named_load_inline_miss, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->named_load_inline_miss(), 1);
if (!dst_.is(rax)) __ movq(dst_, rax);
}
@@ -8054,7 +8064,7 @@ void DeferredReferenceGetKeyedValue::Generate() {
// it in the IC initialization code and patch the movq instruction.
// This means that we cannot allow test instructions after calls to
// KeyedLoadIC stubs in other places.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = Isolate::Current()->builtins()->KeyedLoadIC_Initialize();
__ Call(ic, RelocInfo::CODE_TARGET);
// The delta from the start of the map-compare instruction to the
// test instruction. We use masm_-> directly here instead of the __
@@ -8068,7 +8078,8 @@ void DeferredReferenceGetKeyedValue::Generate() {
// 7-byte NOP with non-zero immediate (0f 1f 80 xxxxxxxx) which won't
// be generated normally.
masm_->testl(rax, Immediate(-delta_to_patch_site));
- __ IncrementCounter(&Counters::keyed_load_inline_miss, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_inline_miss(), 1);
if (!dst_.is(rax)) __ movq(dst_, rax);
}
@@ -8101,7 +8112,8 @@ class DeferredReferenceSetKeyedValue: public DeferredCode {
void DeferredReferenceSetKeyedValue::Generate() {
- __ IncrementCounter(&Counters::keyed_store_inline_miss, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->keyed_store_inline_miss(), 1);
// Move value, receiver, and key to registers rax, rdx, and rcx, as
// the IC stub expects.
// Move value to rax, using xchg if the receiver or key is in rax.
@@ -8148,9 +8160,9 @@ void DeferredReferenceSetKeyedValue::Generate() {
}
// Call the IC stub.
- Handle<Code> ic(Builtins::builtin(
- (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ (strict_mode_ == kStrictMode) ? Builtins::kKeyedStoreIC_Initialize_Strict
+ : Builtins::kKeyedStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// The delta from the start of the map-compare instructions (initial movq)
// to the test instruction. We use masm_-> directly here instead of the
@@ -8195,17 +8207,9 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
result = allocator()->Allocate();
ASSERT(result.is_valid());
- // Cannot use r12 for receiver, because that changes
- // the distance between a call and a fixup location,
- // due to a special encoding of r12 as r/m in a ModR/M byte.
- if (receiver.reg().is(r12)) {
- frame()->Spill(receiver.reg()); // It will be overwritten with result.
- // Swap receiver and value.
- __ movq(result.reg(), receiver.reg());
- Result temp = receiver;
- receiver = result;
- result = temp;
- }
+ // r12 is now a reserved register, so it cannot be the receiver.
+ // If it was, the distance to the fixup location would not be constant.
+ ASSERT(!receiver.reg().is(r12));
DeferredReferenceGetNamedValue* deferred =
new DeferredReferenceGetNamedValue(result.reg(), receiver.reg(), name);
@@ -8217,7 +8221,7 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
// This is the map check instruction that will be patched (so we can't
// use the double underscore macro that may insert instructions).
// Initially use an invalid map to force a failure.
- masm()->movq(kScratchRegister, Factory::null_value(),
+ masm()->movq(kScratchRegister, FACTORY->null_value(),
RelocInfo::EMBEDDED_OBJECT);
masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
kScratchRegister);
@@ -8236,7 +8240,8 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
int offset = kMaxInt;
masm()->movq(result.reg(), FieldOperand(receiver.reg(), offset));
- __ IncrementCounter(&Counters::named_load_inline, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->named_load_inline(), 1);
deferred->BindExit();
}
ASSERT(frame()->height() == original_height - 1);
@@ -8294,7 +8299,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
// the __ macro for the following two instructions because it
// might introduce extra instructions.
__ bind(&patch_site);
- masm()->movq(kScratchRegister, Factory::null_value(),
+ masm()->movq(kScratchRegister, FACTORY->null_value(),
RelocInfo::EMBEDDED_OBJECT);
masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
kScratchRegister);
@@ -8408,7 +8413,7 @@ Result CodeGenerator::EmitKeyedLoad() {
// coverage code can interfere with the patching. Do not use a load
// from the root array to load null_value, since the load must be patched
// with the expected receiver map, which is not in the root array.
- masm_->movq(kScratchRegister, Factory::null_value(),
+ masm_->movq(kScratchRegister, FACTORY->null_value(),
RelocInfo::EMBEDDED_OBJECT);
masm_->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
kScratchRegister);
@@ -8443,7 +8448,8 @@ Result CodeGenerator::EmitKeyedLoad() {
result = elements;
__ CompareRoot(result.reg(), Heap::kTheHoleValueRootIndex);
deferred->Branch(equal);
- __ IncrementCounter(&Counters::keyed_load_inline, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_inline(), 1);
deferred->BindExit();
} else {
@@ -8510,12 +8516,6 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
__ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister);
deferred->Branch(not_equal);
- // Check that the key is within bounds. Both the key and the length of
- // the JSArray are smis. Use unsigned comparison to handle negative keys.
- __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset),
- key.reg());
- deferred->Branch(below_equal);
-
// Get the elements array from the receiver and check that it is not a
// dictionary.
__ movq(tmp.reg(),
@@ -8538,12 +8538,20 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
__ bind(deferred->patch_site());
// Avoid using __ to ensure the distance from patch_site
// to the map address is always the same.
- masm()->movq(kScratchRegister, Factory::fixed_array_map(),
+ masm()->movq(kScratchRegister, FACTORY->fixed_array_map(),
RelocInfo::EMBEDDED_OBJECT);
__ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset),
kScratchRegister);
deferred->Branch(not_equal);
+ // Check that the key is within bounds. Both the key and the length of
+ // the JSArray are smis (because the fixed array check above ensures the
+ // elements are in fast case). Use unsigned comparison to handle negative
+ // keys.
+ __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset),
+ key.reg());
+ deferred->Branch(below_equal);
+
// Store the value.
SmiIndex index =
masm()->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2);
@@ -8552,7 +8560,8 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
index.scale,
FixedArray::kHeaderSize),
result.reg());
- __ IncrementCounter(&Counters::keyed_store_inline, 1);
+ Counters* counters = masm()->isolate()->counters();
+ __ IncrementCounter(counters->keyed_store_inline(), 1);
deferred->BindExit();
} else {
diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h
index 43928291..9a70907c 100644
--- a/src/x64/codegen-x64.h
+++ b/src/x64/codegen-x64.h
@@ -357,6 +357,7 @@ class CodeGenerator: public AstVisitor {
// Accessors
inline bool is_eval();
inline Scope* scope();
+ inline bool is_strict_mode();
inline StrictModeFlag strict_mode_flag();
// Generating deferred code.
@@ -732,6 +733,7 @@ class CodeGenerator: public AstVisitor {
bool in_spilled_code_;
friend class VirtualFrame;
+ friend class Isolate;
friend class JumpTarget;
friend class Reference;
friend class Result;
@@ -740,6 +742,7 @@ class CodeGenerator: public AstVisitor {
friend class FullCodeGenSyntaxChecker;
friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc
+ friend class InlineRuntimeFunctionsTable;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
diff --git a/src/x64/cpu-x64.cc b/src/x64/cpu-x64.cc
index 3ff292e8..b49fb1c4 100644
--- a/src/x64/cpu-x64.cc
+++ b/src/x64/cpu-x64.cc
@@ -42,7 +42,7 @@ namespace v8 {
namespace internal {
void CPU::Setup() {
- CpuFeatures::Probe(true);
+ Isolate::Current()->cpu_features()->Probe(true);
if (Serializer::enabled()) {
V8::DisableCrankshaft();
}
diff --git a/src/x64/debug-x64.cc b/src/x64/debug-x64.cc
index 2c50ddd1..03984651 100644
--- a/src/x64/debug-x64.cc
+++ b/src/x64/debug-x64.cc
@@ -49,7 +49,8 @@ bool BreakLocationIterator::IsDebugBreakAtReturn() {
void BreakLocationIterator::SetDebugBreakAtReturn() {
ASSERT(Assembler::kJSReturnSequenceLength >=
Assembler::kCallInstructionLength);
- rinfo()->PatchCodeWithCall(Debug::debug_break_return()->entry(),
+ rinfo()->PatchCodeWithCall(
+ Isolate::Current()->debug()->debug_break_return()->entry(),
Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
}
@@ -79,7 +80,7 @@ bool BreakLocationIterator::IsDebugBreakAtSlot() {
void BreakLocationIterator::SetDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
rinfo()->PatchCodeWithCall(
- Debug::debug_break_slot()->entry(),
+ Isolate::Current()->debug()->debug_break_slot()->entry(),
Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
}
@@ -128,7 +129,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ Set(rax, 0); // No arguments (argc == 0).
- __ movq(rbx, ExternalReference::debug_break());
+ __ movq(rbx, ExternalReference::debug_break(masm->isolate()));
CEntryStub ceb(1);
__ CallStub(&ceb);
@@ -167,7 +168,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
// jumping to the target address intended by the caller and that was
// overwritten by the address of DebugBreakXXX.
ExternalReference after_break_target =
- ExternalReference(Debug_Address::AfterBreakTarget());
+ ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate());
__ movq(kScratchRegister, after_break_target);
__ jmp(Operand(kScratchRegister, 0));
}
@@ -283,7 +284,8 @@ void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
ExternalReference restarter_frame_function_slot =
- ExternalReference(Debug_Address::RestarterFrameFunctionPointer());
+ ExternalReference(Debug_Address::RestarterFrameFunctionPointer(),
+ masm->isolate());
__ movq(rax, restarter_frame_function_slot);
__ movq(Operand(rax, 0), Immediate(0));
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index daa91280..2080c615 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -101,7 +101,13 @@ class SafepointTableDeoptimiztionEntryIterator {
};
+void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
+ // TODO(1276): Implement.
+}
+
+
void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
+ HandleScope scope;
AssertNoAllocation no_allocation;
if (!function->IsOptimized()) return;
@@ -186,8 +192,9 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
// Add the deoptimizing code to the list.
DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
- node->set_next(deoptimizing_code_list_);
- deoptimizing_code_list_ = node;
+ DeoptimizerData* data = code->GetIsolate()->deoptimizer_data();
+ node->set_next(data->deoptimizing_code_list_);
+ data->deoptimizing_code_list_ = node;
// Set the code for the function to non-optimized version.
function->ReplaceCode(function->shared()->code());
@@ -196,6 +203,11 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
PrintF("[forced deoptimization: ");
function->PrintName();
PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
+#ifdef DEBUG
+ if (FLAG_print_code) {
+ code->PrintLn();
+ }
+#endif
}
}
@@ -349,13 +361,32 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
// There are no translation commands for the caller's pc and fp, the
// context, and the function. Set them up explicitly.
- for (int i = 0; ok && i < 4; i++) {
+ for (int i = StandardFrameConstants::kCallerPCOffset;
+ ok && i >= StandardFrameConstants::kMarkerOffset;
+ i -= kPointerSize) {
intptr_t input_value = input_->GetFrameSlot(input_offset);
if (FLAG_trace_osr) {
- PrintF(" [esp + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] (fixed part)\n",
+ const char* name = "UNKNOWN";
+ switch (i) {
+ case StandardFrameConstants::kCallerPCOffset:
+ name = "caller's pc";
+ break;
+ case StandardFrameConstants::kCallerFPOffset:
+ name = "fp";
+ break;
+ case StandardFrameConstants::kContextOffset:
+ name = "context";
+ break;
+ case StandardFrameConstants::kMarkerOffset:
+ name = "function";
+ break;
+ }
+ PrintF(" [rsp + %d] <- 0x%08" V8PRIxPTR " ; [rsp + %d] "
+ "(fixed part - %s)\n",
output_offset,
input_value,
- input_offset);
+ input_offset,
+ name);
}
output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
input_offset -= kPointerSize;
@@ -382,7 +413,8 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
optimized_code_->entry() + pc_offset);
output_[0]->SetPc(pc);
}
- Code* continuation = Builtins::builtin(Builtins::NotifyOSR);
+ Code* continuation =
+ function->GetIsolate()->builtins()->builtin(Builtins::kNotifyOSR);
output_[0]->SetContinuation(
reinterpret_cast<intptr_t>(continuation->entry()));
@@ -554,8 +586,8 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
// Set the continuation for the topmost frame.
if (is_topmost) {
Code* continuation = (bailout_type_ == EAGER)
- ? Builtins::builtin(Builtins::NotifyDeoptimized)
- : Builtins::builtin(Builtins::NotifyLazyDeoptimized);
+ ? isolate_->builtins()->builtin(Builtins::kNotifyDeoptimized)
+ : isolate_->builtins()->builtin(Builtins::kNotifyLazyDeoptimized);
output_frame->SetContinuation(
reinterpret_cast<intptr_t>(continuation->entry()));
}
@@ -645,7 +677,9 @@ void Deoptimizer::EntryGenerator::Generate() {
__ movq(r8, arg5);
#endif
- __ CallCFunction(ExternalReference::new_deoptimizer_function(), 5);
+ Isolate* isolate = masm()->isolate();
+
+ __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 5);
// Preserve deoptimizer object in register rax and get the input
// frame descriptor pointer.
__ movq(rbx, Operand(rax, Deoptimizer::input_offset()));
@@ -690,7 +724,8 @@ void Deoptimizer::EntryGenerator::Generate() {
__ push(rax);
__ PrepareCallCFunction(1);
__ movq(arg1, rax);
- __ CallCFunction(ExternalReference::compute_output_frames_function(), 1);
+ __ CallCFunction(
+ ExternalReference::compute_output_frames_function(isolate), 1);
__ pop(rax);
// Replace the current frame with the output frames.
@@ -748,7 +783,6 @@ void Deoptimizer::EntryGenerator::Generate() {
}
// Set up the roots register.
- ExternalReference roots_address = ExternalReference::roots_address();
__ InitializeRootRegister();
__ InitializeSmiConstantRegister();
diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc
index 21a100f5..189ee42c 100644
--- a/src/x64/disasm-x64.cc
+++ b/src/x64/disasm-x64.cc
@@ -269,6 +269,7 @@ void InstructionTable::AddJumpConditionalShort() {
static InstructionTable instruction_table;
+
static InstructionDesc cmov_instructions[16] = {
{"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
{"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
@@ -451,9 +452,11 @@ void DisassemblerX64::AppendToBuffer(const char* format, ...) {
int DisassemblerX64::PrintRightOperandHelper(
byte* modrmp,
- RegisterNameMapping register_name) {
+ RegisterNameMapping direct_register_name) {
int mod, regop, rm;
get_modrm(*modrmp, &mod, &regop, &rm);
+ RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
+ &DisassemblerX64::NameOfCPURegister;
switch (mod) {
case 0:
if ((rm & 7) == 5) {
@@ -1028,7 +1031,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
} else if (opcode == 0x6F) {
AppendToBuffer("movdqa %s,",
NameOfXMMRegister(regop));
- current += PrintRightOperand(current);
+ current += PrintRightXMMOperand(current);
} else if (opcode == 0x7E) {
AppendToBuffer("mov%c ",
rex_w() ? 'q' : 'd');
@@ -1036,7 +1039,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
AppendToBuffer(", %s", NameOfXMMRegister(regop));
} else if (opcode == 0x7F) {
AppendToBuffer("movdqa ");
- current += PrintRightOperand(current);
+ current += PrintRightXMMOperand(current);
AppendToBuffer(", %s", NameOfXMMRegister(regop));
} else {
const char* mnemonic = "?";
@@ -1068,11 +1071,11 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
int mod, regop, rm;
get_modrm(*current, &mod, &regop, &rm);
if (opcode == 0x11) {
- current += PrintRightOperand(current);
+ current += PrintRightXMMOperand(current);
AppendToBuffer(",%s", NameOfXMMRegister(regop));
} else {
AppendToBuffer("%s,", NameOfXMMRegister(regop));
- current += PrintRightOperand(current);
+ current += PrintRightXMMOperand(current);
}
} else if (opcode == 0x2A) {
// CVTSI2SD: integer to XMM double conversion.
@@ -1435,19 +1438,26 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
{
bool is_byte = *data == 0xC6;
data++;
-
- AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
- data += PrintRightOperand(data);
- int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
- AppendToBuffer(",0x%x", imm);
- data += is_byte ? 1 : 4;
+ if (is_byte) {
+ AppendToBuffer("movb ");
+ data += PrintRightByteOperand(data);
+ int32_t imm = *data;
+ AppendToBuffer(",0x%x", imm);
+ data++;
+ } else {
+ AppendToBuffer("mov%c ", operand_size_code());
+ data += PrintRightOperand(data);
+ int32_t imm = *reinterpret_cast<int32_t*>(data);
+ AppendToBuffer(",0x%x", imm);
+ data += 4;
+ }
}
break;
case 0x80: {
data++;
AppendToBuffer("cmpb ");
- data += PrintRightOperand(data);
+ data += PrintRightByteOperand(data);
int32_t imm = *data;
AppendToBuffer(",0x%x", imm);
data++;
@@ -1461,9 +1471,15 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
int mod, regop, rm;
data++;
get_modrm(*data, &mod, &regop, &rm);
- AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
- data += PrintRightOperand(data);
- AppendToBuffer(",%s", NameOfCPURegister(regop));
+ if (is_byte) {
+ AppendToBuffer("movb ");
+ data += PrintRightByteOperand(data);
+ AppendToBuffer(",%s", NameOfByteCPURegister(regop));
+ } else {
+ AppendToBuffer("mov%c ", operand_size_code());
+ data += PrintRightOperand(data);
+ AppendToBuffer(",%s", NameOfCPURegister(regop));
+ }
}
break;
@@ -1493,7 +1509,7 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
get_modrm(*data, &mod, &regop, &rm);
if (regop == 1) {
AppendToBuffer("decb ");
- data += PrintRightOperand(data);
+ data += PrintRightByteOperand(data);
} else {
UnimplementedInstruction();
}
@@ -1652,9 +1668,8 @@ static const char* xmm_regs[16] = {
const char* NameConverter::NameOfAddress(byte* addr) const {
- static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
- v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
- return tmp_buffer.start();
+ v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
+ return tmp_buffer_.start();
}
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 780f4b02..90afd857 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -198,13 +198,18 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous
// stack frame was an arguments adapter frame.
- ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+ ArgumentsAccessStub stub(
+ is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
+ : ArgumentsAccessStub::NEW_NON_STRICT);
__ CallStub(&stub);
- // Store new arguments object in both "arguments" and ".arguments" slots.
- __ movq(rcx, rax);
+
+ Variable* arguments_shadow = scope()->arguments_shadow();
+ if (arguments_shadow != NULL) {
+ // Store new arguments object in both "arguments" and ".arguments" slots.
+ __ movq(rcx, rax);
+ Move(arguments_shadow->AsSlot(), rcx, rbx, rdx);
+ }
Move(arguments->AsSlot(), rax, rbx, rdx);
- Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
- Move(dot_arguments_slot, rcx, rbx, rdx);
}
if (FLAG_trace) {
@@ -476,10 +481,10 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(
Label* materialize_false) const {
NearLabel done;
__ bind(materialize_true);
- __ Move(result_register(), Factory::true_value());
+ __ Move(result_register(), isolate()->factory()->true_value());
__ jmp(&done);
__ bind(materialize_false);
- __ Move(result_register(), Factory::false_value());
+ __ Move(result_register(), isolate()->factory()->false_value());
__ bind(&done);
}
@@ -489,10 +494,10 @@ void FullCodeGenerator::StackValueContext::Plug(
Label* materialize_false) const {
NearLabel done;
__ bind(materialize_true);
- __ Push(Factory::true_value());
+ __ Push(isolate()->factory()->true_value());
__ jmp(&done);
__ bind(materialize_false);
- __ Push(Factory::false_value());
+ __ Push(isolate()->factory()->false_value());
__ bind(&done);
}
@@ -546,7 +551,7 @@ void FullCodeGenerator::DoTest(Label* if_true,
__ CompareRoot(result_register(), Heap::kFalseValueRootIndex);
__ j(equal, if_false);
STATIC_ASSERT(kSmiTag == 0);
- __ SmiCompare(result_register(), Smi::FromInt(0));
+ __ Cmp(result_register(), Smi::FromInt(0));
__ j(equal, if_false);
Condition is_smi = masm_->CheckSmi(result_register());
__ j(is_smi, if_true);
@@ -735,9 +740,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
prop->key()->AsLiteral()->handle()->IsSmi());
__ Move(rcx, prop->key()->AsLiteral()->handle());
- Handle<Code> ic(Builtins::builtin(is_strict()
- ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
}
}
@@ -834,6 +839,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
Comment cmnt(masm_, "[ Case body");
CaseClause* clause = clauses->at(i);
__ bind(clause->body_target()->entry_label());
+ PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
VisitStatements(clause->statements());
}
@@ -991,7 +997,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ push(rcx); // Enumerable.
__ push(rbx); // Current entry.
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
- __ SmiCompare(rax, Smi::FromInt(0));
+ __ Cmp(rax, Smi::FromInt(0));
__ j(equal, loop_statement.continue_target());
__ movq(rbx, rax);
@@ -1035,16 +1041,18 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
// doesn't just get a copy of the existing unoptimized code.
if (!FLAG_always_opt &&
!FLAG_prepare_always_opt &&
+ !pretenure &&
scope()->is_function_scope() &&
- info->num_literals() == 0 &&
- !pretenure) {
- FastNewClosureStub stub;
+ info->num_literals() == 0) {
+ FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
__ Push(info);
__ CallStub(&stub);
} else {
__ push(rsi);
__ Push(info);
- __ Push(pretenure ? Factory::true_value() : Factory::false_value());
+ __ Push(pretenure
+ ? isolate()->factory()->true_value()
+ : isolate()->factory()->false_value());
__ CallRuntime(Runtime::kNewClosure, 3);
}
context()->Plug(rax);
@@ -1113,7 +1121,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
// load IC call.
__ movq(rax, GlobalObjectOperand());
__ Move(rcx, slot->var()->name());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
@@ -1196,7 +1204,8 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
slow));
__ Move(rax, key_literal->handle());
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic =
+ isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
__ jmp(done);
}
@@ -1219,7 +1228,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
// object on the stack.
__ Move(rcx, var->name());
__ movq(rax, GlobalObjectOperand());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(rax);
@@ -1282,7 +1291,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
__ Move(rax, key_literal->handle());
// Do a keyed property load.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
context()->Plug(rax);
}
@@ -1349,7 +1358,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
__ Push(Smi::FromInt(expr->literal_index()));
__ Push(expr->constant_properties());
- __ Push(Smi::FromInt(expr->fast_elements() ? 1 : 0));
+ int flags = expr->fast_elements()
+ ? ObjectLiteral::kFastElements
+ : ObjectLiteral::kNoFlags;
+ flags |= expr->has_function()
+ ? ObjectLiteral::kHasFunction
+ : ObjectLiteral::kNoFlags;
+ __ Push(Smi::FromInt(flags));
if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateObjectLiteral, 4);
} else {
@@ -1387,7 +1402,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Move(rcx, key->handle());
__ movq(rdx, Operand(rsp, 0));
if (property->emit_store()) {
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(key->id(), NO_REGISTERS);
}
@@ -1418,6 +1433,12 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
}
+ if (expr->has_function()) {
+ ASSERT(result_saved);
+ __ push(Operand(rsp, 0));
+ __ CallRuntime(Runtime::kToFastProperties, 1);
+ }
+
if (result_saved) {
context()->PlugTOS();
} else {
@@ -1436,11 +1457,12 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
__ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
__ Push(Smi::FromInt(expr->literal_index()));
__ Push(expr->constant_elements());
- if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
+ if (expr->constant_elements()->map() ==
+ isolate()->heap()->fixed_cow_array_map()) {
FastCloneShallowArrayStub stub(
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
__ CallStub(&stub);
- __ IncrementCounter(&Counters::cow_arrays_created_stub, 1);
+ __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
} else if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
@@ -1624,14 +1646,14 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral();
__ Move(rcx, key->handle());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
}
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
}
@@ -1737,9 +1759,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
__ movq(rdx, rax);
__ pop(rax); // Restore value.
__ Move(rcx, prop->key()->AsLiteral()->handle());
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
break;
}
@@ -1760,9 +1782,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
__ pop(rdx);
}
__ pop(rax); // Restore value.
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
break;
}
@@ -1786,9 +1808,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// rcx, and the global object on the stack.
__ Move(rcx, var->name());
__ movq(rdx, GlobalObjectOperand());
- Handle<Code> ic(Builtins::builtin(is_strict()
- ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
@@ -1889,9 +1911,9 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
} else {
__ pop(rdx);
}
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// If the assignment ends an initialization block, revert to fast case.
@@ -1929,9 +1951,9 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
}
// Record source code position before IC call.
SetSourcePosition(expr->position());
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// If the assignment ends an initialization block, revert to fast case.
@@ -1982,7 +2004,8 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
SetSourcePosition(expr->position());
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
+ Handle<Code> ic =
+ ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop);
EmitCallIC(ic, mode);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2015,7 +2038,8 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
SetSourcePosition(expr->position());
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
+ Handle<Code> ic =
+ ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
__ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, mode);
RecordJSReturnSite(expr);
@@ -2208,7 +2232,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Record source code position for IC call.
SetSourcePosition(prop->position());
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Push result (function).
__ push(rax);
@@ -2229,7 +2253,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// also use the full code generator.
FunctionLiteral* lit = fun->AsFunctionLiteral();
if (lit != NULL &&
- lit->name()->Equals(Heap::empty_string()) &&
+ lit->name()->Equals(isolate()->heap()->empty_string()) &&
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
@@ -2276,7 +2300,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ Set(rax, arg_count);
__ movq(rdi, Operand(rsp, arg_count * kPointerSize));
- Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> construct_builtin =
+ isolate()->builtins()->JSConstructCall();
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
context()->Plug(rax);
}
@@ -2498,15 +2523,15 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
// Skip the arguments adaptor frame if it exists.
Label check_frame_marker;
- __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(not_equal, &check_frame_marker);
__ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
// Check the marker in the calling frame.
__ bind(&check_frame_marker);
- __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset),
- Smi::FromInt(StackFrame::CONSTRUCT));
+ __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
+ Smi::FromInt(StackFrame::CONSTRUCT));
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Split(equal, if_true, if_false, fall_through);
@@ -2560,8 +2585,8 @@ void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
// Check if the calling frame is an arguments adaptor frame.
__ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(not_equal, &exit);
// Arguments adaptor case: Read the arguments length from the
@@ -2609,12 +2634,12 @@ void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
// Functions have class 'Function'.
__ bind(&function);
- __ Move(rax, Factory::function_class_symbol());
+ __ Move(rax, isolate()->factory()->function_class_symbol());
__ jmp(&done);
// Objects with a non-function constructor have class 'Object'.
__ bind(&non_function_constructor);
- __ Move(rax, Factory::Object_symbol());
+ __ Move(rax, isolate()->factory()->Object_symbol());
__ jmp(&done);
// Non-JS objects have class null.
@@ -2669,7 +2694,7 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
// Return a random uint32 number in rax.
// The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
__ PrepareCallCFunction(0);
- __ CallCFunction(ExternalReference::random_uint32_function(), 0);
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 0);
// Convert 32 random bits in rax to 0.(32 random bits) in a double
// by computing:
@@ -3006,8 +3031,8 @@ void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
// Fetch the map and check if array is in fast case.
// Check that object doesn't require security checks and
// has no indexed interceptor.
- __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp);
- __ j(below, &slow_case);
+ __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
+ __ j(not_equal, &slow_case);
__ testb(FieldOperand(temp, Map::kBitFieldOffset),
Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
__ j(not_zero, &slow_case);
@@ -3073,7 +3098,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
Handle<FixedArray> jsfunction_result_caches(
- Top::global_context()->jsfunction_result_caches());
+ isolate()->global_context()->jsfunction_result_caches());
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort("Attempt to use undefined cache.");
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
@@ -3150,10 +3175,10 @@ void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
__ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset));
__ j(equal, &ok);
__ bind(&fail);
- __ Move(rax, Factory::false_value());
+ __ Move(rax, isolate()->factory()->false_value());
__ jmp(&done);
__ bind(&ok);
- __ Move(rax, Factory::true_value());
+ __ Move(rax, isolate()->factory()->true_value());
__ bind(&done);
context()->Plug(rax);
@@ -3199,7 +3224,288 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
- context()->Plug(Heap::kUndefinedValueRootIndex);
+ Label bailout, return_result, done, one_char_separator, long_separator,
+ non_trivial_array, not_size_one_array, loop,
+ loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
+ ASSERT(args->length() == 2);
+ // We will leave the separator on the stack until the end of the function.
+ VisitForStackValue(args->at(1));
+ // Load this to rax (= array)
+ VisitForAccumulatorValue(args->at(0));
+ // All aliases of the same register have disjoint lifetimes.
+ Register array = rax;
+ Register elements = no_reg; // Will be rax.
+
+ Register index = rdx;
+
+ Register string_length = rcx;
+
+ Register string = rsi;
+
+ Register scratch = rbx;
+
+ Register array_length = rdi;
+ Register result_pos = no_reg; // Will be rdi.
+
+ Operand separator_operand = Operand(rsp, 2 * kPointerSize);
+ Operand result_operand = Operand(rsp, 1 * kPointerSize);
+ Operand array_length_operand = Operand(rsp, 0 * kPointerSize);
+ // Separator operand is already pushed. Make room for the two
+ // other stack fields, and clear the direction flag in anticipation
+ // of calling CopyBytes.
+ __ subq(rsp, Immediate(2 * kPointerSize));
+ __ cld();
+ // Check that the array is a JSArray
+ __ JumpIfSmi(array, &bailout);
+ __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
+ __ j(not_equal, &bailout);
+
+ // Check that the array has fast elements.
+ __ testb(FieldOperand(scratch, Map::kBitField2Offset),
+ Immediate(1 << Map::kHasFastElements));
+ __ j(zero, &bailout);
+
+ // Array has fast elements, so its length must be a smi.
+ // If the array has length zero, return the empty string.
+ __ movq(array_length, FieldOperand(array, JSArray::kLengthOffset));
+ __ SmiCompare(array_length, Smi::FromInt(0));
+ __ j(not_zero, &non_trivial_array);
+ __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
+ __ jmp(&return_result);
+
+ // Save the array length on the stack.
+ __ bind(&non_trivial_array);
+ __ SmiToInteger32(array_length, array_length);
+ __ movl(array_length_operand, array_length);
+
+ // Save the FixedArray containing array's elements.
+ // End of array's live range.
+ elements = array;
+ __ movq(elements, FieldOperand(array, JSArray::kElementsOffset));
+ array = no_reg;
+
+
+ // Check that all array elements are sequential ASCII strings, and
+ // accumulate the sum of their lengths, as a smi-encoded value.
+ __ Set(index, 0);
+ __ Set(string_length, 0);
+ // Loop condition: while (index < array_length).
+ // Live loop registers: index(int32), array_length(int32), string(String*),
+ // scratch, string_length(int32), elements(FixedArray*).
+ if (FLAG_debug_code) {
+ __ cmpq(index, array_length);
+ __ Assert(below, "No empty arrays here in EmitFastAsciiArrayJoin");
+ }
+ __ bind(&loop);
+ __ movq(string, FieldOperand(elements,
+ index,
+ times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ JumpIfSmi(string, &bailout);
+ __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+ __ andb(scratch, Immediate(
+ kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
+ __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
+ __ j(not_equal, &bailout);
+ __ AddSmiField(string_length,
+ FieldOperand(string, SeqAsciiString::kLengthOffset));
+ __ j(overflow, &bailout);
+ __ incl(index);
+ __ cmpl(index, array_length);
+ __ j(less, &loop);
+
+ // Live registers:
+ // string_length: Sum of string lengths.
+ // elements: FixedArray of strings.
+ // index: Array length.
+ // array_length: Array length.
+
+ // If array_length is 1, return elements[0], a string.
+ __ cmpl(array_length, Immediate(1));
+ __ j(not_equal, &not_size_one_array);
+ __ movq(rax, FieldOperand(elements, FixedArray::kHeaderSize));
+ __ jmp(&return_result);
+
+ __ bind(&not_size_one_array);
+
+ // End of array_length live range.
+ result_pos = array_length;
+ array_length = no_reg;
+
+ // Live registers:
+ // string_length: Sum of string lengths.
+ // elements: FixedArray of strings.
+ // index: Array length.
+
+ // Check that the separator is a sequential ASCII string.
+ __ movq(string, separator_operand);
+ __ JumpIfSmi(string, &bailout);
+ __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+ __ andb(scratch, Immediate(
+ kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
+ __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag));
+ __ j(not_equal, &bailout);
+
+ // Live registers:
+ // string_length: Sum of string lengths.
+ // elements: FixedArray of strings.
+ // index: Array length.
+ // string: Separator string.
+
+ // Add (separator length times (array_length - 1)) to string_length.
+ __ SmiToInteger32(scratch,
+ FieldOperand(string, SeqAsciiString::kLengthOffset));
+ __ decl(index);
+ __ imull(scratch, index);
+ __ j(overflow, &bailout);
+ __ addl(string_length, scratch);
+ __ j(overflow, &bailout);
+
+ // Live registers and stack values:
+ // string_length: Total length of result string.
+ // elements: FixedArray of strings.
+ __ AllocateAsciiString(result_pos, string_length, scratch,
+ index, string, &bailout);
+ __ movq(result_operand, result_pos);
+ __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize));
+
+ __ movq(string, separator_operand);
+ __ SmiCompare(FieldOperand(string, SeqAsciiString::kLengthOffset),
+ Smi::FromInt(1));
+ __ j(equal, &one_char_separator);
+ __ j(greater, &long_separator);
+
+
+ // Empty separator case:
+ __ Set(index, 0);
+ __ movl(scratch, array_length_operand);
+ __ jmp(&loop_1_condition);
+ // Loop condition: while (index < array_length).
+ __ bind(&loop_1);
+ // Each iteration of the loop concatenates one string to the result.
+ // Live values in registers:
+ // index: which element of the elements array we are adding to the result.
+ // result_pos: the position to which we are currently copying characters.
+ // elements: the FixedArray of strings we are joining.
+ // scratch: array length.
+
+ // Get string = array[index].
+ __ movq(string, FieldOperand(elements, index,
+ times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ SmiToInteger32(string_length,
+ FieldOperand(string, String::kLengthOffset));
+ __ lea(string,
+ FieldOperand(string, SeqAsciiString::kHeaderSize));
+ __ CopyBytes(result_pos, string, string_length);
+ __ incl(index);
+ __ bind(&loop_1_condition);
+ __ cmpl(index, scratch);
+ __ j(less, &loop_1); // Loop while (index < array_length).
+ __ jmp(&done);
+
+ // Generic bailout code used from several places.
+ __ bind(&bailout);
+ __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
+ __ jmp(&return_result);
+
+
+ // One-character separator case
+ __ bind(&one_char_separator);
+ // Get the separator ascii character value.
+ // Register "string" holds the separator.
+ __ movzxbl(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
+ __ Set(index, 0);
+ // Jump into the loop after the code that copies the separator, so the first
+ // element is not preceded by a separator
+ __ jmp(&loop_2_entry);
+ // Loop condition: while (index < length).
+ __ bind(&loop_2);
+ // Each iteration of the loop concatenates one string to the result.
+ // Live values in registers:
+ // elements: The FixedArray of strings we are joining.
+ // index: which element of the elements array we are adding to the result.
+ // result_pos: the position to which we are currently copying characters.
+ // scratch: Separator character.
+
+ // Copy the separator character to the result.
+ __ movb(Operand(result_pos, 0), scratch);
+ __ incq(result_pos);
+
+ __ bind(&loop_2_entry);
+ // Get string = array[index].
+ __ movq(string, FieldOperand(elements, index,
+ times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ SmiToInteger32(string_length,
+ FieldOperand(string, String::kLengthOffset));
+ __ lea(string,
+ FieldOperand(string, SeqAsciiString::kHeaderSize));
+ __ CopyBytes(result_pos, string, string_length);
+ __ incl(index);
+ __ cmpl(index, array_length_operand);
+ __ j(less, &loop_2); // End while (index < length).
+ __ jmp(&done);
+
+
+ // Long separator case (separator is more than one character).
+ __ bind(&long_separator);
+
+ // Make elements point to end of elements array, and index
+ // count from -array_length to zero, so we don't need to maintain
+ // a loop limit.
+ __ movl(index, array_length_operand);
+ __ lea(elements, FieldOperand(elements, index, times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ neg(index);
+
+ // Replace separator string with pointer to its first character, and
+ // make scratch be its length.
+ __ movq(string, separator_operand);
+ __ SmiToInteger32(scratch,
+ FieldOperand(string, String::kLengthOffset));
+ __ lea(string,
+ FieldOperand(string, SeqAsciiString::kHeaderSize));
+ __ movq(separator_operand, string);
+
+ // Jump into the loop after the code that copies the separator, so the first
+ // element is not preceded by a separator
+ __ jmp(&loop_3_entry);
+ // Loop condition: while (index < length).
+ __ bind(&loop_3);
+ // Each iteration of the loop concatenates one string to the result.
+ // Live values in registers:
+ // index: which element of the elements array we are adding to the result.
+ // result_pos: the position to which we are currently copying characters.
+ // scratch: Separator length.
+ // separator_operand (rsp[0x10]): Address of first char of separator.
+
+ // Copy the separator to the result.
+ __ movq(string, separator_operand);
+ __ movl(string_length, scratch);
+ __ CopyBytes(result_pos, string, string_length, 2);
+
+ __ bind(&loop_3_entry);
+ // Get string = array[index].
+ __ movq(string, Operand(elements, index, times_pointer_size, 0));
+ __ SmiToInteger32(string_length,
+ FieldOperand(string, String::kLengthOffset));
+ __ lea(string,
+ FieldOperand(string, SeqAsciiString::kHeaderSize));
+ __ CopyBytes(result_pos, string, string_length);
+ __ incq(index);
+ __ j(not_equal, &loop_3); // Loop while (index < 0).
+
+ __ bind(&done);
+ __ movq(rax, result_operand);
+
+ __ bind(&return_result);
+ // Drop temp values from the stack, and restore context register.
+ __ addq(rsp, Immediate(3 * kPointerSize));
+ __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+ context()->Plug(rax);
}
@@ -3230,7 +3536,8 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
// Call the JS runtime function using a call IC.
__ Move(rcx, expr->name());
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
+ Handle<Code> ic =
+ ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop);
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -3542,9 +3849,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
case NAMED_PROPERTY: {
__ Move(rcx, prop->key()->AsLiteral()->handle());
__ pop(rdx);
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -3559,9 +3866,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
case KEYED_PROPERTY: {
__ pop(rcx);
__ pop(rdx);
- Handle<Code> ic(Builtins::builtin(
- is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) {
@@ -3586,7 +3893,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
Comment cmnt(masm_, "Global variable");
__ Move(rcx, proxy->name());
__ movq(rax, GlobalObjectOperand());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
// Use a regular load, not a contextual load, to avoid a reference
// error.
EmitCallIC(ic, RelocInfo::CODE_TARGET);
@@ -3639,12 +3946,12 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
}
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
- if (check->Equals(Heap::number_symbol())) {
+ if (check->Equals(isolate()->heap()->number_symbol())) {
__ JumpIfSmi(rax, if_true);
__ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
__ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::string_symbol())) {
+ } else if (check->Equals(isolate()->heap()->string_symbol())) {
__ JumpIfSmi(rax, if_false);
// Check for undetectable objects => false.
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
@@ -3652,12 +3959,12 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
__ testb(FieldOperand(rdx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
Split(zero, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::boolean_symbol())) {
+ } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
__ j(equal, if_true);
__ CompareRoot(rax, Heap::kFalseValueRootIndex);
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::undefined_symbol())) {
+ } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(equal, if_true);
__ JumpIfSmi(rax, if_false);
@@ -3666,11 +3973,11 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
__ testb(FieldOperand(rdx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
Split(not_zero, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::function_symbol())) {
+ } else if (check->Equals(isolate()->heap()->function_symbol())) {
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, FIRST_FUNCTION_CLASS_TYPE, rdx);
Split(above_equal, if_true, if_false, fall_through);
- } else if (check->Equals(Heap::object_symbol())) {
+ } else if (check->Equals(isolate()->heap()->object_symbol())) {
__ JumpIfSmi(rax, if_false);
__ CompareRoot(rax, Heap::kNullValueRootIndex);
__ j(equal, if_true);
@@ -3850,18 +4157,19 @@ Register FullCodeGenerator::context_register() {
void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
ASSERT(mode == RelocInfo::CODE_TARGET ||
mode == RelocInfo::CODE_TARGET_CONTEXT);
+ Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
- __ IncrementCounter(&Counters::named_load_full, 1);
+ __ IncrementCounter(counters->named_load_full(), 1);
break;
case Code::KEYED_LOAD_IC:
- __ IncrementCounter(&Counters::keyed_load_full, 1);
+ __ IncrementCounter(counters->keyed_load_full(), 1);
break;
case Code::STORE_IC:
- __ IncrementCounter(&Counters::named_store_full, 1);
+ __ IncrementCounter(counters->named_store_full(), 1);
break;
case Code::KEYED_STORE_IC:
- __ IncrementCounter(&Counters::keyed_store_full, 1);
+ __ IncrementCounter(counters->keyed_store_full(), 1);
default:
break;
}
@@ -3893,18 +4201,19 @@ void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
+ Counters* counters = isolate()->counters();
switch (ic->kind()) {
case Code::LOAD_IC:
- __ IncrementCounter(&Counters::named_load_full, 1);
+ __ IncrementCounter(counters->named_load_full(), 1);
break;
case Code::KEYED_LOAD_IC:
- __ IncrementCounter(&Counters::keyed_load_full, 1);
+ __ IncrementCounter(counters->keyed_load_full(), 1);
break;
case Code::STORE_IC:
- __ IncrementCounter(&Counters::named_store_full, 1);
+ __ IncrementCounter(counters->named_store_full(), 1);
break;
case Code::KEYED_STORE_IC:
- __ IncrementCounter(&Counters::keyed_store_full, 1);
+ __ IncrementCounter(counters->keyed_store_full(), 1);
default:
break;
}
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index b3243cf4..9180465e 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -554,7 +554,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// -- rsp[0] : return address
// -----------------------------------
Label slow, check_string, index_smi, index_string, property_array_property;
- Label check_pixel_array, probe_dictionary, check_number_dictionary;
+ Label probe_dictionary, check_number_dictionary;
// Check that the key is a smi.
__ JumpIfNotSmi(rax, &check_string);
@@ -569,7 +569,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// now in rcx.
__ testb(FieldOperand(rcx, Map::kBitField2Offset),
Immediate(1 << Map::kHasFastElements));
- __ j(zero, &check_pixel_array);
+ __ j(zero, &check_number_dictionary);
GenerateFastArrayLoad(masm,
rdx,
@@ -579,21 +579,14 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
rax,
NULL,
&slow);
- __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
__ ret(0);
- __ bind(&check_pixel_array);
- GenerateFastPixelArrayLoad(masm,
- rdx,
- rax,
- rcx,
- rbx,
- rax,
- &check_number_dictionary,
- NULL,
- &slow);
-
__ bind(&check_number_dictionary);
+ __ SmiToInteger32(rbx, rax);
+ __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
+
// Check whether the elements is a number dictionary.
// rdx: receiver
// rax: key
@@ -609,7 +602,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Slow case: Jump to runtime.
// rdx: receiver
// rax: key
- __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
+ __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
GenerateRuntimeGetProperty(masm);
__ bind(&check_string);
@@ -638,10 +631,10 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Load the key (consisting of map and symbol) from the cache and
// check for match.
ExternalReference cache_keys
- = ExternalReference::keyed_lookup_cache_keys();
+ = ExternalReference::keyed_lookup_cache_keys(masm->isolate());
__ movq(rdi, rcx);
__ shl(rdi, Immediate(kPointerSizeLog2 + 1));
- __ movq(kScratchRegister, cache_keys);
+ __ LoadAddress(kScratchRegister, cache_keys);
__ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, 0));
__ j(not_equal, &slow);
__ cmpq(rax, Operand(kScratchRegister, rdi, times_1, kPointerSize));
@@ -649,8 +642,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Get field offset, which is a 32-bit integer.
ExternalReference cache_field_offsets
- = ExternalReference::keyed_lookup_cache_field_offsets();
- __ movq(kScratchRegister, cache_field_offsets);
+ = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
+ __ LoadAddress(kScratchRegister, cache_field_offsets);
__ movl(rdi, Operand(kScratchRegister, rcx, times_4, 0));
__ movzxbq(rcx, FieldOperand(rbx, Map::kInObjectPropertiesOffset));
__ subq(rdi, rcx);
@@ -660,7 +653,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
__ addq(rcx, rdi);
__ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0));
- __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
+ __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
__ ret(0);
// Load property array property.
@@ -668,7 +661,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ movq(rax, FieldOperand(rdx, JSObject::kPropertiesOffset));
__ movq(rax, FieldOperand(rax, rdi, times_pointer_size,
FixedArray::kHeaderSize));
- __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
+ __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
__ ret(0);
// Do a quick inline probe of the receiver's dictionary, if it
@@ -683,7 +676,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
GenerateGlobalInstanceTypeCheck(masm, rcx, &slow);
GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax);
- __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
+ __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
__ ret(0);
__ bind(&index_string);
@@ -758,8 +751,11 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
__ push(rcx); // return address
// Perform tail call to the entry.
- __ TailCallExternalReference(ExternalReference(
- IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
+ __ TailCallExternalReference(
+ ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
+ masm->isolate()),
+ 2,
+ 1);
__ bind(&slow);
GenerateMiss(masm);
@@ -774,7 +770,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- Label slow, slow_with_tagged_index, fast, array, extra, check_pixel_array;
+ Label slow, slow_with_tagged_index, fast, array, extra;
// Check that the object isn't a smi.
__ JumpIfSmi(rdx, &slow_with_tagged_index);
@@ -803,7 +799,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
// Check that the object is in fast mode and writable.
__ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
Heap::kFixedArrayMapRootIndex);
- __ j(not_equal, &check_pixel_array);
+ __ j(not_equal, &slow);
__ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
// rax: value
// rbx: FixedArray
@@ -817,25 +813,6 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
GenerateRuntimeSetProperty(masm, strict_mode);
// Never returns to here.
- // Check whether the elements is a pixel array.
- // rax: value
- // rdx: receiver
- // rbx: receiver's elements array
- // rcx: index, zero-extended.
- __ bind(&check_pixel_array);
- GenerateFastPixelArrayStore(masm,
- rdx,
- rcx,
- rax,
- rbx,
- rdi,
- false,
- true,
- NULL,
- &slow,
- &slow,
- &slow);
-
// Extra capacity case: Check if there is extra capacity to
// perform the store and update the length. Used for adding one
// element to the array by writing to array[array.length].
@@ -907,7 +884,8 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
Code::kNoExtraICState,
NORMAL,
argc);
- StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, rax);
+ Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
+ rax);
// If the stub cache probing failed, the receiver might be a value.
// For value objects, we use the map of the prototype objects for
@@ -943,7 +921,8 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
// Probe the stub cache for the value object.
__ bind(&probe);
- StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg);
+ Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
+ no_reg);
__ bind(&miss);
}
@@ -1012,10 +991,11 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
+ Counters* counters = masm->isolate()->counters();
if (id == IC::kCallIC_Miss) {
- __ IncrementCounter(&Counters::call_miss, 1);
+ __ IncrementCounter(counters->call_miss(), 1);
} else {
- __ IncrementCounter(&Counters::keyed_call_miss, 1);
+ __ IncrementCounter(counters->keyed_call_miss(), 1);
}
// Get the receiver of the function from the stack; 1 ~ return address.
@@ -1031,7 +1011,7 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
// Call the entry.
CEntryStub stub(1);
__ movq(rax, Immediate(2));
- __ movq(rbx, ExternalReference(IC_Utility(id)));
+ __ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate()));
__ CallStub(&stub);
// Move result to rdi and exit the internal frame.
@@ -1141,7 +1121,8 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
GenerateFastArrayLoad(
masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load);
- __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
__ bind(&do_call);
// receiver in rdx is not used after this point.
@@ -1159,13 +1140,13 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
__ SmiToInteger32(rbx, rcx);
// ebx: untagged index
GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi);
- __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1);
+ __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
__ jmp(&do_call);
__ bind(&slow_load);
// This branch is taken when calling KeyedCallIC_Miss is neither required
// nor beneficial.
- __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1);
+ __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
__ EnterInternalFrame();
__ push(rcx); // save the key
__ push(rdx); // pass the receiver
@@ -1192,11 +1173,11 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
__ j(not_equal, &lookup_monomorphic_cache);
GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi);
- __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
+ __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
__ jmp(&do_call);
__ bind(&lookup_monomorphic_cache);
- __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1);
+ __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
// Fall through on miss.
@@ -1207,7 +1188,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// - the value loaded is not a function,
// - there is hope that the runtime will create a monomorphic call stub
// that will get fetched next time.
- __ IncrementCounter(&Counters::keyed_call_generic_slow, 1);
+ __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
GenerateMiss(masm, argc);
__ bind(&index_string);
@@ -1265,7 +1246,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
NOT_IN_LOOP,
MONOMORPHIC);
- StubCache::GenerateProbe(masm, flags, rax, rcx, rbx, rdx);
+ Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rax, rcx, rbx,
+ rdx);
// Cache miss: Jump to runtime.
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
@@ -1300,7 +1282,8 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
// -- rsp[0] : return address
// -----------------------------------
- __ IncrementCounter(&Counters::load_miss, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->load_miss(), 1);
__ pop(rbx);
__ push(rax); // receiver
@@ -1308,7 +1291,8 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
__ push(rbx); // return address
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
@@ -1383,7 +1367,7 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
// (-1) or we should be clearing the inlined version.
ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 ||
*reinterpret_cast<int*>(offset_address) == -1 ||
- (offset == 0 && map == Heap::null_value()));
+ (offset == 0 && map == HEAP->null_value()));
*reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
// Patch the offset in the write-barrier code. The offset is the
@@ -1393,7 +1377,7 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
// (-1) or we should be clearing the inlined version.
ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt ||
*reinterpret_cast<int*>(offset_address) == -1 ||
- (offset == 0 && map == Heap::null_value()));
+ (offset == 0 && map == HEAP->null_value()));
*reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
return true;
@@ -1444,7 +1428,8 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// -- rsp[0] : return address
// -----------------------------------
- __ IncrementCounter(&Counters::keyed_load_miss, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_miss(), 1);
__ pop(rbx);
__ push(rdx); // receiver
@@ -1452,7 +1437,8 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
__ push(rbx); // return address
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
+ ExternalReference ref
+ = ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
}
@@ -1488,7 +1474,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
NOT_IN_LOOP,
MONOMORPHIC,
strict_mode);
- StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg);
+ Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
+ no_reg);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
@@ -1510,7 +1497,8 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
__ push(rbx); // return address
// Perform tail call to the entry.
- ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
@@ -1563,7 +1551,8 @@ void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
__ push(value);
__ push(scratch); // return address
- ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
__ TailCallExternalReference(ref, 2, 1);
__ bind(&miss);
@@ -1585,11 +1574,12 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
GenerateStringDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss);
GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9);
- __ IncrementCounter(&Counters::store_normal_hit, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->store_normal_hit(), 1);
__ ret(0);
__ bind(&miss);
- __ IncrementCounter(&Counters::store_normal_miss, 1);
+ __ IncrementCounter(counters->store_normal_miss(), 1);
GenerateMiss(masm);
}
@@ -1652,7 +1642,8 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
__ push(rbx); // return address
// Do tail-call to runtime routine.
- ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
+ ExternalReference ref =
+ ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 3, 1);
}
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index bd968b95..86a7e833 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -39,38 +39,31 @@ namespace internal {
// When invoking builtins, we need to record the safepoint in the middle of
// the invoke instruction sequence generated by the macro assembler.
-class SafepointGenerator : public PostCallGenerator {
+class SafepointGenerator : public CallWrapper {
public:
SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers,
- int deoptimization_index,
- bool ensure_reloc_space = false)
+ int deoptimization_index)
: codegen_(codegen),
pointers_(pointers),
- deoptimization_index_(deoptimization_index),
- ensure_reloc_space_(ensure_reloc_space),
- previous_safepoint_position_(-kMinSafepointSize) { }
+ deoptimization_index_(deoptimization_index) { }
virtual ~SafepointGenerator() { }
- virtual void Generate() {
+ virtual void BeforeCall(int call_size) {
+ ASSERT(call_size >= 0);
// Ensure that we have enough space after the previous safepoint position
- // for the generated code there.
- int position = codegen_->masm()->pc_offset();
- ASSERT(position > previous_safepoint_position_);
- if (position < previous_safepoint_position_ + kMinSafepointSize) {
- int padding_size =
- previous_safepoint_position_ + kMinSafepointSize - position;
+ // for the jump generated there.
+ int call_end = codegen_->masm()->pc_offset() + call_size;
+ int prev_jump_end = codegen_->LastSafepointEnd() + kMinSafepointSize;
+ if (call_end < prev_jump_end) {
+ int padding_size = prev_jump_end - call_end;
STATIC_ASSERT(kMinSafepointSize <= 9); // One multibyte nop is enough.
codegen_->masm()->nop(padding_size);
- position += padding_size;
- }
- // Ensure that we have enough space in the reloc info to patch
- // this with calls when doing deoptimization.
- if (ensure_reloc_space_) {
- codegen_->masm()->RecordComment(RelocInfo::kFillerCommentString, true);
}
+ }
+
+ virtual void AfterCall() {
codegen_->RecordSafepoint(pointers_, deoptimization_index_);
- previous_safepoint_position_ = position;
}
private:
@@ -79,8 +72,6 @@ class SafepointGenerator : public PostCallGenerator {
LCodeGen* codegen_;
LPointerMap* pointers_;
int deoptimization_index_;
- bool ensure_reloc_space_;
- int previous_safepoint_position_;
};
@@ -103,6 +94,7 @@ void LCodeGen::FinishCode(Handle<Code> code) {
code->set_stack_slots(StackSlotCount());
code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
PopulateDeoptimizationData(code);
+ Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
}
@@ -259,9 +251,8 @@ LInstruction* LCodeGen::GetNextInstruction() {
bool LCodeGen::GenerateJumpTable() {
for (int i = 0; i < jump_table_.length(); i++) {
- JumpTableEntry* info = jump_table_[i];
- __ bind(&(info->label_));
- __ Jump(info->address_, RelocInfo::RUNTIME_ENTRY);
+ __ bind(&jump_table_[i].label);
+ __ Jump(jump_table_[i].address, RelocInfo::RUNTIME_ENTRY);
}
return !is_aborted();
}
@@ -467,7 +458,7 @@ void LCodeGen::CallCode(Handle<Code> code,
}
-void LCodeGen::CallRuntime(Runtime::Function* function,
+void LCodeGen::CallRuntime(const Runtime::Function* function,
int num_arguments,
LInstruction* instr) {
ASSERT(instr != NULL);
@@ -539,17 +530,13 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
if (cc == no_condition) {
__ Jump(entry, RelocInfo::RUNTIME_ENTRY);
} else {
- JumpTableEntry* jump_info = NULL;
// We often have several deopts to the same entry, reuse the last
// jump entry if this is the case.
- if (jump_table_.length() > 0 &&
- jump_table_[jump_table_.length() - 1]->address_ == entry) {
- jump_info = jump_table_[jump_table_.length() - 1];
- } else {
- jump_info = new JumpTableEntry(entry);
- jump_table_.Add(jump_info);
+ if (jump_table_.is_empty() ||
+ jump_table_.last().address != entry) {
+ jump_table_.Add(entry);
}
- __ j(cc, &jump_info->label_);
+ __ j(cc, &jump_table_.last().label);
}
}
@@ -559,14 +546,14 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
if (length == 0) return;
ASSERT(FLAG_deopt);
Handle<DeoptimizationInputData> data =
- Factory::NewDeoptimizationInputData(length, TENURED);
+ factory()->NewDeoptimizationInputData(length, TENURED);
Handle<ByteArray> translations = translations_.CreateByteArray();
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
Handle<FixedArray> literals =
- Factory::NewFixedArray(deoptimization_literals_.length(), TENURED);
+ factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
for (int i = 0; i < deoptimization_literals_.length(); i++) {
literals->set(i, *deoptimization_literals_[i]);
}
@@ -720,16 +707,6 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
break;
}
- case CodeStub::StringCharAt: {
- StringCharAtStub stub;
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- break;
- }
- case CodeStub::MathPow: {
- MathPowStub stub;
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- break;
- }
case CodeStub::NumberToString: {
NumberToStringStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
@@ -763,41 +740,65 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
void LCodeGen::DoModI(LModI* instr) {
- LOperand* right = instr->InputAt(1);
- ASSERT(ToRegister(instr->result()).is(rdx));
- ASSERT(ToRegister(instr->InputAt(0)).is(rax));
- ASSERT(!ToRegister(instr->InputAt(1)).is(rax));
- ASSERT(!ToRegister(instr->InputAt(1)).is(rdx));
+ if (instr->hydrogen()->HasPowerOf2Divisor()) {
+ Register dividend = ToRegister(instr->InputAt(0));
- Register right_reg = ToRegister(right);
+ int32_t divisor =
+ HConstant::cast(instr->hydrogen()->right())->Integer32Value();
- // Check for x % 0.
- if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
- __ testl(right_reg, right_reg);
- DeoptimizeIf(zero, instr->environment());
- }
+ if (divisor < 0) divisor = -divisor;
- // Sign extend eax to edx. (We are using only the low 32 bits of the values.)
- __ cdq();
+ NearLabel positive_dividend, done;
+ __ testl(dividend, dividend);
+ __ j(not_sign, &positive_dividend);
+ __ negl(dividend);
+ __ andl(dividend, Immediate(divisor - 1));
+ __ negl(dividend);
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ __ j(not_zero, &done);
+ DeoptimizeIf(no_condition, instr->environment());
+ }
+ __ bind(&positive_dividend);
+ __ andl(dividend, Immediate(divisor - 1));
+ __ bind(&done);
+ } else {
+ LOperand* right = instr->InputAt(1);
+ Register right_reg = ToRegister(right);
- // Check for (0 % -x) that will produce negative zero.
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- NearLabel positive_left;
- NearLabel done;
- __ testl(rax, rax);
- __ j(not_sign, &positive_left);
- __ idivl(right_reg);
+ ASSERT(ToRegister(instr->result()).is(rdx));
+ ASSERT(ToRegister(instr->InputAt(0)).is(rax));
+ ASSERT(!right_reg.is(rax));
+ ASSERT(!right_reg.is(rdx));
- // Test the remainder for 0, because then the result would be -0.
- __ testl(rdx, rdx);
- __ j(not_zero, &done);
+ // Check for x % 0.
+ if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
+ __ testl(right_reg, right_reg);
+ DeoptimizeIf(zero, instr->environment());
+ }
- DeoptimizeIf(no_condition, instr->environment());
- __ bind(&positive_left);
- __ idivl(right_reg);
- __ bind(&done);
- } else {
- __ idivl(right_reg);
+ // Sign extend eax to edx.
+ // (We are using only the low 32 bits of the values.)
+ __ cdq();
+
+ // Check for (0 % -x) that will produce negative zero.
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ NearLabel positive_left;
+ NearLabel done;
+ __ testl(rax, rax);
+ __ j(not_sign, &positive_left);
+ __ idivl(right_reg);
+
+ // Test the remainder for 0, because then the result would be -0.
+ __ testl(rdx, rdx);
+ __ j(not_zero, &done);
+
+ DeoptimizeIf(no_condition, instr->environment());
+ __ bind(&positive_left);
+ __ idivl(right_reg);
+ __ bind(&done);
+ } else {
+ __ idivl(right_reg);
+ }
}
}
@@ -856,16 +857,56 @@ void LCodeGen::DoMulI(LMulI* instr) {
__ movl(kScratchRegister, left);
}
+ bool can_overflow =
+ instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
if (right->IsConstantOperand()) {
int right_value = ToInteger32(LConstantOperand::cast(right));
- __ imull(left, left, Immediate(right_value));
+ if (right_value == -1) {
+ __ negl(left);
+ } else if (right_value == 0) {
+ __ xorl(left, left);
+ } else if (right_value == 2) {
+ __ addl(left, left);
+ } else if (!can_overflow) {
+ // If the multiplication is known to not overflow, we
+ // can use operations that don't set the overflow flag
+ // correctly.
+ switch (right_value) {
+ case 1:
+ // Do nothing.
+ break;
+ case 3:
+ __ leal(left, Operand(left, left, times_2, 0));
+ break;
+ case 4:
+ __ shll(left, Immediate(2));
+ break;
+ case 5:
+ __ leal(left, Operand(left, left, times_4, 0));
+ break;
+ case 8:
+ __ shll(left, Immediate(3));
+ break;
+ case 9:
+ __ leal(left, Operand(left, left, times_8, 0));
+ break;
+ case 16:
+ __ shll(left, Immediate(4));
+ break;
+ default:
+ __ imull(left, left, Immediate(right_value));
+ break;
+ }
+ } else {
+ __ imull(left, left, Immediate(right_value));
+ }
} else if (right->IsStackSlot()) {
__ imull(left, ToOperand(right));
} else {
__ imull(left, ToRegister(right));
}
- if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
+ if (can_overflow) {
DeoptimizeIf(overflow, instr->environment());
}
@@ -1067,10 +1108,10 @@ void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
}
-void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
+void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
- __ movq(result, FieldOperand(array, PixelArray::kLengthOffset));
+ __ movl(result, FieldOperand(array, ExternalPixelArray::kLengthOffset));
}
@@ -1152,7 +1193,8 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
__ PrepareCallCFunction(2);
__ movsd(xmm0, left);
ASSERT(right.is(xmm1));
- __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 2);
+ __ CallCFunction(
+ ExternalReference::double_fp_operation(Token::MOD, isolate()), 2);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
__ movsd(result, xmm0);
break;
@@ -1221,7 +1263,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
Register reg = ToRegister(instr->InputAt(0));
HType type = instr->hydrogen()->type();
if (type.IsBoolean()) {
- __ Cmp(reg, Factory::true_value());
+ __ CompareRoot(reg, Heap::kTrueValueRootIndex);
EmitBranch(true_block, false_block, equal);
} else if (type.IsSmi()) {
__ SmiCompare(reg, Smi::FromInt(0));
@@ -1236,7 +1278,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ j(equal, true_label);
__ CompareRoot(reg, Heap::kFalseValueRootIndex);
__ j(equal, false_label);
- __ SmiCompare(reg, Smi::FromInt(0));
+ __ Cmp(reg, Smi::FromInt(0));
__ j(equal, false_label);
__ JumpIfSmi(reg, true_label);
@@ -1488,14 +1530,14 @@ void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
int true_block = chunk_->LookupDestination(instr->true_block_id());
- __ Cmp(reg, Factory::null_value());
+ __ CompareRoot(reg, Heap::kNullValueRootIndex);
if (instr->is_strict()) {
EmitBranch(true_block, false_block, equal);
} else {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
__ j(equal, true_label);
- __ Cmp(reg, Factory::undefined_value());
+ __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
__ j(equal, true_label);
__ JumpIfSmi(reg, false_label);
// Check for undetectable objects by looking in the bit field in
@@ -1834,24 +1876,51 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
LInstanceOfKnownGlobal* instr)
: LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() {
- codegen()->DoDeferredLInstanceOfKnownGlobal(instr_);
+ codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
}
+ Label* map_check() { return &map_check_; }
+
private:
LInstanceOfKnownGlobal* instr_;
+ Label map_check_;
};
DeferredInstanceOfKnownGlobal* deferred;
deferred = new DeferredInstanceOfKnownGlobal(this, instr);
- Label false_result;
+ Label done, false_result;
Register object = ToRegister(instr->InputAt(0));
// A Smi is not an instance of anything.
__ JumpIfSmi(object, &false_result);
- // Null is not an instance of anything.
+ // This is the inlined call site instanceof cache. The two occurences of the
+ // hole value will be patched to the last map/result pair generated by the
+ // instanceof stub.
+ NearLabel cache_miss;
+ // Use a temp register to avoid memory operands with variable lengths.
+ Register map = ToRegister(instr->TempAt(0));
+ __ movq(map, FieldOperand(object, HeapObject::kMapOffset));
+ __ bind(deferred->map_check()); // Label for calculating code patching.
+ __ movq(kScratchRegister, factory()->the_hole_value(),
+ RelocInfo::EMBEDDED_OBJECT);
+ __ cmpq(map, kScratchRegister); // Patched to cached map.
+ __ j(not_equal, &cache_miss);
+ // Patched to load either true or false.
+ __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
+#ifdef DEBUG
+ // Check that the code size between patch label and patch sites is invariant.
+ Label end_of_patched_code;
+ __ bind(&end_of_patched_code);
+ ASSERT(true);
+#endif
+ __ jmp(&done);
+
+ // The inlined call site cache did not match. Check for null and string
+ // before calling the deferred code.
+ __ bind(&cache_miss); // Null is not an instance of anything.
__ CompareRoot(object, Heap::kNullValueRootIndex);
__ j(equal, &false_result);
@@ -1862,17 +1931,26 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
__ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
__ bind(deferred->exit());
+ __ bind(&done);
}
-void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
+void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+ Label* map_check) {
__ PushSafepointRegisters();
-
- InstanceofStub stub(InstanceofStub::kNoFlags);
+ InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>(
+ InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck);
+ InstanceofStub stub(flags);
__ push(ToRegister(instr->InputAt(0)));
__ Push(instr->function());
- __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+ Register temp = ToRegister(instr->TempAt(0));
+ ASSERT(temp.is(rdi));
+ static const int kAdditionalDelta = 16;
+ int delta =
+ masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
+ __ movq(temp, Immediate(delta));
+ __ push(temp);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ movq(kScratchRegister, rax);
__ PopSafepointRegisters();
@@ -2011,12 +2089,76 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
}
+void LCodeGen::EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name) {
+ LookupResult lookup;
+ type->LookupInDescriptors(NULL, *name, &lookup);
+ ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
+ int index = lookup.GetLocalFieldIndexFromMap(*type);
+ int offset = index * kPointerSize;
+ if (index < 0) {
+ // Negative property indices are in-object properties, indexed
+ // from the end of the fixed part of the object.
+ __ movq(result, FieldOperand(object, offset + type->instance_size()));
+ } else {
+ // Non-negative property indices are in the properties array.
+ __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
+ __ movq(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
+ }
+}
+
+
+void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
+ Register object = ToRegister(instr->object());
+ Register result = ToRegister(instr->result());
+
+ int map_count = instr->hydrogen()->types()->length();
+ Handle<String> name = instr->hydrogen()->name();
+
+ if (map_count == 0) {
+ ASSERT(instr->hydrogen()->need_generic());
+ __ Move(rcx, instr->hydrogen()->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ NearLabel done;
+ for (int i = 0; i < map_count - 1; ++i) {
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ NearLabel next;
+ __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ __ j(not_equal, &next);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&next);
+ }
+ Handle<Map> map = instr->hydrogen()->types()->last();
+ __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ if (instr->hydrogen()->need_generic()) {
+ NearLabel generic;
+ __ j(not_equal, &generic);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&generic);
+ __ Move(rcx, instr->hydrogen()->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ DeoptimizeIf(not_equal, instr->environment());
+ EmitLoadField(result, object, map, name);
+ }
+ __ bind(&done);
+ }
+}
+
+
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(rax));
ASSERT(ToRegister(instr->result()).is(rax));
__ Move(rcx, instr->name());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2068,25 +2210,31 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
__ movq(result, FieldOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) {
NearLabel done;
- __ Cmp(FieldOperand(result, HeapObject::kMapOffset),
- Factory::fixed_array_map());
+ __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset),
+ Heap::kFixedArrayMapRootIndex);
__ j(equal, &done);
- __ Cmp(FieldOperand(result, HeapObject::kMapOffset),
- Factory::pixel_array_map());
+ __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset),
+ Heap::kFixedCOWArrayMapRootIndex);
__ j(equal, &done);
- __ Cmp(FieldOperand(result, HeapObject::kMapOffset),
- Factory::fixed_cow_array_map());
- __ Check(equal, "Check for fast elements failed.");
+ Register temp((result.is(rax)) ? rbx : rax);
+ __ push(temp);
+ __ movq(temp, FieldOperand(result, HeapObject::kMapOffset));
+ __ movzxbq(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
+ __ subq(temp, Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
+ __ cmpq(temp, Immediate(kExternalArrayTypeCount));
+ __ pop(temp);
+ __ Check(below, "Check for fast elements failed.");
__ bind(&done);
}
}
-void LCodeGen::DoLoadPixelArrayExternalPointer(
- LLoadPixelArrayExternalPointer* instr) {
+void LCodeGen::DoLoadExternalArrayPointer(
+ LLoadExternalArrayPointer* instr) {
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0));
- __ movq(result, FieldOperand(input, PixelArray::kExternalPointerOffset));
+ __ movq(result, FieldOperand(input,
+ ExternalPixelArray::kExternalPointerOffset));
}
@@ -2121,19 +2269,52 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
FixedArray::kHeaderSize));
// Check for the hole value.
- __ Cmp(result, Factory::the_hole_value());
+ __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
DeoptimizeIf(equal, instr->environment());
}
-void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
- Register external_elements = ToRegister(instr->external_pointer());
+void LCodeGen::DoLoadKeyedSpecializedArrayElement(
+ LLoadKeyedSpecializedArrayElement* instr) {
+ Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
- Register result = ToRegister(instr->result());
- ASSERT(result.is(external_elements));
-
- // Load the result.
- __ movzxbq(result, Operand(external_elements, key, times_1, 0));
+ ExternalArrayType array_type = instr->array_type();
+ if (array_type == kExternalFloatArray) {
+ XMMRegister result(ToDoubleRegister(instr->result()));
+ __ movss(result, Operand(external_pointer, key, times_4, 0));
+ __ cvtss2sd(result, result);
+ } else {
+ Register result(ToRegister(instr->result()));
+ switch (array_type) {
+ case kExternalByteArray:
+ __ movsxbq(result, Operand(external_pointer, key, times_1, 0));
+ break;
+ case kExternalUnsignedByteArray:
+ case kExternalPixelArray:
+ __ movzxbq(result, Operand(external_pointer, key, times_1, 0));
+ break;
+ case kExternalShortArray:
+ __ movsxwq(result, Operand(external_pointer, key, times_2, 0));
+ break;
+ case kExternalUnsignedShortArray:
+ __ movzxwq(result, Operand(external_pointer, key, times_2, 0));
+ break;
+ case kExternalIntArray:
+ __ movsxlq(result, Operand(external_pointer, key, times_4, 0));
+ break;
+ case kExternalUnsignedIntArray:
+ __ movl(result, Operand(external_pointer, key, times_4, 0));
+ __ testl(result, result);
+ // TODO(danno): we could be more clever here, perhaps having a special
+ // version of the stub that detects if the overflow case actually
+ // happens, and generate code that returns a double rather than int.
+ DeoptimizeIf(negative, instr->environment());
+ break;
+ case kExternalFloatArray:
+ UNREACHABLE();
+ break;
+ }
+ }
}
@@ -2141,7 +2322,7 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(rdx));
ASSERT(ToRegister(instr->key()).is(rax));
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2152,8 +2333,8 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
// Check for arguments adapter frame.
NearLabel done, adapted;
__ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ SmiCompare(Operand(result, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(equal, &adapted);
// No arguments adaptor frame.
@@ -2256,8 +2437,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
RegisterEnvironmentForDeoptimization(env);
SafepointGenerator safepoint_generator(this,
pointers,
- env->deoptimization_index(),
- true);
+ env->deoptimization_index());
v8::internal::ParameterCount actual(rax);
__ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
}
@@ -2298,9 +2478,9 @@ void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
+ Register global = ToRegister(instr->global());
Register result = ToRegister(instr->result());
- __ movq(result, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
- __ movq(result, FieldOperand(result, GlobalObject::kGlobalReceiverOffset));
+ __ movq(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
}
@@ -2536,7 +2716,8 @@ void LCodeGen::DoPower(LPower* instr) {
// Move arguments to correct registers
__ movsd(xmm0, left_reg);
ASSERT(ToDoubleRegister(right).is(xmm1));
- __ CallCFunction(ExternalReference::power_double_double_function(), 2);
+ __ CallCFunction(
+ ExternalReference::power_double_double_function(isolate()), 2);
} else if (exponent_type.IsInteger32()) {
__ PrepareCallCFunction(2);
// Move arguments to correct registers: xmm0 and edi (not rdi).
@@ -2547,7 +2728,8 @@ void LCodeGen::DoPower(LPower* instr) {
#else
ASSERT(ToRegister(right).is(rdi));
#endif
- __ CallCFunction(ExternalReference::power_double_int_function(), 2);
+ __ CallCFunction(
+ ExternalReference::power_double_int_function(isolate()), 2);
} else {
ASSERT(exponent_type.IsTagged());
CpuFeatures::Scope scope(SSE2);
@@ -2569,10 +2751,13 @@ void LCodeGen::DoPower(LPower* instr) {
// Move arguments to correct registers xmm0 and xmm1.
__ movsd(xmm0, left_reg);
// Right argument is already in xmm1.
- __ CallCFunction(ExternalReference::power_double_double_function(), 2);
+ __ CallCFunction(
+ ExternalReference::power_double_double_function(isolate()), 2);
}
// Return value is in xmm0.
__ movsd(result_reg, xmm0);
+ // Restore context register.
+ __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
}
@@ -2586,7 +2771,7 @@ void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
- TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
}
@@ -2594,7 +2779,7 @@ void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
- TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
}
@@ -2638,7 +2823,8 @@ void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
+ arity, NOT_IN_LOOP);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
}
@@ -2648,7 +2834,8 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
+ arity, NOT_IN_LOOP);
__ Move(rcx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -2669,7 +2856,8 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
- Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
+ arity, NOT_IN_LOOP);
__ Move(rcx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -2687,7 +2875,7 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
ASSERT(ToRegister(instr->InputAt(0)).is(rdi));
ASSERT(ToRegister(instr->result()).is(rax));
- Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
__ Set(rax, instr->arity());
CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
}
@@ -2733,28 +2921,53 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
ASSERT(ToRegister(instr->value()).is(rax));
__ Move(rcx, instr->hydrogen()->name());
- Handle<Code> ic(Builtins::builtin(
- info_->is_strict() ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic = info_->is_strict()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
-void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
+void LCodeGen::DoStoreKeyedSpecializedArrayElement(
+ LStoreKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
- Register value = ToRegister(instr->value());
-
- { // Clamp the value to [0..255].
- NearLabel done;
- __ testl(value, Immediate(0xFFFFFF00));
- __ j(zero, &done);
- __ setcc(negative, value); // 1 if negative, 0 if positive.
- __ decb(value); // 0 if negative, 255 if positive.
- __ bind(&done);
+ ExternalArrayType array_type = instr->array_type();
+ if (array_type == kExternalFloatArray) {
+ XMMRegister value(ToDoubleRegister(instr->value()));
+ __ cvtsd2ss(value, value);
+ __ movss(Operand(external_pointer, key, times_4, 0), value);
+ } else {
+ Register value(ToRegister(instr->value()));
+ switch (array_type) {
+ case kExternalPixelArray:
+ { // Clamp the value to [0..255].
+ NearLabel done;
+ __ testl(value, Immediate(0xFFFFFF00));
+ __ j(zero, &done);
+ __ setcc(negative, value); // 1 if negative, 0 if positive.
+ __ decb(value); // 0 if negative, 255 if positive.
+ __ bind(&done);
+ __ movb(Operand(external_pointer, key, times_1, 0), value);
+ }
+ break;
+ case kExternalByteArray:
+ case kExternalUnsignedByteArray:
+ __ movb(Operand(external_pointer, key, times_1, 0), value);
+ break;
+ case kExternalShortArray:
+ case kExternalUnsignedShortArray:
+ __ movw(Operand(external_pointer, key, times_2, 0), value);
+ break;
+ case kExternalIntArray:
+ case kExternalUnsignedIntArray:
+ __ movl(Operand(external_pointer, key, times_4, 0), value);
+ break;
+ case kExternalFloatArray:
+ UNREACHABLE();
+ break;
+ }
}
-
- __ movb(Operand(external_pointer, key, times_1, 0), value);
}
@@ -2804,9 +3017,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->key()).is(rcx));
ASSERT(ToRegister(instr->value()).is(rax));
- Handle<Code> ic(Builtins::builtin(
- info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic = info_->is_strict()
+ ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
+ : isolate()->builtins()->KeyedStoreIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2951,6 +3164,56 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
}
+void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
+ class DeferredStringCharFromCode: public LDeferredCode {
+ public:
+ DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
+ private:
+ LStringCharFromCode* instr_;
+ };
+
+ DeferredStringCharFromCode* deferred =
+ new DeferredStringCharFromCode(this, instr);
+
+ ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+ ASSERT(!char_code.is(result));
+
+ __ cmpl(char_code, Immediate(String::kMaxAsciiCharCode));
+ __ j(above, deferred->entry());
+ __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
+ __ movq(result, FieldOperand(result,
+ char_code, times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ CompareRoot(result, Heap::kUndefinedValueRootIndex);
+ __ j(equal, deferred->entry());
+ __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+
+ // TODO(3095996): Get rid of this. For now, we need to make the
+ // result register contain a valid pointer because it is already
+ // contained in the register pointer map.
+ __ Set(result, 0);
+
+ __ PushSafepointRegisters();
+ __ Integer32ToSmi(char_code, char_code);
+ __ push(char_code);
+ __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
+ __ StoreToSafepointRegisterSlot(result, rax);
+ __ PopSafepointRegisters();
+}
+
+
void LCodeGen::DoStringLength(LStringLength* instr) {
Register string = ToRegister(instr->string());
Register result = ToRegister(instr->result());
@@ -3201,11 +3464,14 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
LOperand* input = instr->InputAt(0);
- ASSERT(input->IsRegister());
Condition cc = masm()->CheckSmi(ToRegister(input));
- if (instr->condition() != equal) {
- cc = NegateCondition(cc);
- }
+ DeoptimizeIf(NegateCondition(cc), instr->environment());
+}
+
+
+void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
+ LOperand* input = instr->InputAt(0);
+ Condition cc = masm()->CheckSmi(ToRegister(input));
DeoptimizeIf(cc, instr->environment());
}
@@ -3260,9 +3526,9 @@ void LCodeGen::DoCheckMap(LCheckMap* instr) {
void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
- if (Heap::InNewSpace(*object)) {
+ if (heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
- Factory::NewJSGlobalPropertyCell(object);
+ factory()->NewJSGlobalPropertyCell(object);
__ movq(result, cell, RelocInfo::GLOBAL_PROPERTY_CELL);
__ movq(result, Operand(result, 0));
} else {
@@ -3343,6 +3609,13 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
}
+void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
+ ASSERT(ToRegister(instr->InputAt(0)).is(rax));
+ __ push(rax);
+ CallRuntime(Runtime::kToFastProperties, 1, instr);
+}
+
+
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
NearLabel materialized;
// Registers will be used as follows:
@@ -3400,14 +3673,17 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
// space for nested functions that don't need literals cloning.
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (shared_info->num_literals() == 0 && !pretenure) {
- FastNewClosureStub stub;
+ if (!pretenure && shared_info->num_literals() == 0) {
+ FastNewClosureStub stub(
+ shared_info->strict_mode() ? kStrictMode : kNonStrictMode);
__ Push(shared_info);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
} else {
__ push(rsi);
__ Push(shared_info);
- __ Push(pretenure ? Factory::true_value() : Factory::false_value());
+ __ PushRoot(pretenure ?
+ Heap::kTrueValueRootIndex :
+ Heap::kFalseValueRootIndex);
CallRuntime(Runtime::kNewClosure, 3, instr);
}
}
@@ -3488,13 +3764,14 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
Register input,
Handle<String> type_name) {
Condition final_branch_condition = no_condition;
- if (type_name->Equals(Heap::number_symbol())) {
+ if (type_name->Equals(heap()->number_symbol())) {
__ JumpIfSmi(input, true_label);
- __ Cmp(FieldOperand(input, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset),
+ Heap::kHeapNumberMapRootIndex);
+
final_branch_condition = equal;
- } else if (type_name->Equals(Heap::string_symbol())) {
+ } else if (type_name->Equals(heap()->string_symbol())) {
__ JumpIfSmi(input, false_label);
__ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
__ j(above_equal, false_label);
@@ -3502,13 +3779,13 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
Immediate(1 << Map::kIsUndetectable));
final_branch_condition = zero;
- } else if (type_name->Equals(Heap::boolean_symbol())) {
+ } else if (type_name->Equals(heap()->boolean_symbol())) {
__ CompareRoot(input, Heap::kTrueValueRootIndex);
__ j(equal, true_label);
__ CompareRoot(input, Heap::kFalseValueRootIndex);
final_branch_condition = equal;
- } else if (type_name->Equals(Heap::undefined_symbol())) {
+ } else if (type_name->Equals(heap()->undefined_symbol())) {
__ CompareRoot(input, Heap::kUndefinedValueRootIndex);
__ j(equal, true_label);
__ JumpIfSmi(input, false_label);
@@ -3518,12 +3795,12 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
Immediate(1 << Map::kIsUndetectable));
final_branch_condition = not_zero;
- } else if (type_name->Equals(Heap::function_symbol())) {
+ } else if (type_name->Equals(heap()->function_symbol())) {
__ JumpIfSmi(input, false_label);
__ CmpObjectType(input, FIRST_FUNCTION_CLASS_TYPE, input);
final_branch_condition = above_equal;
- } else if (type_name->Equals(Heap::object_symbol())) {
+ } else if (type_name->Equals(heap()->object_symbol())) {
__ JumpIfSmi(input, false_label);
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ j(equal, true_label);
@@ -3581,15 +3858,15 @@ void LCodeGen::EmitIsConstructCall(Register temp) {
// Skip the arguments adaptor frame if it exists.
NearLabel check_frame_marker;
- __ SmiCompare(Operand(temp, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(not_equal, &check_frame_marker);
__ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset));
// Check the marker in the calling frame.
__ bind(&check_frame_marker);
- __ SmiCompare(Operand(temp, StandardFrameConstants::kMarkerOffset),
- Smi::FromInt(StackFrame::CONSTRUCT));
+ __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
+ Smi::FromInt(StackFrame::CONSTRUCT));
}
@@ -3631,8 +3908,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
// builtin)
SafepointGenerator safepoint_generator(this,
pointers,
- env->deoptimization_index(),
- true);
+ env->deoptimization_index());
__ Push(Smi::FromInt(strict_mode_flag()));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
}
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index ab0dffb1..f44fdb95 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -67,6 +67,9 @@ class LCodeGen BASE_EMBEDDED {
// Simple accessors.
MacroAssembler* masm() const { return masm_; }
CompilationInfo* info() const { return info_; }
+ Isolate* isolate() const { return info_->isolate(); }
+ Factory* factory() const { return isolate()->factory(); }
+ Heap* heap() const { return isolate()->heap(); }
// Support for converting LOperands to assembler types.
Register ToRegister(LOperand* op) const;
@@ -77,7 +80,6 @@ class LCodeGen BASE_EMBEDDED {
Handle<Object> ToHandle(LConstantOperand* op) const;
Operand ToOperand(LOperand* op) const;
-
// Try to generate code for the entire chunk, but it may fail if the
// chunk contains constructs we cannot handle. Returns true if the
// code generation attempt succeeded.
@@ -93,7 +95,9 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
- void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr);
+ void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
+ void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+ Label* map_check);
// Parallel move support.
void DoParallelMove(LParallelMove* move);
@@ -155,13 +159,13 @@ class LCodeGen BASE_EMBEDDED {
void CallCode(Handle<Code> code,
RelocInfo::Mode mode,
LInstruction* instr);
- void CallRuntime(Runtime::Function* function,
+ void CallRuntime(const Runtime::Function* function,
int num_arguments,
LInstruction* instr);
void CallRuntime(Runtime::FunctionId id,
int num_arguments,
LInstruction* instr) {
- Runtime::Function* function = Runtime::FunctionForId(id);
+ const Runtime::Function* function = Runtime::FunctionForId(id);
CallRuntime(function, num_arguments, instr);
}
@@ -210,6 +214,9 @@ class LCodeGen BASE_EMBEDDED {
int arguments,
int deoptimization_index);
void RecordPosition(int position);
+ int LastSafepointEnd() {
+ return static_cast<int>(safepoints_.GetPcAfterGap());
+ }
static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
@@ -234,15 +241,20 @@ class LCodeGen BASE_EMBEDDED {
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp);
+ void EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name);
+
// Emits code for pushing a constant operand.
void EmitPushConstantOperand(LOperand* operand);
struct JumpTableEntry {
- inline JumpTableEntry(Address address)
- : label_(),
- address_(address) { }
- Label label_;
- Address address_;
+ inline JumpTableEntry(Address entry)
+ : label(),
+ address(entry) { }
+ Label label;
+ Address address;
};
LChunk* const chunk_;
@@ -253,7 +265,7 @@ class LCodeGen BASE_EMBEDDED {
int current_instruction_;
const ZoneList<LInstruction*>* instructions_;
ZoneList<LEnvironment*> deoptimizations_;
- ZoneList<JumpTableEntry*> jump_table_;
+ ZoneList<JumpTableEntry> jump_table_;
ZoneList<Handle<Object> > deoptimization_literals_;
int inlined_function_count_;
Scope* const scope_;
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index bf4d5a16..c47cd726 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1156,7 +1156,8 @@ LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
HInstanceOfKnownGlobal* instr) {
LInstanceOfKnownGlobal* result =
- new LInstanceOfKnownGlobal(UseFixed(instr->value(), rax));
+ new LInstanceOfKnownGlobal(UseFixed(instr->value(), rax),
+ FixedTemp(rdi));
return MarkAsCall(DefineFixed(result, rax), instr);
}
@@ -1198,7 +1199,8 @@ LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
- return DefineAsRegister(new LGlobalReceiver);
+ LOperand* global_object = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new LGlobalReceiver(global_object));
}
@@ -1346,13 +1348,23 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
- // The temporary operand is necessary to ensure that right is not allocated
- // into edx.
- LOperand* temp = FixedTemp(rdx);
- LOperand* value = UseFixed(instr->left(), rax);
- LOperand* divisor = UseRegister(instr->right());
- LModI* mod = new LModI(value, divisor, temp);
- LInstruction* result = DefineFixed(mod, rdx);
+
+ LInstruction* result;
+ if (instr->HasPowerOf2Divisor()) {
+ ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
+ LOperand* value = UseRegisterAtStart(instr->left());
+ LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
+ result = DefineSameAsFirst(mod);
+ } else {
+ // The temporary operand is necessary to ensure that right is not
+ // allocated into edx.
+ LOperand* temp = FixedTemp(rdx);
+ LOperand* value = UseFixed(instr->left(), rax);
+ LOperand* divisor = UseRegister(instr->right());
+ LModI* mod = new LModI(value, divisor, temp);
+ result = DefineFixed(mod, rdx);
+ }
+
return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanBeDivByZero))
? AssignEnvironment(result)
@@ -1555,9 +1567,10 @@ LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
}
-LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) {
+LInstruction* LChunkBuilder::DoExternalArrayLength(
+ HExternalArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LPixelArrayLength(array));
+ return DefineAsRegister(new LExternalArrayLength(array));
}
@@ -1601,7 +1614,8 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
bool needs_check = !instr->value()->type().IsSmi();
if (needs_check) {
LOperand* xmm_temp =
- (instr->CanTruncateToInt32() && CpuFeatures::IsSupported(SSE3))
+ (instr->CanTruncateToInt32() &&
+ Isolate::Current()->cpu_features()->IsSupported(SSE3))
? NULL
: FixedTemp(xmm1);
LTaggedToI* res = new LTaggedToI(value, xmm_temp);
@@ -1646,7 +1660,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
- return AssignEnvironment(new LCheckSmi(value, zero));
+ return AssignEnvironment(new LCheckNonSmi(value));
}
@@ -1666,7 +1680,7 @@ LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
- return AssignEnvironment(new LCheckSmi(value, not_zero));
+ return AssignEnvironment(new LCheckSmi(value));
}
@@ -1749,6 +1763,21 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
}
+LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
+ HLoadNamedFieldPolymorphic* instr) {
+ ASSERT(instr->representation().IsTagged());
+ if (instr->need_generic()) {
+ LOperand* obj = UseFixed(instr->object(), rax);
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return MarkAsCall(DefineFixed(result, rax), instr);
+ } else {
+ LOperand* obj = UseRegisterAtStart(instr->object());
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return AssignEnvironment(DefineAsRegister(result));
+ }
+}
+
+
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
LOperand* object = UseFixed(instr->object(), rax);
LLoadNamedGeneric* result = new LLoadNamedGeneric(object);
@@ -1769,10 +1798,10 @@ LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
}
-LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer(
- HLoadPixelArrayExternalPointer* instr) {
+LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
+ HLoadExternalArrayPointer* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LLoadPixelArrayExternalPointer(input));
+ return DefineAsRegister(new LLoadExternalArrayPointer(input));
}
@@ -1787,16 +1816,22 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
}
-LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
- HLoadPixelArrayElement* instr) {
- ASSERT(instr->representation().IsInteger32());
+LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
+ HLoadKeyedSpecializedArrayElement* instr) {
+ ExternalArrayType array_type = instr->array_type();
+ Representation representation(instr->representation());
+ ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
+ (representation.IsDouble() && array_type == kExternalFloatArray));
ASSERT(instr->key()->representation().IsInteger32());
- LOperand* external_pointer =
- UseRegisterAtStart(instr->external_pointer());
- LOperand* key = UseRegisterAtStart(instr->key());
- LLoadPixelArrayElement* result =
- new LLoadPixelArrayElement(external_pointer, key);
- return DefineSameAsFirst(result);
+ LOperand* external_pointer = UseRegister(instr->external_pointer());
+ LOperand* key = UseRegister(instr->key());
+ LLoadKeyedSpecializedArrayElement* result =
+ new LLoadKeyedSpecializedArrayElement(external_pointer, key);
+ LInstruction* load_instr = DefineAsRegister(result);
+ // An unsigned int array load might overflow and cause a deopt, make sure it
+ // has an environment.
+ return (array_type == kExternalUnsignedIntArray) ?
+ AssignEnvironment(load_instr) : load_instr;
}
@@ -1828,17 +1863,26 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
}
-LInstruction* LChunkBuilder::DoStorePixelArrayElement(
- HStorePixelArrayElement* instr) {
- ASSERT(instr->value()->representation().IsInteger32());
+LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
+ HStoreKeyedSpecializedArrayElement* instr) {
+ Representation representation(instr->value()->representation());
+ ExternalArrayType array_type = instr->array_type();
+ ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
+ (representation.IsDouble() && array_type == kExternalFloatArray));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* val = UseTempRegister(instr->value());
+ bool val_is_temp_register = array_type == kExternalPixelArray ||
+ array_type == kExternalFloatArray;
+ LOperand* val = val_is_temp_register
+ ? UseTempRegister(instr->value())
+ : UseRegister(instr->key());
LOperand* key = UseRegister(instr->key());
- return new LStorePixelArrayElement(external_pointer, key, val);
+ return new LStoreKeyedSpecializedArrayElement(external_pointer,
+ key,
+ val);
}
@@ -1893,6 +1937,13 @@ LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
}
+LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
+ LOperand* char_code = UseRegister(instr->value());
+ LStringCharFromCode* result = new LStringCharFromCode(char_code);
+ return AssignPointerMap(DefineAsRegister(result));
+}
+
+
LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
LOperand* string = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LStringLength(string));
@@ -1969,6 +2020,13 @@ LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
}
+LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
+ LOperand* object = UseFixed(instr->value(), rax);
+ LToFastProperties* result = new LToFastProperties(object);
+ return MarkAsCall(DefineFixed(result, rax), instr);
+}
+
+
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
LTypeof* result = new LTypeof(UseAtStart(instr->value()));
return MarkAsCall(DefineFixed(result, rax), instr);
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 67ec7af8..e94debf4 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -70,8 +70,11 @@ class LCodeGen;
V(CheckFunction) \
V(CheckInstanceType) \
V(CheckMap) \
+ V(CheckNonSmi) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
+ V(ClassOfTest) \
+ V(ClassOfTestAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
@@ -87,13 +90,18 @@ class LCodeGen;
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
+ V(ExternalArrayLength) \
+ V(FixedArrayLength) \
V(FunctionLiteral) \
V(Gap) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
V(GlobalReceiver) \
V(Goto) \
- V(FixedArrayLength) \
+ V(HasInstanceType) \
+ V(HasInstanceTypeAndBranch) \
+ V(HasCachedArrayIndex) \
+ V(HasCachedArrayIndexAndBranch) \
V(InstanceOf) \
V(InstanceOfAndBranch) \
V(InstanceOfKnownGlobal) \
@@ -105,24 +113,19 @@ class LCodeGen;
V(IsSmi) \
V(IsSmiAndBranch) \
V(JSArrayLength) \
- V(HasInstanceType) \
- V(HasInstanceTypeAndBranch) \
- V(HasCachedArrayIndex) \
- V(HasCachedArrayIndexAndBranch) \
- V(ClassOfTest) \
- V(ClassOfTestAndBranch) \
V(Label) \
V(LazyBailout) \
V(LoadContextSlot) \
V(LoadElements) \
+ V(LoadExternalArrayPointer) \
V(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
+ V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
+ V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
- V(LoadPixelArrayElement) \
- V(LoadPixelArrayExternalPointer) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@@ -132,7 +135,6 @@ class LCodeGen;
V(OsrEntry) \
V(OuterContext) \
V(Parameter) \
- V(PixelArrayLength) \
V(Power) \
V(PushArgument) \
V(RegExpLiteral) \
@@ -145,13 +147,15 @@ class LCodeGen;
V(StoreGlobal) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
+ V(StoreKeyedSpecializedArrayElement) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
- V(StorePixelArrayElement) \
V(StringCharCodeAt) \
+ V(StringCharFromCode) \
V(StringLength) \
V(SubI) \
V(TaggedToI) \
+ V(ToFastProperties) \
V(Throw) \
V(Typeof) \
V(TypeofIs) \
@@ -844,10 +848,11 @@ class LInstanceOfAndBranch: public LControlInstruction<2, 0> {
};
-class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 0> {
+class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> {
public:
- explicit LInstanceOfKnownGlobal(LOperand* value) {
+ LInstanceOfKnownGlobal(LOperand* value, LOperand* temp) {
inputs_[0] = value;
+ temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal,
@@ -996,14 +1001,14 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
};
-class LPixelArrayLength: public LTemplateInstruction<1, 1, 0> {
+class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LPixelArrayLength(LOperand* value) {
+ explicit LExternalArrayLength(LOperand* value) {
inputs_[0] = value;
}
- DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel-array-length")
- DECLARE_HYDROGEN_ACCESSOR(PixelArrayLength)
+ DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
+ DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
};
@@ -1130,6 +1135,19 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> {
};
+class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LLoadNamedFieldPolymorphic(LOperand* object) {
+ inputs_[0] = object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic")
+ DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic)
+
+ LOperand* object() { return inputs_[0]; }
+};
+
+
class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadNamedGeneric(LOperand* object) {
@@ -1167,14 +1185,14 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> {
};
-class LLoadPixelArrayExternalPointer: public LTemplateInstruction<1, 1, 0> {
+class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> {
public:
- explicit LLoadPixelArrayExternalPointer(LOperand* object) {
+ explicit LLoadExternalArrayPointer(LOperand* object) {
inputs_[0] = object;
}
- DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer,
- "load-pixel-array-external-pointer")
+ DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer,
+ "load-external-array-pointer")
};
@@ -1193,19 +1211,23 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
};
-class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> {
+class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
- LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) {
+ LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
+ LOperand* key) {
inputs_[0] = external_pointer;
inputs_[1] = key;
}
- DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
- "load-pixel-array-element")
- DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement)
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
+ "load-keyed-specialized-array-element")
+ DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
+ ExternalArrayType array_type() const {
+ return hydrogen()->array_type();
+ }
};
@@ -1312,9 +1334,15 @@ class LGlobalObject: public LTemplateInstruction<1, 0, 0> {
};
-class LGlobalReceiver: public LTemplateInstruction<1, 0, 0> {
+class LGlobalReceiver: public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LGlobalReceiver(LOperand* global_object) {
+ inputs_[0] = global_object;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver")
+
+ LOperand* global() { return InputAt(0); }
};
@@ -1414,7 +1442,7 @@ class LCallRuntime: public LTemplateInstruction<1, 0, 0> {
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
- Runtime::Function* function() const { return hydrogen()->function(); }
+ const Runtime::Function* function() const { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count(); }
};
@@ -1577,23 +1605,26 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
};
-class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 0> {
+class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
public:
- LStorePixelArrayElement(LOperand* external_pointer,
- LOperand* key,
- LOperand* val) {
+ LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
+ LOperand* key,
+ LOperand* val) {
inputs_[0] = external_pointer;
inputs_[1] = key;
inputs_[2] = val;
}
- DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
- "store-pixel-array-element")
- DECLARE_HYDROGEN_ACCESSOR(StorePixelArrayElement)
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
+ "store-keyed-specialized-array-element")
+ DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
+ ExternalArrayType array_type() const {
+ return hydrogen()->array_type();
+ }
};
@@ -1630,6 +1661,19 @@ class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> {
};
+class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LStringCharFromCode(LOperand* char_code) {
+ inputs_[0] = char_code;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
+ DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
+
+ LOperand* char_code() { return inputs_[0]; }
+};
+
+
class LStringLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LStringLength(LOperand* string) {
@@ -1692,20 +1736,21 @@ class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> {
class LCheckSmi: public LTemplateInstruction<0, 1, 0> {
public:
- LCheckSmi(LOperand* value, Condition condition)
- : condition_(condition) {
+ explicit LCheckSmi(LOperand* value) {
inputs_[0] = value;
}
- Condition condition() const { return condition_; }
+ DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi")
+};
+
- virtual void CompileToNative(LCodeGen* generator);
- virtual const char* Mnemonic() const {
- return (condition_ == zero) ? "check-non-smi" : "check-smi";
+class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
+ public:
+ explicit LCheckNonSmi(LOperand* value) {
+ inputs_[0] = value;
}
- private:
- Condition condition_;
+ DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
};
@@ -1739,6 +1784,17 @@ class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> {
};
+class LToFastProperties: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LToFastProperties(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
+ DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
+};
+
+
class LTypeof: public LTemplateInstruction<1, 1, 0> {
public:
explicit LTypeof(LOperand* value) {
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index b468e82f..654814c1 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -44,11 +44,110 @@ MacroAssembler::MacroAssembler(void* buffer, int size)
: Assembler(buffer, size),
generating_stub_(false),
allow_stub_calls_(true),
- code_object_(Heap::undefined_value()) {
+ root_array_available_(true),
+ code_object_(isolate()->heap()->undefined_value()) {
+}
+
+
+static intptr_t RootRegisterDelta(ExternalReference other, Isolate* isolate) {
+ Address roots_register_value = kRootRegisterBias +
+ reinterpret_cast<Address>(isolate->heap()->roots_address());
+ intptr_t delta = other.address() - roots_register_value;
+ return delta;
+}
+
+
+Operand MacroAssembler::ExternalOperand(ExternalReference target,
+ Register scratch) {
+ if (root_array_available_ && !Serializer::enabled()) {
+ intptr_t delta = RootRegisterDelta(target, isolate());
+ if (is_int32(delta)) {
+ Serializer::TooLateToEnableNow();
+ return Operand(kRootRegister, static_cast<int32_t>(delta));
+ }
+ }
+ movq(scratch, target);
+ return Operand(scratch, 0);
+}
+
+
+void MacroAssembler::Load(Register destination, ExternalReference source) {
+ if (root_array_available_ && !Serializer::enabled()) {
+ intptr_t delta = RootRegisterDelta(source, isolate());
+ if (is_int32(delta)) {
+ Serializer::TooLateToEnableNow();
+ movq(destination, Operand(kRootRegister, static_cast<int32_t>(delta)));
+ return;
+ }
+ }
+ // Safe code.
+ if (destination.is(rax)) {
+ load_rax(source);
+ } else {
+ movq(kScratchRegister, source);
+ movq(destination, Operand(kScratchRegister, 0));
+ }
+}
+
+
+void MacroAssembler::Store(ExternalReference destination, Register source) {
+ if (root_array_available_ && !Serializer::enabled()) {
+ intptr_t delta = RootRegisterDelta(destination, isolate());
+ if (is_int32(delta)) {
+ Serializer::TooLateToEnableNow();
+ movq(Operand(kRootRegister, static_cast<int32_t>(delta)), source);
+ return;
+ }
+ }
+ // Safe code.
+ if (source.is(rax)) {
+ store_rax(destination);
+ } else {
+ movq(kScratchRegister, destination);
+ movq(Operand(kScratchRegister, 0), source);
+ }
+}
+
+
+void MacroAssembler::LoadAddress(Register destination,
+ ExternalReference source) {
+ if (root_array_available_ && !Serializer::enabled()) {
+ intptr_t delta = RootRegisterDelta(source, isolate());
+ if (is_int32(delta)) {
+ Serializer::TooLateToEnableNow();
+ lea(destination, Operand(kRootRegister, static_cast<int32_t>(delta)));
+ return;
+ }
+ }
+ // Safe code.
+ movq(destination, source);
+}
+
+
+int MacroAssembler::LoadAddressSize(ExternalReference source) {
+ if (root_array_available_ && !Serializer::enabled()) {
+ // This calculation depends on the internals of LoadAddress.
+ // It's correctness is ensured by the asserts in the Call
+ // instruction below.
+ intptr_t delta = RootRegisterDelta(source, isolate());
+ if (is_int32(delta)) {
+ Serializer::TooLateToEnableNow();
+ // Operand is lea(scratch, Operand(kRootRegister, delta));
+ // Opcodes : REX.W 8D ModRM Disp8/Disp32 - 4 or 7.
+ int size = 4;
+ if (!is_int8(static_cast<int32_t>(delta))) {
+ size += 3; // Need full four-byte displacement in lea.
+ }
+ return size;
+ }
+ }
+ // Size of movq(destination, src);
+ return 10;
}
void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
+ ASSERT(root_array_available_);
movq(destination, Operand(kRootRegister,
(index << kPointerSizeLog2) - kRootRegisterBias));
}
@@ -57,6 +156,7 @@ void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
void MacroAssembler::LoadRootIndexed(Register destination,
Register variable_offset,
int fixed_offset) {
+ ASSERT(root_array_available_);
movq(destination,
Operand(kRootRegister,
variable_offset, times_pointer_size,
@@ -65,17 +165,20 @@ void MacroAssembler::LoadRootIndexed(Register destination,
void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index) {
+ ASSERT(root_array_available_);
movq(Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias),
source);
}
void MacroAssembler::PushRoot(Heap::RootListIndex index) {
+ ASSERT(root_array_available_);
push(Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias));
}
void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
+ ASSERT(root_array_available_);
cmpq(with, Operand(kRootRegister,
(index << kPointerSizeLog2) - kRootRegisterBias));
}
@@ -83,6 +186,7 @@ void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
void MacroAssembler::CompareRoot(const Operand& with,
Heap::RootListIndex index) {
+ ASSERT(root_array_available_);
ASSERT(!with.AddressUsesRegister(kScratchRegister));
LoadRoot(kScratchRegister, index);
cmpq(with, kScratchRegister);
@@ -92,7 +196,7 @@ void MacroAssembler::CompareRoot(const Operand& with,
void MacroAssembler::RecordWriteHelper(Register object,
Register addr,
Register scratch) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Check that the object is not in new space.
NearLabel not_in_new_space;
InNewSpace(object, scratch, not_equal, &not_in_new_space);
@@ -124,7 +228,7 @@ void MacroAssembler::RecordWrite(Register object,
ASSERT(!object.is(rsi) && !value.is(rsi) && !index.is(rsi));
// First, check if a write barrier is even needed. The tests below
- // catch stores of Smis and stores into young gen.
+ // catch stores of smis and stores into the young generation.
Label done;
JumpIfSmi(value, &done);
@@ -136,7 +240,7 @@ void MacroAssembler::RecordWrite(Register object,
// clobbering done inside RecordWriteNonSmi but it's necessary to
// avoid having the fast case for smis leave the registers
// unchanged.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
movq(index, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
@@ -153,7 +257,7 @@ void MacroAssembler::RecordWrite(Register object,
ASSERT(!object.is(rsi) && !value.is(rsi) && !address.is(rsi));
// First, check if a write barrier is even needed. The tests below
- // catch stores of Smis and stores into young gen.
+ // catch stores of smis and stores into the young generation.
Label done;
JumpIfSmi(value, &done);
@@ -165,7 +269,7 @@ void MacroAssembler::RecordWrite(Register object,
// Clobber all input registers when running with the debug-code flag
// turned on to provoke errors.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
movq(address, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
@@ -179,7 +283,7 @@ void MacroAssembler::RecordWriteNonSmi(Register object,
Register index) {
Label done;
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
NearLabel okay;
JumpIfNotSmi(object, &okay);
Abort("MacroAssembler::RecordWriteNonSmi cannot deal with smis");
@@ -223,7 +327,7 @@ void MacroAssembler::RecordWriteNonSmi(Register object,
// Clobber all input registers when running with the debug-code flag
// turned on to provoke errors.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
movq(scratch, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
movq(index, BitCast<int64_t>(kZapValue), RelocInfo::NONE);
@@ -231,12 +335,12 @@ void MacroAssembler::RecordWriteNonSmi(Register object,
}
void MacroAssembler::Assert(Condition cc, const char* msg) {
- if (FLAG_debug_code) Check(cc, msg);
+ if (emit_debug_code()) Check(cc, msg);
}
void MacroAssembler::AssertFastElements(Register elements) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
NearLabel ok;
CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
Heap::kFixedArrayMapRootIndex);
@@ -391,9 +495,9 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
- Runtime::Function* function = Runtime::FunctionForId(id);
+ const Runtime::Function* function = Runtime::FunctionForId(id);
Set(rax, function->nargs);
- movq(rbx, ExternalReference(function));
+ LoadAddress(rbx, ExternalReference(function, isolate()));
CEntryStub ces(1);
ces.SaveDoubles();
CallStub(&ces);
@@ -406,7 +510,8 @@ MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
}
-void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
+void MacroAssembler::CallRuntime(const Runtime::Function* f,
+ int num_arguments) {
// If the expected number of arguments of the runtime function is
// constant, we check that the actual number of arguments match the
// expectation.
@@ -420,19 +525,19 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
// should remove this need and make the runtime routine entry code
// smarter.
Set(rax, num_arguments);
- movq(rbx, ExternalReference(f));
+ LoadAddress(rbx, ExternalReference(f, isolate()));
CEntryStub ces(f->result_size);
CallStub(&ces);
}
-MaybeObject* MacroAssembler::TryCallRuntime(Runtime::Function* f,
+MaybeObject* MacroAssembler::TryCallRuntime(const Runtime::Function* f,
int num_arguments) {
if (f->nargs >= 0 && f->nargs != num_arguments) {
IllegalOperation(num_arguments);
// Since we did not call the stub, there was no allocation failure.
// Return some non-failure object.
- return Heap::undefined_value();
+ return HEAP->undefined_value();
}
// TODO(1236192): Most runtime routines don't need the number of
@@ -440,7 +545,7 @@ MaybeObject* MacroAssembler::TryCallRuntime(Runtime::Function* f,
// should remove this need and make the runtime routine entry code
// smarter.
Set(rax, num_arguments);
- movq(rbx, ExternalReference(f));
+ LoadAddress(rbx, ExternalReference(f, isolate()));
CEntryStub ces(f->result_size);
return TryCallStub(&ces);
}
@@ -449,7 +554,7 @@ MaybeObject* MacroAssembler::TryCallRuntime(Runtime::Function* f,
void MacroAssembler::CallExternalReference(const ExternalReference& ext,
int num_arguments) {
Set(rax, num_arguments);
- movq(rbx, ext);
+ LoadAddress(rbx, ext);
CEntryStub stub(1);
CallStub(&stub);
@@ -496,14 +601,16 @@ MaybeObject* MacroAssembler::TryTailCallExternalReference(
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size) {
- TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
+ TailCallExternalReference(ExternalReference(fid, isolate()),
+ num_arguments,
+ result_size);
}
MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size) {
- return TryTailCallExternalReference(ExternalReference(fid),
+ return TryTailCallExternalReference(ExternalReference(fid, isolate()),
num_arguments,
result_size);
}
@@ -550,12 +657,12 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
ExternalReference::handle_scope_level_address(),
next_address);
ExternalReference scheduled_exception_address =
- ExternalReference::scheduled_exception_address();
+ ExternalReference::scheduled_exception_address(isolate());
// Allocate HandleScope in callee-save registers.
Register prev_next_address_reg = r14;
Register prev_limit_reg = rbx;
- Register base_reg = r12;
+ Register base_reg = r15;
movq(base_reg, next_address);
movq(prev_next_address_reg, Operand(base_reg, kNextOffset));
movq(prev_limit_reg, Operand(base_reg, kLimitOffset));
@@ -587,7 +694,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
// Check if the function scheduled an exception.
movq(rsi, scheduled_exception_address);
- Cmp(Operand(rsi, 0), Factory::the_hole_value());
+ Cmp(Operand(rsi, 0), FACTORY->the_hole_value());
j(not_equal, &promote_scheduled_exception);
LeaveApiExitFrame();
@@ -602,14 +709,20 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
bind(&empty_result);
// It was zero; the result is undefined.
- Move(rax, Factory::undefined_value());
+ Move(rax, FACTORY->undefined_value());
jmp(&prologue);
// HandleScope limit has changed. Delete allocated extensions.
bind(&delete_allocated_handles);
movq(Operand(base_reg, kLimitOffset), prev_limit_reg);
movq(prev_limit_reg, rax);
- movq(rax, ExternalReference::delete_handle_scope_extensions());
+#ifdef _WIN64
+ LoadAddress(rcx, ExternalReference::isolate_address());
+#else
+ LoadAddress(rdi, ExternalReference::isolate_address());
+#endif
+ LoadAddress(rax,
+ ExternalReference::delete_handle_scope_extensions(isolate()));
call(rax);
movq(rax, prev_limit_reg);
jmp(&leave_exit_frame);
@@ -621,7 +734,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
int result_size) {
// Set the entry point and jump to the C entry runtime stub.
- movq(rbx, ext);
+ LoadAddress(rbx, ext);
CEntryStub ces(result_size);
jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
}
@@ -630,7 +743,7 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
MaybeObject* MacroAssembler::TryJumpToExternalReference(
const ExternalReference& ext, int result_size) {
// Set the entry point and jump to the C entry runtime stub.
- movq(rbx, ext);
+ LoadAddress(rbx, ext);
CEntryStub ces(result_size);
return TryTailCallStub(&ces);
}
@@ -638,7 +751,7 @@ MaybeObject* MacroAssembler::TryJumpToExternalReference(
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
// Calls are not allowed in some stubs.
ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
@@ -647,7 +760,7 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
// parameter count to avoid emitting code to do the check.
ParameterCount expected(0);
GetBuiltinEntry(rdx, id);
- InvokeCode(rdx, expected, expected, flag, post_call_generator);
+ InvokeCode(rdx, expected, expected, flag, call_wrapper);
}
@@ -707,7 +820,7 @@ Register MacroAssembler::GetSmiConstant(Smi* source) {
}
void MacroAssembler::LoadSmiConstant(Register dst, Smi* source) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
movq(dst,
reinterpret_cast<uint64_t>(Smi::FromInt(kSmiConstantRegisterValue)),
RelocInfo::NONE);
@@ -721,11 +834,11 @@ void MacroAssembler::LoadSmiConstant(Register dst, Smi* source) {
bind(&ok);
}
}
- if (source->value() == 0) {
+ int value = source->value();
+ if (value == 0) {
xorl(dst, dst);
return;
}
- int value = source->value();
bool negative = value < 0;
unsigned int uvalue = negative ? -value : value;
@@ -776,7 +889,7 @@ void MacroAssembler::Integer32ToSmi(Register dst, Register src) {
void MacroAssembler::Integer32ToSmiField(const Operand& dst, Register src) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
testb(dst, Immediate(0x01));
NearLabel ok;
j(zero, &ok);
@@ -796,9 +909,9 @@ void MacroAssembler::Integer64PlusConstantToSmi(Register dst,
Register src,
int constant) {
if (dst.is(src)) {
- addq(dst, Immediate(constant));
+ addl(dst, Immediate(constant));
} else {
- lea(dst, Operand(src, constant));
+ leal(dst, Operand(src, constant));
}
shl(dst, Immediate(kSmiShift));
}
@@ -837,12 +950,24 @@ void MacroAssembler::SmiTest(Register src) {
}
-void MacroAssembler::SmiCompare(Register dst, Register src) {
- cmpq(dst, src);
+void MacroAssembler::SmiCompare(Register smi1, Register smi2) {
+ if (emit_debug_code()) {
+ AbortIfNotSmi(smi1);
+ AbortIfNotSmi(smi2);
+ }
+ cmpq(smi1, smi2);
}
void MacroAssembler::SmiCompare(Register dst, Smi* src) {
+ if (emit_debug_code()) {
+ AbortIfNotSmi(dst);
+ }
+ Cmp(dst, src);
+}
+
+
+void MacroAssembler::Cmp(Register dst, Smi* src) {
ASSERT(!dst.is(kScratchRegister));
if (src->value() == 0) {
testq(dst, dst);
@@ -854,20 +979,39 @@ void MacroAssembler::SmiCompare(Register dst, Smi* src) {
void MacroAssembler::SmiCompare(Register dst, const Operand& src) {
+ if (emit_debug_code()) {
+ AbortIfNotSmi(dst);
+ AbortIfNotSmi(src);
+ }
cmpq(dst, src);
}
void MacroAssembler::SmiCompare(const Operand& dst, Register src) {
+ if (emit_debug_code()) {
+ AbortIfNotSmi(dst);
+ AbortIfNotSmi(src);
+ }
cmpq(dst, src);
}
void MacroAssembler::SmiCompare(const Operand& dst, Smi* src) {
+ if (emit_debug_code()) {
+ AbortIfNotSmi(dst);
+ }
cmpl(Operand(dst, kSmiShift / kBitsPerByte), Immediate(src->value()));
}
+void MacroAssembler::Cmp(const Operand& dst, Smi* src) {
+ // The Operand cannot use the smi register.
+ Register smi_reg = GetSmiConstant(src);
+ ASSERT(!dst.AddressUsesRegister(smi_reg));
+ cmpq(dst, smi_reg);
+}
+
+
void MacroAssembler::SmiCompareInteger32(const Operand& dst, Register src) {
cmpl(Operand(dst, kSmiShift / kBitsPerByte), src);
}
@@ -1101,12 +1245,10 @@ void MacroAssembler::SmiAdd(Register dst,
// No overflow checking. Use only when it's known that
// overflowing is impossible.
ASSERT(!dst.is(src2));
- if (dst.is(src1)) {
- addq(dst, src2);
- } else {
+ if (!dst.is(src1)) {
movq(dst, src1);
- addq(dst, src2);
}
+ addq(dst, src2);
Assert(no_overflow, "Smi addition overflow");
}
@@ -1115,12 +1257,10 @@ void MacroAssembler::SmiSub(Register dst, Register src1, Register src2) {
// No overflow checking. Use only when it's known that
// overflowing is impossible (e.g., subtracting two positive smis).
ASSERT(!dst.is(src2));
- if (dst.is(src1)) {
- subq(dst, src2);
- } else {
+ if (!dst.is(src1)) {
movq(dst, src1);
- subq(dst, src2);
}
+ subq(dst, src2);
Assert(no_overflow, "Smi subtraction overflow");
}
@@ -1130,12 +1270,10 @@ void MacroAssembler::SmiSub(Register dst,
const Operand& src2) {
// No overflow checking. Use only when it's known that
// overflowing is impossible (e.g., subtracting two positive smis).
- if (dst.is(src1)) {
- subq(dst, src2);
- } else {
+ if (!dst.is(src1)) {
movq(dst, src1);
- subq(dst, src2);
}
+ subq(dst, src2);
Assert(no_overflow, "Smi subtraction overflow");
}
@@ -1322,6 +1460,13 @@ SmiIndex MacroAssembler::SmiToNegativeIndex(Register dst,
}
+void MacroAssembler::AddSmiField(Register dst, const Operand& src) {
+ ASSERT_EQ(0, kSmiShift % kBitsPerByte);
+ addl(dst, Operand(src, kSmiShift / kBitsPerByte));
+}
+
+
+
void MacroAssembler::Move(Register dst, Register src) {
if (!dst.is(src)) {
movq(dst, src);
@@ -1352,7 +1497,7 @@ void MacroAssembler::Move(const Operand& dst, Handle<Object> source) {
void MacroAssembler::Cmp(Register dst, Handle<Object> source) {
if (source->IsSmi()) {
- SmiCompare(dst, Smi::cast(*source));
+ Cmp(dst, Smi::cast(*source));
} else {
Move(kScratchRegister, source);
cmpq(dst, kScratchRegister);
@@ -1362,7 +1507,7 @@ void MacroAssembler::Cmp(Register dst, Handle<Object> source) {
void MacroAssembler::Cmp(const Operand& dst, Handle<Object> source) {
if (source->IsSmi()) {
- SmiCompare(dst, Smi::cast(*source));
+ Cmp(dst, Smi::cast(*source));
} else {
ASSERT(source->IsHeapObject());
movq(kScratchRegister, source, RelocInfo::EMBEDDED_OBJECT);
@@ -1406,7 +1551,7 @@ void MacroAssembler::Test(const Operand& src, Smi* source) {
void MacroAssembler::Jump(ExternalReference ext) {
- movq(kScratchRegister, ext);
+ LoadAddress(kScratchRegister, ext);
jmp(kScratchRegister);
}
@@ -1423,21 +1568,46 @@ void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
}
+int MacroAssembler::CallSize(ExternalReference ext) {
+ // Opcode for call kScratchRegister is: Rex.B FF D4 (three bytes).
+ const int kCallInstructionSize = 3;
+ return LoadAddressSize(ext) + kCallInstructionSize;
+}
+
+
void MacroAssembler::Call(ExternalReference ext) {
- movq(kScratchRegister, ext);
+#ifdef DEBUG
+ int end_position = pc_offset() + CallSize(ext);
+#endif
+ LoadAddress(kScratchRegister, ext);
call(kScratchRegister);
+#ifdef DEBUG
+ CHECK_EQ(end_position, pc_offset());
+#endif
}
void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
+#ifdef DEBUG
+ int end_position = pc_offset() + CallSize(destination, rmode);
+#endif
movq(kScratchRegister, destination, rmode);
call(kScratchRegister);
+#ifdef DEBUG
+ CHECK_EQ(pc_offset(), end_position);
+#endif
}
void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
+#ifdef DEBUG
+ int end_position = pc_offset() + CallSize(code_object);
+#endif
ASSERT(RelocInfo::IsCodeTarget(rmode));
call(code_object, rmode);
+#ifdef DEBUG
+ CHECK_EQ(end_position, pc_offset());
+#endif
}
@@ -1453,10 +1623,10 @@ void MacroAssembler::Pushad() {
push(r9);
// r10 is kScratchRegister.
push(r11);
- push(r12);
+ // r12 is kSmiConstantRegister.
// r13 is kRootRegister.
push(r14);
- // r15 is kSmiConstantRegister
+ push(r15);
STATIC_ASSERT(11 == kNumSafepointSavedRegisters);
// Use lea for symmetry with Popad.
int sp_delta =
@@ -1470,8 +1640,8 @@ void MacroAssembler::Popad() {
int sp_delta =
(kNumSafepointRegisters - kNumSafepointSavedRegisters) * kPointerSize;
lea(rsp, Operand(rsp, sp_delta));
+ pop(r15);
pop(r14);
- pop(r12);
pop(r11);
pop(r9);
pop(r8);
@@ -1490,7 +1660,7 @@ void MacroAssembler::Dropad() {
// Order general registers are pushed by Pushad:
-// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14.
+// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
int MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = {
0,
1,
@@ -1504,10 +1674,10 @@ int MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = {
7,
-1,
8,
- 9,
-1,
- 10,
- -1
+ -1,
+ 9,
+ 10
};
@@ -1557,18 +1727,20 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
push(Immediate(0)); // NULL frame pointer.
}
// Save the current handler.
- movq(kScratchRegister, ExternalReference(Top::k_handler_address));
- push(Operand(kScratchRegister, 0));
+ Operand handler_operand =
+ ExternalOperand(ExternalReference(Isolate::k_handler_address, isolate()));
+ push(handler_operand);
// Link this handler.
- movq(Operand(kScratchRegister, 0), rsp);
+ movq(handler_operand, rsp);
}
void MacroAssembler::PopTryHandler() {
ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
// Unlink this handler.
- movq(kScratchRegister, ExternalReference(Top::k_handler_address));
- pop(Operand(kScratchRegister, 0));
+ Operand handler_operand =
+ ExternalOperand(ExternalReference(Isolate::k_handler_address, isolate()));
+ pop(handler_operand);
// Remove the remaining fields.
addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize));
}
@@ -1586,12 +1758,11 @@ void MacroAssembler::Throw(Register value) {
movq(rax, value);
}
- ExternalReference handler_address(Top::k_handler_address);
- movq(kScratchRegister, handler_address);
- movq(rsp, Operand(kScratchRegister, 0));
+ ExternalReference handler_address(Isolate::k_handler_address, isolate());
+ Operand handler_operand = ExternalOperand(handler_address);
+ movq(rsp, handler_operand);
// get next in chain
- pop(rcx);
- movq(Operand(kScratchRegister, 0), rcx);
+ pop(handler_operand);
pop(rbp); // pop frame pointer
pop(rdx); // remove state
@@ -1614,9 +1785,8 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
movq(rax, value);
}
// Fetch top stack handler.
- ExternalReference handler_address(Top::k_handler_address);
- movq(kScratchRegister, handler_address);
- movq(rsp, Operand(kScratchRegister, 0));
+ ExternalReference handler_address(Isolate::k_handler_address, isolate());
+ Load(rsp, handler_address);
// Unwind the handlers until the ENTRY handler is found.
NearLabel loop, done;
@@ -1632,19 +1802,21 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
- movq(kScratchRegister, handler_address);
- pop(Operand(kScratchRegister, 0));
+ Operand handler_operand = ExternalOperand(handler_address);
+ pop(handler_operand);
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
- ExternalReference external_caught(Top::k_external_caught_exception_address);
+ ExternalReference external_caught(
+ Isolate::k_external_caught_exception_address, isolate());
movq(rax, Immediate(false));
- store_rax(external_caught);
+ Store(external_caught, rax);
// Set pending exception and rax to out of memory exception.
- ExternalReference pending_exception(Top::k_pending_exception_address);
+ ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ isolate());
movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
- store_rax(pending_exception);
+ Store(pending_exception, rax);
}
// Clear the context pointer.
@@ -1652,14 +1824,14 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
// Restore registers from handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset + kPointerSize ==
- StackHandlerConstants::kFPOffset);
+ StackHandlerConstants::kFPOffset);
pop(rbp); // FP
STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize ==
- StackHandlerConstants::kStateOffset);
+ StackHandlerConstants::kStateOffset);
pop(rdx); // State
STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize ==
- StackHandlerConstants::kPCOffset);
+ StackHandlerConstants::kPCOffset);
ret(0);
}
@@ -1718,7 +1890,7 @@ void MacroAssembler::AbortIfNotNumber(Register object) {
Condition is_smi = CheckSmi(object);
j(is_smi, &ok);
Cmp(FieldOperand(object, HeapObject::kMapOffset),
- Factory::heap_number_map());
+ FACTORY->heap_number_map());
Assert(equal, "Operand not a number");
bind(&ok);
}
@@ -1732,7 +1904,12 @@ void MacroAssembler::AbortIfSmi(Register object) {
void MacroAssembler::AbortIfNotSmi(Register object) {
- NearLabel ok;
+ Condition is_smi = CheckSmi(object);
+ Assert(is_smi, "Operand is not a smi");
+}
+
+
+void MacroAssembler::AbortIfNotSmi(const Operand& object) {
Condition is_smi = CheckSmi(object);
Assert(is_smi, "Operand is not a smi");
}
@@ -1819,8 +1996,8 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
if (FLAG_native_code_counters && counter->Enabled()) {
- movq(kScratchRegister, ExternalReference(counter));
- movl(Operand(kScratchRegister, 0), Immediate(value));
+ Operand counter_operand = ExternalOperand(ExternalReference(counter));
+ movq(counter_operand, Immediate(value));
}
}
@@ -1828,12 +2005,11 @@ void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
ASSERT(value > 0);
if (FLAG_native_code_counters && counter->Enabled()) {
- movq(kScratchRegister, ExternalReference(counter));
- Operand operand(kScratchRegister, 0);
+ Operand counter_operand = ExternalOperand(ExternalReference(counter));
if (value == 1) {
- incl(operand);
+ incl(counter_operand);
} else {
- addl(operand, Immediate(value));
+ addl(counter_operand, Immediate(value));
}
}
}
@@ -1842,12 +2018,11 @@ void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
ASSERT(value > 0);
if (FLAG_native_code_counters && counter->Enabled()) {
- movq(kScratchRegister, ExternalReference(counter));
- Operand operand(kScratchRegister, 0);
+ Operand counter_operand = ExternalOperand(ExternalReference(counter));
if (value == 1) {
- decl(operand);
+ decl(counter_operand);
} else {
- subl(operand, Immediate(value));
+ subl(counter_operand, Immediate(value));
}
}
}
@@ -1857,7 +2032,7 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
void MacroAssembler::DebugBreak() {
ASSERT(allow_stub_calls());
Set(rax, 0); // No arguments.
- movq(rbx, ExternalReference(Runtime::kDebugBreak));
+ LoadAddress(rbx, ExternalReference(Runtime::kDebugBreak, isolate()));
CEntryStub ces(1);
Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
}
@@ -1868,7 +2043,7 @@ void MacroAssembler::InvokeCode(Register code,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
NearLabel done;
InvokePrologue(expected,
actual,
@@ -1876,10 +2051,11 @@ void MacroAssembler::InvokeCode(Register code,
code,
&done,
flag,
- post_call_generator);
+ call_wrapper);
if (flag == CALL_FUNCTION) {
+ if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(code));
call(code);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ if (call_wrapper != NULL) call_wrapper->AfterCall();
} else {
ASSERT(flag == JUMP_FUNCTION);
jmp(code);
@@ -1893,7 +2069,7 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
NearLabel done;
Register dummy = rax;
InvokePrologue(expected,
@@ -1902,10 +2078,11 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
dummy,
&done,
flag,
- post_call_generator);
+ call_wrapper);
if (flag == CALL_FUNCTION) {
+ if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(code));
Call(code, rmode);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ if (call_wrapper != NULL) call_wrapper->AfterCall();
} else {
ASSERT(flag == JUMP_FUNCTION);
Jump(code, rmode);
@@ -1917,7 +2094,7 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
void MacroAssembler::InvokeFunction(Register function,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
ASSERT(function.is(rdi));
movq(rdx, FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
movq(rsi, FieldOperand(function, JSFunction::kContextOffset));
@@ -1928,14 +2105,14 @@ void MacroAssembler::InvokeFunction(Register function,
movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
ParameterCount expected(rbx);
- InvokeCode(rdx, expected, actual, flag, post_call_generator);
+ InvokeCode(rdx, expected, actual, flag, call_wrapper);
}
void MacroAssembler::InvokeFunction(JSFunction* function,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
ASSERT(function->is_compiled());
// Get the function and setup the context.
Move(rdi, Handle<JSFunction>(function));
@@ -1946,7 +2123,7 @@ void MacroAssembler::InvokeFunction(JSFunction* function,
// the Code object every time we call the function.
movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
ParameterCount expected(function->shared()->formal_parameter_count());
- InvokeCode(rdx, expected, actual, flag, post_call_generator);
+ InvokeCode(rdx, expected, actual, flag, call_wrapper);
} else {
// Invoke the cached code.
Handle<Code> code(function->code());
@@ -1956,7 +2133,7 @@ void MacroAssembler::InvokeFunction(JSFunction* function,
actual,
RelocInfo::CODE_TARGET,
flag,
- post_call_generator);
+ call_wrapper);
}
}
@@ -1968,9 +2145,9 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) {
Push(Smi::FromInt(type));
movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
push(kScratchRegister);
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
movq(kScratchRegister,
- Factory::undefined_value(),
+ FACTORY->undefined_value(),
RelocInfo::EMBEDDED_OBJECT);
cmpq(Operand(rsp, 0), kScratchRegister);
Check(not_equal, "code object not properly patched");
@@ -1979,7 +2156,7 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) {
void MacroAssembler::LeaveFrame(StackFrame::Type type) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
Move(kScratchRegister, Smi::FromInt(type));
cmpq(Operand(rbp, StandardFrameConstants::kMarkerOffset), kScratchRegister);
Check(equal, "stack frame types must match");
@@ -2005,16 +2182,12 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax) {
push(kScratchRegister); // Accessed from EditFrame::code_slot.
// Save the frame pointer and the context in top.
- ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
- ExternalReference context_address(Top::k_context_address);
if (save_rax) {
- movq(r14, rax); // Backup rax before we use it.
+ movq(r14, rax); // Backup rax in callee-save register.
}
- movq(rax, rbp);
- store_rax(c_entry_fp_address);
- movq(rax, rsi);
- store_rax(context_address);
+ Store(ExternalReference(Isolate::k_c_entry_fp_address, isolate()), rbp);
+ Store(ExternalReference(Isolate::k_context_address, isolate()), rsi);
}
@@ -2040,7 +2213,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space,
}
// Get the required frame alignment for the OS.
- static const int kFrameAlignment = OS::ActivationFrameAlignment();
+ const int kFrameAlignment = OS::ActivationFrameAlignment();
if (kFrameAlignment > 0) {
ASSERT(IsPowerOf2(kFrameAlignment));
movq(kScratchRegister, Immediate(-kFrameAlignment));
@@ -2055,10 +2228,10 @@ void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space,
void MacroAssembler::EnterExitFrame(int arg_stack_space, bool save_doubles) {
EnterExitFramePrologue(true);
- // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
+ // Setup argv in callee-saved register r15. It is reused in LeaveExitFrame,
// so it must be retained across the C-call.
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
- lea(r12, Operand(rbp, r14, times_pointer_size, offset));
+ lea(r15, Operand(rbp, r14, times_pointer_size, offset));
EnterExitFrameEpilogue(arg_stack_space, save_doubles);
}
@@ -2072,7 +2245,7 @@ void MacroAssembler::EnterApiExitFrame(int arg_stack_space) {
void MacroAssembler::LeaveExitFrame(bool save_doubles) {
// Registers:
- // r12 : argv
+ // r15 : argv
if (save_doubles) {
int offset = -2 * kPointerSize;
for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) {
@@ -2086,7 +2259,7 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) {
// Drop everything up to and including the arguments and the receiver
// from the caller stack.
- lea(rsp, Operand(r12, 1 * kPointerSize));
+ lea(rsp, Operand(r15, 1 * kPointerSize));
// Push the return address to get ready to return.
push(rcx);
@@ -2105,17 +2278,18 @@ void MacroAssembler::LeaveApiExitFrame() {
void MacroAssembler::LeaveExitFrameEpilogue() {
// Restore current context from top and clear it in debug mode.
- ExternalReference context_address(Top::k_context_address);
- movq(kScratchRegister, context_address);
- movq(rsi, Operand(kScratchRegister, 0));
+ ExternalReference context_address(Isolate::k_context_address, isolate());
+ Operand context_operand = ExternalOperand(context_address);
+ movq(rsi, context_operand);
#ifdef DEBUG
- movq(Operand(kScratchRegister, 0), Immediate(0));
+ movq(context_operand, Immediate(0));
#endif
// Clear the top frame.
- ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
- movq(kScratchRegister, c_entry_fp_address);
- movq(Operand(kScratchRegister, 0), Immediate(0));
+ ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address,
+ isolate());
+ Operand c_entry_fp_operand = ExternalOperand(c_entry_fp_address);
+ movq(c_entry_fp_operand, Immediate(0));
}
@@ -2130,7 +2304,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
movq(scratch, Operand(rbp, StandardFrameConstants::kContextOffset));
// When generating debug code, make sure the lexical context is set.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
cmpq(scratch, Immediate(0));
Check(not_equal, "we should not have an empty lexical context");
}
@@ -2140,9 +2314,9 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
// Check the context is a global context.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
Cmp(FieldOperand(scratch, HeapObject::kMapOffset),
- Factory::global_context_map());
+ FACTORY->global_context_map());
Check(equal, "JSGlobalObject::global_context should be a global context.");
}
@@ -2156,7 +2330,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
// object.
// Check the context is a global context.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Preserve original value of holder_reg.
push(holder_reg);
movq(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
@@ -2186,7 +2360,7 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
Register scratch,
AllocationFlags flags) {
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
// Just return if allocation top is already known.
if ((flags & RESULT_CONTAINS_TOP) != 0) {
@@ -2194,8 +2368,8 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
ASSERT(!scratch.is_valid());
#ifdef DEBUG
// Assert that result actually contains top on entry.
- movq(kScratchRegister, new_space_allocation_top);
- cmpq(result, Operand(kScratchRegister, 0));
+ Operand top_operand = ExternalOperand(new_space_allocation_top);
+ cmpq(result, top_operand);
Check(equal, "Unexpected allocation top");
#endif
return;
@@ -2204,39 +2378,30 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
// Move address of new object to result. Use scratch register if available,
// and keep address in scratch until call to UpdateAllocationTopHelper.
if (scratch.is_valid()) {
- movq(scratch, new_space_allocation_top);
+ LoadAddress(scratch, new_space_allocation_top);
movq(result, Operand(scratch, 0));
- } else if (result.is(rax)) {
- load_rax(new_space_allocation_top);
} else {
- movq(kScratchRegister, new_space_allocation_top);
- movq(result, Operand(kScratchRegister, 0));
+ Load(result, new_space_allocation_top);
}
}
void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
Register scratch) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
testq(result_end, Immediate(kObjectAlignmentMask));
Check(zero, "Unaligned allocation in new space");
}
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
// Update new top.
- if (result_end.is(rax)) {
- // rax can be stored directly to a memory location.
- store_rax(new_space_allocation_top);
+ if (scratch.is_valid()) {
+ // Scratch already contains address of allocation top.
+ movq(Operand(scratch, 0), result_end);
} else {
- // Register required - use scratch provided if available.
- if (scratch.is_valid()) {
- movq(Operand(scratch, 0), result_end);
- } else {
- movq(kScratchRegister, new_space_allocation_top);
- movq(Operand(kScratchRegister, 0), result_end);
- }
+ Store(new_space_allocation_top, result_end);
}
}
@@ -2248,7 +2413,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
Label* gc_required,
AllocationFlags flags) {
if (!FLAG_inline_new) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
movl(result, Immediate(0x7091));
if (result_end.is_valid()) {
@@ -2268,7 +2433,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
Register top_reg = result_end.is_valid() ? result_end : result;
@@ -2277,8 +2442,8 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
}
addq(top_reg, Immediate(object_size));
j(carry, gc_required);
- movq(kScratchRegister, new_space_allocation_limit);
- cmpq(top_reg, Operand(kScratchRegister, 0));
+ Operand limit_operand = ExternalOperand(new_space_allocation_limit);
+ cmpq(top_reg, limit_operand);
j(above, gc_required);
// Update allocation top.
@@ -2306,7 +2471,7 @@ void MacroAssembler::AllocateInNewSpace(int header_size,
Label* gc_required,
AllocationFlags flags) {
if (!FLAG_inline_new) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
movl(result, Immediate(0x7091));
movl(result_end, Immediate(0x7191));
@@ -2325,15 +2490,15 @@ void MacroAssembler::AllocateInNewSpace(int header_size,
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
// We assume that element_count*element_size + header_size does not
// overflow.
lea(result_end, Operand(element_count, element_size, header_size));
addq(result_end, result);
j(carry, gc_required);
- movq(kScratchRegister, new_space_allocation_limit);
- cmpq(result_end, Operand(kScratchRegister, 0));
+ Operand limit_operand = ExternalOperand(new_space_allocation_limit);
+ cmpq(result_end, limit_operand);
j(above, gc_required);
// Update allocation top.
@@ -2353,7 +2518,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
Label* gc_required,
AllocationFlags flags) {
if (!FLAG_inline_new) {
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
movl(result, Immediate(0x7091));
movl(result_end, Immediate(0x7191));
@@ -2372,14 +2537,14 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
if (!object_size.is(result_end)) {
movq(result_end, object_size);
}
addq(result_end, result);
j(carry, gc_required);
- movq(kScratchRegister, new_space_allocation_limit);
- cmpq(result_end, Operand(kScratchRegister, 0));
+ Operand limit_operand = ExternalOperand(new_space_allocation_limit);
+ cmpq(result_end, limit_operand);
j(above, gc_required);
// Update allocation top.
@@ -2394,16 +2559,16 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
void MacroAssembler::UndoAllocationInNewSpace(Register object) {
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
// Make sure the object has no tag before resetting top.
and_(object, Immediate(~kHeapObjectTagMask));
- movq(kScratchRegister, new_space_allocation_top);
+ Operand top_operand = ExternalOperand(new_space_allocation_top);
#ifdef DEBUG
- cmpq(object, Operand(kScratchRegister, 0));
+ cmpq(object, top_operand);
Check(below, "Undo allocation of non allocated memory");
#endif
- movq(Operand(kScratchRegister, 0), object);
+ movq(top_operand, object);
}
@@ -2537,6 +2702,70 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
}
+// Copy memory, byte-by-byte, from source to destination. Not optimized for
+// long or aligned copies. The contents of scratch and length are destroyed.
+// Destination is incremented by length, source, length and scratch are
+// clobbered.
+// A simpler loop is faster on small copies, but slower on large ones.
+// The cld() instruction must have been emitted, to set the direction flag(),
+// before calling this function.
+void MacroAssembler::CopyBytes(Register destination,
+ Register source,
+ Register length,
+ int min_length,
+ Register scratch) {
+ ASSERT(min_length >= 0);
+ if (FLAG_debug_code) {
+ cmpl(length, Immediate(min_length));
+ Assert(greater_equal, "Invalid min_length");
+ }
+ Label loop, done, short_string, short_loop;
+
+ const int kLongStringLimit = 20;
+ if (min_length <= kLongStringLimit) {
+ cmpl(length, Immediate(kLongStringLimit));
+ j(less_equal, &short_string);
+ }
+
+ ASSERT(source.is(rsi));
+ ASSERT(destination.is(rdi));
+ ASSERT(length.is(rcx));
+
+ // Because source is 8-byte aligned in our uses of this function,
+ // we keep source aligned for the rep movs operation by copying the odd bytes
+ // at the end of the ranges.
+ movq(scratch, length);
+ shrl(length, Immediate(3));
+ repmovsq();
+ // Move remaining bytes of length.
+ andl(scratch, Immediate(0x7));
+ movq(length, Operand(source, scratch, times_1, -8));
+ movq(Operand(destination, scratch, times_1, -8), length);
+ addq(destination, scratch);
+
+ if (min_length <= kLongStringLimit) {
+ jmp(&done);
+
+ bind(&short_string);
+ if (min_length == 0) {
+ testl(length, length);
+ j(zero, &done);
+ }
+ lea(scratch, Operand(destination, length, times_1, 0));
+
+ bind(&short_loop);
+ movb(length, Operand(source, 0));
+ movb(Operand(destination, 0), length);
+ incq(source);
+ incq(destination);
+ cmpq(destination, scratch);
+ j(not_equal, &short_loop);
+
+ bind(&done);
+ }
+}
+
+
void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
if (context_chain_length > 0) {
// Move up the chain of contexts to the context containing the slot.
@@ -2560,13 +2789,18 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
// (i.e., the static scope chain and runtime context chain do not agree).
// A variable occurring in such a scope should have slot type LOOKUP and
// not CONTEXT.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
cmpq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
Check(equal, "Yo dawg, I heard you liked function contexts "
"so I put function contexts in all your contexts");
}
}
+#ifdef _WIN64
+static const int kRegisterPassedArguments = 4;
+#else
+static const int kRegisterPassedArguments = 6;
+#endif
void MacroAssembler::LoadGlobalFunction(int index, Register function) {
// Load the global or builtins object from the current context.
@@ -2582,9 +2816,9 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
Register map) {
// Load the initial map. The global functions all have initial maps.
movq(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
Label ok, fail;
- CheckMap(map, Factory::meta_map(), &fail, false);
+ CheckMap(map, FACTORY->meta_map(), &fail, false);
jmp(&ok);
bind(&fail);
Abort("Global functions must have initial map");
@@ -2602,11 +2836,10 @@ int MacroAssembler::ArgumentStackSlotsForCFunctionCall(int num_arguments) {
// and the caller does not reserve stack slots for them.
ASSERT(num_arguments >= 0);
#ifdef _WIN64
- static const int kMinimumStackSlots = 4;
+ const int kMinimumStackSlots = kRegisterPassedArguments;
if (num_arguments < kMinimumStackSlots) return kMinimumStackSlots;
return num_arguments;
#else
- static const int kRegisterPassedArguments = 6;
if (num_arguments < kRegisterPassedArguments) return 0;
return num_arguments - kRegisterPassedArguments;
#endif
@@ -2617,6 +2850,10 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments) {
int frame_alignment = OS::ActivationFrameAlignment();
ASSERT(frame_alignment != 0);
ASSERT(num_arguments >= 0);
+
+ // Reserve space for Isolate address which is always passed as last parameter
+ num_arguments += 1;
+
// Make stack end at alignment and allocate space for arguments and old rsp.
movq(kScratchRegister, rsp);
ASSERT(IsPowerOf2(frame_alignment));
@@ -2630,20 +2867,41 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments) {
void MacroAssembler::CallCFunction(ExternalReference function,
int num_arguments) {
- movq(rax, function);
+ LoadAddress(rax, function);
CallCFunction(rax, num_arguments);
}
void MacroAssembler::CallCFunction(Register function, int num_arguments) {
+ // Pass current isolate address as additional parameter.
+ if (num_arguments < kRegisterPassedArguments) {
+#ifdef _WIN64
+ // First four arguments are passed in registers on Windows.
+ Register arg_to_reg[] = {rcx, rdx, r8, r9};
+#else
+ // First six arguments are passed in registers on other platforms.
+ Register arg_to_reg[] = {rdi, rsi, rdx, rcx, r8, r9};
+#endif
+ Register reg = arg_to_reg[num_arguments];
+ LoadAddress(reg, ExternalReference::isolate_address());
+ } else {
+ // Push Isolate pointer after all parameters.
+ int argument_slots_on_stack =
+ ArgumentStackSlotsForCFunctionCall(num_arguments);
+ LoadAddress(kScratchRegister, ExternalReference::isolate_address());
+ movq(Operand(rsp, argument_slots_on_stack * kPointerSize),
+ kScratchRegister);
+ }
+
// Check stack alignment.
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
CheckStackAlignment();
}
call(function);
ASSERT(OS::ActivationFrameAlignment() != 0);
ASSERT(num_arguments >= 0);
+ num_arguments += 1;
int argument_slots_on_stack =
ArgumentStackSlotsForCFunctionCall(num_arguments);
movq(rsp, Operand(rsp, argument_slots_on_stack * kPointerSize));
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 7a7f1a27..1ee0fe02 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -48,7 +48,7 @@ enum AllocationFlags {
// a spare register). The register isn't callee save, and not used by the
// function calling convention.
static const Register kScratchRegister = { 10 }; // r10.
-static const Register kSmiConstantRegister = { 15 }; // r15 (callee save).
+static const Register kSmiConstantRegister = { 12 }; // r12 (callee save).
static const Register kRootRegister = { 13 }; // r13 (callee save).
// Value of smi in kSmiConstantRegister.
static const int kSmiConstantRegisterValue = 1;
@@ -61,7 +61,7 @@ typedef Operand MemOperand;
// Forward declaration.
class JumpTarget;
-class PostCallGenerator;
+class CallWrapper;
struct SmiIndex {
SmiIndex(Register index_register, ScaleFactor scale)
@@ -76,7 +76,49 @@ class MacroAssembler: public Assembler {
public:
MacroAssembler(void* buffer, int size);
+ // Prevent the use of the RootArray during the lifetime of this
+ // scope object.
+ class NoRootArrayScope BASE_EMBEDDED {
+ public:
+ explicit NoRootArrayScope(MacroAssembler* assembler)
+ : variable_(&assembler->root_array_available_),
+ old_value_(assembler->root_array_available_) {
+ assembler->root_array_available_ = false;
+ }
+ ~NoRootArrayScope() {
+ *variable_ = old_value_;
+ }
+ private:
+ bool* variable_;
+ bool old_value_;
+ };
+
+ // Operand pointing to an external reference.
+ // May emit code to set up the scratch register. The operand is
+ // only guaranteed to be correct as long as the scratch register
+ // isn't changed.
+ // If the operand is used more than once, use a scratch register
+ // that is guaranteed not to be clobbered.
+ Operand ExternalOperand(ExternalReference reference,
+ Register scratch = kScratchRegister);
+ // Loads and stores the value of an external reference.
+ // Special case code for load and store to take advantage of
+ // load_rax/store_rax if possible/necessary.
+ // For other operations, just use:
+ // Operand operand = ExternalOperand(extref);
+ // operation(operand, ..);
+ void Load(Register destination, ExternalReference source);
+ void Store(ExternalReference destination, Register source);
+ // Loads the address of the external reference into the destination
+ // register.
+ void LoadAddress(Register destination, ExternalReference source);
+ // Returns the size of the code generated by LoadAddress.
+ // Used by CallSize(ExternalReference) to find the size of a call.
+ int LoadAddressSize(ExternalReference source);
+
+ // Operations on roots in the root-array.
void LoadRoot(Register destination, Heap::RootListIndex index);
+ void StoreRoot(Register source, Heap::RootListIndex index);
// Load a root value where the index (or part of it) is variable.
// The variable_offset register is added to the fixed_offset value
// to get the index into the root-array.
@@ -86,7 +128,6 @@ class MacroAssembler: public Assembler {
void CompareRoot(Register with, Heap::RootListIndex index);
void CompareRoot(const Operand& with, Heap::RootListIndex index);
void PushRoot(Heap::RootListIndex index);
- void StoreRoot(Register source, Heap::RootListIndex index);
// ---------------------------------------------------------------------------
// GC Support
@@ -186,7 +227,8 @@ class MacroAssembler: public Assembler {
void LoadFromSafepointRegisterSlot(Register dst, Register src);
void InitializeRootRegister() {
- ExternalReference roots_address = ExternalReference::roots_address();
+ ExternalReference roots_address =
+ ExternalReference::roots_address(isolate());
movq(kRootRegister, roots_address);
addq(kRootRegister, Immediate(kRootRegisterBias));
}
@@ -199,32 +241,32 @@ class MacroAssembler: public Assembler {
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
void InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
// Invoke the JavaScript function in the given register. Changes the
// current context to the context in the function before invoking.
void InvokeFunction(Register function,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
void InvokeFunction(JSFunction* function,
const ParameterCount& actual,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
// Invoke specified builtin JavaScript function. Adds an entry to
// the unresolved list if the name does not resolve.
void InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
- PostCallGenerator* post_call_generator = NULL);
+ CallWrapper* call_wrapper = NULL);
// Store the function for the given builtin in the target register.
void GetBuiltinFunction(Register target, Builtins::JavaScript id);
@@ -278,8 +320,9 @@ class MacroAssembler: public Assembler {
int power);
- // Simple comparison of smis.
- void SmiCompare(Register dst, Register src);
+ // Simple comparison of smis. Both sides must be known smis to use these,
+ // otherwise use Cmp.
+ void SmiCompare(Register smi1, Register smi2);
void SmiCompare(Register dst, Smi* src);
void SmiCompare(Register dst, const Operand& src);
void SmiCompare(const Operand& dst, Register src);
@@ -427,6 +470,11 @@ class MacroAssembler: public Assembler {
Register src1,
Register src2,
LabelType* on_not_smi_result);
+ template <typename LabelType>
+ void SmiAdd(Register dst,
+ Register src1,
+ const Operand& src2,
+ LabelType* on_not_smi_result);
void SmiAdd(Register dst,
Register src1,
@@ -547,6 +595,10 @@ class MacroAssembler: public Assembler {
// Converts a positive smi to a negative index.
SmiIndex SmiToNegativeIndex(Register dst, Register src, int shift);
+ // Add the value of a smi in memory to an int32 register.
+ // Sets flags as a normal add.
+ void AddSmiField(Register dst, const Operand& src);
+
// Basic Smi operations.
void Move(Register dst, Smi* source) {
LoadSmiConstant(dst, source);
@@ -609,6 +661,8 @@ class MacroAssembler: public Assembler {
void Move(const Operand& dst, Handle<Object> source);
void Cmp(Register dst, Handle<Object> source);
void Cmp(const Operand& dst, Handle<Object> source);
+ void Cmp(Register dst, Smi* src);
+ void Cmp(const Operand& dst, Smi* src);
void Push(Handle<Object> source);
// Emit code to discard a non-negative number of pointer-sized elements
@@ -626,6 +680,24 @@ class MacroAssembler: public Assembler {
void Call(ExternalReference ext);
void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
+ // The size of the code generated for different call instructions.
+ int CallSize(Address destination, RelocInfo::Mode rmode) {
+ return kCallInstructionLength;
+ }
+ int CallSize(ExternalReference ext);
+ int CallSize(Handle<Code> code_object) {
+ // Code calls use 32-bit relative addressing.
+ return kShortCallInstructionLength;
+ }
+ int CallSize(Register target) {
+ // Opcode: REX_opt FF /2 m64
+ return (target.high_bit() != 0) ? 3 : 2;
+ }
+ int CallSize(const Operand& target) {
+ // Opcode: REX_opt FF /2 m64
+ return (target.requires_rex() ? 2 : 1) + target.operand_size();
+ }
+
// Emit call to the code we are currently generating.
void CallSelf() {
Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
@@ -682,6 +754,7 @@ class MacroAssembler: public Assembler {
// Abort execution if argument is not a smi. Used in debug code.
void AbortIfNotSmi(Register object);
+ void AbortIfNotSmi(const Operand& object);
// Abort execution if argument is a string. Used in debug code.
void AbortIfNotString(Register object);
@@ -864,7 +937,7 @@ class MacroAssembler: public Assembler {
void StubReturn(int argc);
// Call a runtime routine.
- void CallRuntime(Runtime::Function* f, int num_arguments);
+ void CallRuntime(const Runtime::Function* f, int num_arguments);
// Call a runtime function and save the value of XMM registers.
void CallRuntimeSaveDoubles(Runtime::FunctionId id);
@@ -872,7 +945,7 @@ class MacroAssembler: public Assembler {
// Call a runtime function, returning the CodeStub object called.
// Try to generate the stub code if necessary. Do not perform a GC
// but instead return a retry after GC failure.
- MUST_USE_RESULT MaybeObject* TryCallRuntime(Runtime::Function* f,
+ MUST_USE_RESULT MaybeObject* TryCallRuntime(const Runtime::Function* f,
int num_arguments);
// Convenience function: Same as above, but takes the fid instead.
@@ -921,7 +994,7 @@ class MacroAssembler: public Assembler {
// Calls an API function. Allocates HandleScope, extracts
// returned value from handle and propagates exceptions.
- // Clobbers r12, r14, rbx and caller-save registers. Restores context.
+ // Clobbers r14, r15, rbx and caller-save registers. Restores context.
// On return removes stack_space * kPointerSize (GCed).
MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn(
ApiFunction* function, int stack_space);
@@ -958,6 +1031,18 @@ class MacroAssembler: public Assembler {
Handle<Object> CodeObject() { return code_object_; }
+ // Copy length bytes from source to destination.
+ // Uses scratch register internally (if you have a low-eight register
+ // free, do use it, otherwise kScratchRegister will be used).
+ // The min_length is a minimum limit on the value that length will have.
+ // The algorithm has some special cases that might be omitted if the string
+ // is known to always be long.
+ void CopyBytes(Register destination,
+ Register source,
+ Register length,
+ int min_length = 0,
+ Register scratch = kScratchRegister);
+
// ---------------------------------------------------------------------------
// StatsCounter support
@@ -993,12 +1078,13 @@ class MacroAssembler: public Assembler {
private:
// Order general registers are pushed by Pushad.
- // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14.
+ // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
static int kSafepointPushRegisterIndices[Register::kNumRegisters];
static const int kNumSafepointSavedRegisters = 11;
bool generating_stub_;
bool allow_stub_calls_;
+ bool root_array_available_;
// Returns a register holding the smi value. The register MUST NOT be
// modified. It may be the "smi 1 constant" register.
@@ -1018,7 +1104,7 @@ class MacroAssembler: public Assembler {
Register code_register,
LabelType* done,
InvokeFlag flag,
- PostCallGenerator* post_call_generator);
+ CallWrapper* call_wrapper);
// Activation support.
void EnterFrame(StackFrame::Type type);
@@ -1084,13 +1170,17 @@ class CodePatcher {
// Helper class for generating code or data associated with the code
-// right after a call instruction. As an example this can be used to
+// right before or after a call instruction. As an example this can be used to
// generate safepoint data after calls for crankshaft.
-class PostCallGenerator {
+class CallWrapper {
public:
- PostCallGenerator() { }
- virtual ~PostCallGenerator() { }
- virtual void Generate() = 0;
+ CallWrapper() { }
+ virtual ~CallWrapper() { }
+ // Called just before emitting a call. Argument is the size of the generated
+ // call code.
+ virtual void BeforeCall(int call_size) = 0;
+ // Called just after emitting a call, i.e., at the return site for the call.
+ virtual void AfterCall() = 0;
};
@@ -1204,6 +1294,26 @@ void MacroAssembler::SmiAdd(Register dst,
template <typename LabelType>
+void MacroAssembler::SmiAdd(Register dst,
+ Register src1,
+ const Operand& src2,
+ LabelType* on_not_smi_result) {
+ ASSERT_NOT_NULL(on_not_smi_result);
+ if (dst.is(src1)) {
+ movq(kScratchRegister, src1);
+ addq(kScratchRegister, src2);
+ j(overflow, on_not_smi_result);
+ movq(dst, kScratchRegister);
+ } else {
+ ASSERT(!src2.AddressUsesRegister(dst));
+ movq(dst, src1);
+ addq(dst, src2);
+ j(overflow, on_not_smi_result);
+ }
+}
+
+
+template <typename LabelType>
void MacroAssembler::SmiSub(Register dst,
Register src1,
Register src2,
@@ -1769,26 +1879,26 @@ void MacroAssembler::InNewSpace(Register object,
// case the size of the new space is different between the snapshot maker
// and the running system.
if (scratch.is(object)) {
- movq(kScratchRegister, ExternalReference::new_space_mask());
+ movq(kScratchRegister, ExternalReference::new_space_mask(isolate()));
and_(scratch, kScratchRegister);
} else {
- movq(scratch, ExternalReference::new_space_mask());
+ movq(scratch, ExternalReference::new_space_mask(isolate()));
and_(scratch, object);
}
- movq(kScratchRegister, ExternalReference::new_space_start());
+ movq(kScratchRegister, ExternalReference::new_space_start(isolate()));
cmpq(scratch, kScratchRegister);
j(cc, branch);
} else {
- ASSERT(is_int32(static_cast<int64_t>(Heap::NewSpaceMask())));
+ ASSERT(is_int32(static_cast<int64_t>(HEAP->NewSpaceMask())));
intptr_t new_space_start =
- reinterpret_cast<intptr_t>(Heap::NewSpaceStart());
+ reinterpret_cast<intptr_t>(HEAP->NewSpaceStart());
movq(kScratchRegister, -new_space_start, RelocInfo::NONE);
if (scratch.is(object)) {
addq(scratch, kScratchRegister);
} else {
lea(scratch, Operand(object, kScratchRegister, times_1, 0));
}
- and_(scratch, Immediate(static_cast<int32_t>(Heap::NewSpaceMask())));
+ and_(scratch, Immediate(static_cast<int32_t>(HEAP->NewSpaceMask())));
j(cc, branch);
}
}
@@ -1801,7 +1911,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Register code_register,
LabelType* done,
InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+ CallWrapper* call_wrapper) {
bool definitely_matches = false;
NearLabel invoke;
if (expected.is_immediate()) {
@@ -1841,8 +1951,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
}
if (!definitely_matches) {
- Handle<Code> adaptor =
- Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
+ Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (!code_constant.is_null()) {
movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT);
addq(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag));
@@ -1851,8 +1960,9 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
}
if (flag == CALL_FUNCTION) {
+ if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(adaptor));
Call(adaptor, RelocInfo::CODE_TARGET);
- if (post_call_generator != NULL) post_call_generator->Generate();
+ if (call_wrapper != NULL) call_wrapper->AfterCall();
jmp(done);
} else {
Jump(adaptor, RelocInfo::CODE_TARGET);
diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc
index cd3bfbd4..269e7afa 100644
--- a/src/x64/regexp-macro-assembler-x64.cc
+++ b/src/x64/regexp-macro-assembler-x64.cc
@@ -63,11 +63,16 @@ namespace internal {
*
* The registers rax, rbx, r9 and r11 are free to use for computations.
* If changed to use r12+, they should be saved as callee-save registers.
+ * The macro assembler special registers r12 and r13 (kSmiConstantRegister,
+ * kRootRegister) aren't special during execution of RegExp code (they don't
+ * hold the values assumed when creating JS code), so no Smi or Root related
+ * macro operations can be used.
*
* Each call to a C++ method should retain these registers.
*
* The stack will have the following content, in some order, indexable from the
* frame pointer (see, e.g., kStackHighEnd):
+ * - Isolate* isolate (Address of the current isolate)
* - direct_call (if 1, direct call from JavaScript code, if 0 call
* through the runtime system)
* - stack_area_base (High end of the memory area to use as
@@ -104,12 +109,13 @@ namespace internal {
* bool direct_call)
*/
-#define __ ACCESS_MASM(masm_)
+#define __ ACCESS_MASM((&masm_))
RegExpMacroAssemblerX64::RegExpMacroAssemblerX64(
Mode mode,
int registers_to_save)
- : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
+ : masm_(NULL, kRegExpCodeSize),
+ no_root_array_scope_(&masm_),
code_relative_fixup_positions_(4),
mode_(mode),
num_registers_(registers_to_save),
@@ -126,7 +132,6 @@ RegExpMacroAssemblerX64::RegExpMacroAssemblerX64(
RegExpMacroAssemblerX64::~RegExpMacroAssemblerX64() {
- delete masm_;
// Unuse labels in case we throw away the assembler without calling GetCode.
entry_label_.Unuse();
start_label_.Unuse();
@@ -422,11 +427,11 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
__ movq(rdx, rbx);
#endif
ExternalReference compare =
- ExternalReference::re_case_insensitive_compare_uc16();
+ ExternalReference::re_case_insensitive_compare_uc16(masm_.isolate());
__ CallCFunction(compare, num_arguments);
// Restore original values before reacting on result value.
- __ Move(code_object_pointer(), masm_->CodeObject());
+ __ Move(code_object_pointer(), masm_.CodeObject());
__ pop(backtrack_stackpointer());
#ifndef _WIN64
__ pop(rdi);
@@ -740,7 +745,7 @@ Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(masm_.isolate());
__ movq(rcx, rsp);
__ movq(kScratchRegister, stack_limit);
__ subq(rcx, Operand(kScratchRegister, 0));
@@ -756,7 +761,7 @@ Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
__ jmp(&exit_label_);
__ bind(&stack_limit_hit);
- __ Move(code_object_pointer(), masm_->CodeObject());
+ __ Move(code_object_pointer(), masm_.CodeObject());
CallCheckStackGuardState(); // Preserves no registers beside rbp and rsp.
__ testq(rax, rax);
// If returned value is non-zero, we exit with the returned value as result.
@@ -811,7 +816,7 @@ Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
// Initialize backtrack stack pointer.
__ movq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
// Initialize code object pointer.
- __ Move(code_object_pointer(), masm_->CodeObject());
+ __ Move(code_object_pointer(), masm_.CodeObject());
// Load previous char as initial value of current-character.
Label at_start;
__ cmpb(Operand(rbp, kStartIndex), Immediate(0));
@@ -892,7 +897,7 @@ Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
__ j(not_zero, &exit_label_);
// Restore registers.
- __ Move(code_object_pointer(), masm_->CodeObject());
+ __ Move(code_object_pointer(), masm_.CodeObject());
__ pop(rdi);
__ pop(backtrack_stackpointer());
// String might have moved: Reload esi from frame.
@@ -925,7 +930,8 @@ Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
__ movq(rdi, backtrack_stackpointer()); // First argument.
__ lea(rsi, Operand(rbp, kStackHighEnd)); // Second argument.
#endif
- ExternalReference grow_stack = ExternalReference::re_grow_stack();
+ ExternalReference grow_stack =
+ ExternalReference::re_grow_stack(masm_.isolate());
__ CallCFunction(grow_stack, num_arguments);
// If return NULL, we have failed to grow the stack, and
// must exit with a stack-overflow exception.
@@ -934,7 +940,7 @@ Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
// Otherwise use return value as new stack pointer.
__ movq(backtrack_stackpointer(), rax);
// Restore saved registers and continue.
- __ Move(code_object_pointer(), masm_->CodeObject());
+ __ Move(code_object_pointer(), masm_.CodeObject());
#ifndef _WIN64
__ pop(rdi);
__ pop(rsi);
@@ -953,11 +959,12 @@ Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
FixupCodeRelativePositions();
CodeDesc code_desc;
- masm_->GetCode(&code_desc);
- Handle<Code> code = Factory::NewCode(code_desc,
- Code::ComputeFlags(Code::REGEXP),
- masm_->CodeObject());
- PROFILE(RegExpCodeCreateEvent(*code, *source));
+ masm_.GetCode(&code_desc);
+ Isolate* isolate = ISOLATE;
+ Handle<Code> code = isolate->factory()->NewCode(
+ code_desc, Code::ComputeFlags(Code::REGEXP),
+ masm_.CodeObject());
+ PROFILE(isolate, RegExpCodeCreateEvent(*code, *source));
return Handle<Object>::cast(code);
}
@@ -1126,7 +1133,7 @@ void RegExpMacroAssemblerX64::CallCheckStackGuardState() {
__ lea(rdi, Operand(rsp, -kPointerSize));
#endif
ExternalReference stack_check =
- ExternalReference::re_check_stack_guard_state();
+ ExternalReference::re_check_stack_guard_state(masm_.isolate());
__ CallCFunction(stack_check, num_arguments);
}
@@ -1141,8 +1148,10 @@ static T& frame_entry(Address re_frame, int frame_offset) {
int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame) {
- if (StackGuard::IsStackOverflow()) {
- Top::StackOverflow();
+ Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
+ ASSERT(isolate == Isolate::Current());
+ if (isolate->stack_guard()->IsStackOverflow()) {
+ isolate->StackOverflow();
return EXCEPTION;
}
@@ -1289,8 +1298,8 @@ void RegExpMacroAssemblerX64::FixupCodeRelativePositions() {
// Patch the relative offset to be relative to the Code object pointer
// instead.
int patch_position = position - kIntSize;
- int offset = masm_->long_at(patch_position);
- masm_->long_at_put(patch_position,
+ int offset = masm_.long_at(patch_position);
+ masm_.long_at_put(patch_position,
offset
+ position
+ Code::kHeaderSize
@@ -1324,7 +1333,7 @@ void RegExpMacroAssemblerX64::CheckPreemption() {
// Check for preemption.
Label no_preempt;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(masm_.isolate());
__ load_rax(stack_limit);
__ cmpq(rsp, rax);
__ j(above, &no_preempt);
@@ -1338,7 +1347,7 @@ void RegExpMacroAssemblerX64::CheckPreemption() {
void RegExpMacroAssemblerX64::CheckStackLimit() {
Label no_stack_overflow;
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit();
+ ExternalReference::address_of_regexp_stack_limit(masm_.isolate());
__ load_rax(stack_limit);
__ cmpq(backtrack_stackpointer(), rax);
__ j(above, &no_stack_overflow);
diff --git a/src/x64/regexp-macro-assembler-x64.h b/src/x64/regexp-macro-assembler-x64.h
index 421a2294..a83f8cbc 100644
--- a/src/x64/regexp-macro-assembler-x64.h
+++ b/src/x64/regexp-macro-assembler-x64.h
@@ -104,7 +104,8 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
Handle<String> subject,
int* offsets_vector,
int offsets_vector_length,
- int previous_index);
+ int previous_index,
+ Isolate* isolate);
static Result Execute(Code* code,
String* input,
@@ -142,6 +143,7 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
static const int kStackHighEnd = kRegisterOutput + kPointerSize;
// DirectCall is passed as 32 bit int (values 0 or 1).
static const int kDirectCall = kStackHighEnd + kPointerSize;
+ static const int kIsolate = kDirectCall + kPointerSize;
#else
// In AMD64 ABI Calling Convention, the first six integer parameters
// are passed as registers, and caller must allocate space on the stack
@@ -153,6 +155,7 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
static const int kRegisterOutput = kInputEnd - kPointerSize;
static const int kStackHighEnd = kRegisterOutput - kPointerSize;
static const int kDirectCall = kFrameAlign;
+ static const int kIsolate = kDirectCall + kPointerSize;
#endif
#ifdef _WIN64
@@ -215,7 +218,7 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
void BranchOrBacktrack(Condition condition, Label* to);
void MarkPositionForCodeRelativeFixup() {
- code_relative_fixup_positions_.Add(masm_->pc_offset());
+ code_relative_fixup_positions_.Add(masm_.pc_offset());
}
void FixupCodeRelativePositions();
@@ -247,7 +250,8 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
// Increments the stack pointer (rcx) by a word size.
inline void Drop();
- MacroAssembler* masm_;
+ MacroAssembler masm_;
+ MacroAssembler::NoRootArrayScope no_root_array_scope_;
ZoneList<int> code_relative_fixup_positions_;
diff --git a/src/x64/register-allocator-x64-inl.h b/src/x64/register-allocator-x64-inl.h
index c6bea3ab..5df3d54e 100644
--- a/src/x64/register-allocator-x64-inl.h
+++ b/src/x64/register-allocator-x64-inl.h
@@ -60,10 +60,10 @@ int RegisterAllocator::ToNumber(Register reg) {
6, // r9
-1, // r10 Scratch register.
8, // r11
- 9, // r12
+ -1, // r12 Smi constant.
-1, // r13 Roots array. This is callee saved.
7, // r14
- -1 // r15 Smi constant register.
+ 9 // r15
};
return kNumbers[reg.code()];
}
@@ -72,7 +72,7 @@ int RegisterAllocator::ToNumber(Register reg) {
Register RegisterAllocator::ToRegister(int num) {
ASSERT(num >= 0 && num < kNumRegisters);
const Register kRegisters[] =
- { rax, rbx, rcx, rdx, rdi, r8, r9, r14, r11, r12 };
+ { rax, rbx, rcx, rdx, rdi, r8, r9, r14, r11, r15 };
return kRegisters[num];
}
diff --git a/src/x64/register-allocator-x64.cc b/src/x64/register-allocator-x64.cc
index 1f5467e1..65189f57 100644
--- a/src/x64/register-allocator-x64.cc
+++ b/src/x64/register-allocator-x64.cc
@@ -42,9 +42,11 @@ namespace internal {
void Result::ToRegister() {
ASSERT(is_valid());
if (is_constant()) {
- Result fresh = CodeGeneratorScope::Current()->allocator()->Allocate();
+ CodeGenerator* code_generator =
+ CodeGeneratorScope::Current(Isolate::Current());
+ Result fresh = code_generator->allocator()->Allocate();
ASSERT(fresh.is_valid());
- CodeGeneratorScope::Current()->masm()->Move(fresh.reg(), handle());
+ code_generator->masm()->Move(fresh.reg(), handle());
// This result becomes a copy of the fresh one.
fresh.set_type_info(type_info());
*this = fresh;
@@ -55,21 +57,23 @@ void Result::ToRegister() {
void Result::ToRegister(Register target) {
ASSERT(is_valid());
+ CodeGenerator* code_generator =
+ CodeGeneratorScope::Current(Isolate::Current());
if (!is_register() || !reg().is(target)) {
- Result fresh = CodeGeneratorScope::Current()->allocator()->Allocate(target);
+ Result fresh = code_generator->allocator()->Allocate(target);
ASSERT(fresh.is_valid());
if (is_register()) {
- CodeGeneratorScope::Current()->masm()->movq(fresh.reg(), reg());
+ code_generator->masm()->movq(fresh.reg(), reg());
} else {
ASSERT(is_constant());
- CodeGeneratorScope::Current()->masm()->Move(fresh.reg(), handle());
+ code_generator->masm()->Move(fresh.reg(), handle());
}
fresh.set_type_info(type_info());
*this = fresh;
} else if (is_register() && reg().is(target)) {
- ASSERT(CodeGeneratorScope::Current()->has_valid_frame());
- CodeGeneratorScope::Current()->frame()->Spill(target);
- ASSERT(CodeGeneratorScope::Current()->allocator()->count(target) == 1);
+ ASSERT(code_generator->has_valid_frame());
+ code_generator->frame()->Spill(target);
+ ASSERT(code_generator->allocator()->count(target) == 1);
}
ASSERT(is_register());
ASSERT(reg().is(target));
diff --git a/src/x64/simulator-x64.h b/src/x64/simulator-x64.h
index aa2994f2..cfaa5b8c 100644
--- a/src/x64/simulator-x64.h
+++ b/src/x64/simulator-x64.h
@@ -40,12 +40,12 @@ namespace internal {
(entry(p0, p1, p2, p3, p4))
typedef int (*regexp_matcher)(String*, int, const byte*,
- const byte*, int*, Address, int);
+ const byte*, int*, Address, int, Isolate*);
// Call the generated regexp code directly. The code at the entry address should
-// expect seven int/pointer sized arguments and return an int.
-#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
- (FUNCTION_CAST<regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6))
+// expect eight int/pointer sized arguments and return an int.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
+ (FUNCTION_CAST<regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7))
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
(reinterpret_cast<TryCatch*>(try_catch_address))
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 109985c7..7494fe0d 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -39,7 +39,8 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-static void ProbeTable(MacroAssembler* masm,
+static void ProbeTable(Isolate* isolate,
+ MacroAssembler* masm,
Code::Flags flags,
StubCache::Table table,
Register name,
@@ -48,10 +49,10 @@ static void ProbeTable(MacroAssembler* masm,
ASSERT_EQ(16, sizeof(StubCache::Entry));
// The offset register holds the entry offset times four (due to masking
// and shifting optimizations).
- ExternalReference key_offset(SCTableReference::keyReference(table));
+ ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
Label miss;
- __ movq(kScratchRegister, key_offset);
+ __ LoadAddress(kScratchRegister, key_offset);
// Check that the key in the entry matches the name.
// Multiply entry offset by 16 to get the entry address. Since the
// offset register already holds the entry offset times four, multiply
@@ -88,8 +89,9 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Register r0,
Register r1) {
ASSERT(name->IsSymbol());
- __ IncrementCounter(&Counters::negative_lookups, 1);
- __ IncrementCounter(&Counters::negative_lookups_miss, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->negative_lookups(), 1);
+ __ IncrementCounter(counters->negative_lookups_miss(), 1);
Label done;
__ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset));
@@ -151,7 +153,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
ASSERT_EQ(kSmiTagSize, 1);
__ movq(entity_name, Operand(properties, index, times_pointer_size,
kElementsStartOffset - kHeapObjectTag));
- __ Cmp(entity_name, Factory::undefined_value());
+ __ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
// __ jmp(miss_label);
if (i != kProbes - 1) {
__ j(equal, &done);
@@ -172,7 +174,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
}
__ bind(&done);
- __ DecrementCounter(&Counters::negative_lookups_miss, 1);
+ __ DecrementCounter(counters->negative_lookups_miss(), 1);
}
@@ -183,6 +185,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
Register scratch,
Register extra,
Register extra2) {
+ Isolate* isolate = masm->isolate();
Label miss;
USE(extra); // The register extra is not used on the X64 platform.
USE(extra2); // The register extra2 is not used on the X64 platform.
@@ -212,7 +215,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
// Probe the primary table.
- ProbeTable(masm, flags, kPrimary, name, scratch);
+ ProbeTable(isolate, masm, flags, kPrimary, name, scratch);
// Primary miss: Compute hash for secondary probe.
__ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
@@ -224,7 +227,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
__ and_(scratch, Immediate((kSecondaryTableSize - 1) << kHeapObjectTagSize));
// Probe the secondary table.
- ProbeTable(masm, flags, kSecondary, name, scratch);
+ ProbeTable(isolate, masm, flags, kSecondary, name, scratch);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
@@ -253,13 +256,15 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
MacroAssembler* masm, int index, Register prototype, Label* miss) {
+ Isolate* isolate = masm->isolate();
// Check we're still in the same context.
- __ Move(prototype, Top::global());
+ __ Move(prototype, isolate->global());
__ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)),
prototype);
__ j(not_equal, miss);
// Get the global function with the given index.
- JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
+ JSFunction* function =
+ JSFunction::cast(isolate->global_context()->get(index));
// Load its initial map. The global functions all have initial maps.
__ Move(prototype, Handle<Map>(function->initial_map()));
// Load the prototype from the initial map.
@@ -375,7 +380,7 @@ static void PushInterceptorArguments(MacroAssembler* masm,
JSObject* holder_obj) {
__ push(name);
InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
- ASSERT(!Heap::InNewSpace(interceptor));
+ ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
__ Move(kScratchRegister, Handle<Object>(interceptor));
__ push(kScratchRegister);
__ push(receiver);
@@ -392,9 +397,10 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
ExternalReference ref =
- ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
+ masm->isolate());
__ movq(rax, Immediate(5));
- __ movq(rbx, ref);
+ __ LoadAddress(rbx, ref);
CEntryStub stub(1);
__ CallStub(&stub);
@@ -466,7 +472,7 @@ static MaybeObject* GenerateFastApiCall(MacroAssembler* masm,
__ movq(Operand(rsp, 2 * kPointerSize), rdi);
Object* call_data = optimization.api_call_info()->data();
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
- if (Heap::InNewSpace(call_data)) {
+ if (masm->isolate()->heap()->InNewSpace(call_data)) {
__ Move(rcx, api_call_info_handle);
__ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
__ movq(Operand(rsp, 3 * kPointerSize), rbx);
@@ -561,7 +567,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
name,
holder,
miss);
- return Heap::undefined_value(); // Success.
+ return masm->isolate()->heap()->undefined_value(); // Success.
}
}
@@ -597,10 +603,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
(depth2 != kInvalidProtoDepth);
}
- __ IncrementCounter(&Counters::call_const_interceptor, 1);
+ Counters* counters = masm->isolate()->counters();
+ __ IncrementCounter(counters->call_const_interceptor(), 1);
if (can_do_fast_api_call) {
- __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1);
+ __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ReserveSpaceForFastApiCall(masm, scratch1);
}
@@ -660,7 +667,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
FreeSpaceForFastApiCall(masm, scratch1);
}
- return Heap::undefined_value(); // Success.
+ return masm->isolate()->heap()->undefined_value(); // Success.
}
void CompileRegular(MacroAssembler* masm,
@@ -688,7 +695,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
interceptor_holder);
__ CallExternalReference(
- ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
+ masm->isolate()),
5);
// Restore the name_ register.
@@ -729,9 +737,9 @@ void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
Code* code = NULL;
if (kind == Code::LOAD_IC) {
- code = Builtins::builtin(Builtins::LoadIC_Miss);
+ code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss);
} else {
- code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
+ code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss);
}
Handle<Code> ic(code);
@@ -776,7 +784,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
__ push(rax);
__ push(scratch);
__ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
+ ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
+ masm->isolate()),
+ 3,
+ 1);
return;
}
@@ -836,7 +847,7 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
ASSERT(cell->value()->IsTheHole());
__ Move(scratch, Handle<Object>(cell));
__ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
- Factory::the_hole_value());
+ masm->isolate()->factory()->the_hole_value());
__ j(not_equal, miss);
return cell;
}
@@ -885,7 +896,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
!current->IsJSGlobalObject() &&
!current->IsJSGlobalProxy()) {
if (!name->IsSymbol()) {
- MaybeObject* lookup_result = Heap::LookupSymbol(name);
+ MaybeObject* lookup_result = heap()->LookupSymbol(name);
if (lookup_result->IsFailure()) {
set_failure(Failure::cast(lookup_result));
return reg;
@@ -905,7 +916,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
__ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
reg = holder_reg; // from now the object is in holder_reg
__ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
- } else if (Heap::InNewSpace(prototype)) {
+ } else if (heap()->InNewSpace(prototype)) {
// Get the map of the current object.
__ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
__ Cmp(scratch1, Handle<Map>(current->map()));
@@ -956,7 +967,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
__ j(not_equal, miss);
// Log the check depth.
- LOG(IntEvent("check-maps-depth", depth + 1));
+ LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
// Perform security check for access to the global object and return
// the holder register.
@@ -1039,7 +1050,7 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
__ push(receiver); // receiver
__ push(reg); // holder
- if (Heap::InNewSpace(callback_handle->data())) {
+ if (heap()->InNewSpace(callback_handle->data())) {
__ Move(scratch1, callback_handle);
__ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data
} else {
@@ -1230,7 +1241,8 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
__ push(scratch2); // restore return address
ExternalReference ref =
- ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
+ isolate());
__ TailCallExternalReference(ref, 5, 1);
}
} else { // !compile_followup_inline
@@ -1245,7 +1257,7 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
__ push(scratch2); // restore old return address
ExternalReference ref = ExternalReference(
- IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
+ IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
__ TailCallExternalReference(ref, 5, 1);
}
}
@@ -1291,7 +1303,7 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
__ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function.
- if (Heap::InNewSpace(function)) {
+ if (heap()->InNewSpace(function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
@@ -1313,8 +1325,8 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
MaybeObject* CallStubCompiler::GenerateMissBranch() {
- MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(),
- kind_);
+ MaybeObject* maybe_obj = isolate()->stub_cache()->ComputeCallMiss(
+ arguments().immediate(), kind_);
Object* obj;
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
__ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
@@ -1369,10 +1381,8 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
// Handle call cache miss.
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(FIELD, name);
@@ -1393,7 +1403,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// -----------------------------------
// If object is not an array, bail out to regular call.
- if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
Label miss;
@@ -1427,7 +1437,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// Check that the elements are in fast mode and writable.
__ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
- Factory::fixed_array_map());
+ factory()->fixed_array_map());
__ j(not_equal, &call_builtin);
if (argc == 1) { // Otherwise fall through to call builtin.
@@ -1477,14 +1487,13 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
}
ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address();
+ ExternalReference::new_space_allocation_top_address(isolate());
ExternalReference new_space_allocation_limit =
- ExternalReference::new_space_allocation_limit_address();
+ ExternalReference::new_space_allocation_limit_address(isolate());
const int kAllocationDelta = 4;
// Load top.
- __ movq(rcx, new_space_allocation_top);
- __ movq(rcx, Operand(rcx, 0));
+ __ Load(rcx, new_space_allocation_top);
// Check if it's the end of elements.
__ lea(rdx, FieldOperand(rbx,
@@ -1493,13 +1502,13 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
__ cmpq(rdx, rcx);
__ j(not_equal, &call_builtin);
__ addq(rcx, Immediate(kAllocationDelta * kPointerSize));
- __ movq(kScratchRegister, new_space_allocation_limit);
- __ cmpq(rcx, Operand(kScratchRegister, 0));
+ Operand limit_operand =
+ masm()->ExternalOperand(new_space_allocation_limit);
+ __ cmpq(rcx, limit_operand);
__ j(above, &call_builtin);
// We fit and could grow elements.
- __ movq(kScratchRegister, new_space_allocation_top);
- __ movq(Operand(kScratchRegister, 0), rcx);
+ __ Store(new_space_allocation_top, rcx);
__ movq(rcx, Operand(rsp, argc * kPointerSize));
// Push the argument...
@@ -1526,16 +1535,15 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
}
__ bind(&call_builtin);
- __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush),
+ __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
+ isolate()),
argc + 1,
1);
}
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1556,7 +1564,7 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
// -----------------------------------
// If object is not an array, bail out to regular call.
- if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
Label miss, return_undefined, call_builtin;
@@ -1611,15 +1619,14 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
__ ret((argc + 1) * kPointerSize);
__ bind(&call_builtin);
- __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop),
- argc + 1,
- 1);
+ __ TailCallExternalReference(
+ ExternalReference(Builtins::c_ArrayPop, isolate()),
+ argc + 1,
+ 1);
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1641,7 +1648,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// -----------------------------------
// If object is not a string, bail out to regular call.
- if (!object->IsString() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsString() || cell != NULL) return heap()->undefined_value();
const int argc = arguments().immediate();
@@ -1700,10 +1707,8 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// Restore function name in rcx.
__ Move(rcx, Handle<String>(name));
__ bind(&name_miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1725,7 +1730,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// -----------------------------------
// If object is not a string, bail out to regular call.
- if (!object->IsString() || cell != NULL) return Heap::undefined_value();
+ if (!object->IsString() || cell != NULL) return heap()->undefined_value();
const int argc = arguments().immediate();
@@ -1786,10 +1791,8 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// Restore function name in rcx.
__ Move(rcx, Handle<String>(name));
__ bind(&name_miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -1814,7 +1817,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
- if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
+ if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss;
GenerateNameCheck(name, &miss);
@@ -1857,10 +1860,8 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
__ bind(&miss);
// rcx: function name.
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
@@ -1873,7 +1874,7 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
JSFunction* function,
String* name) {
// TODO(872): implement this.
- return Heap::undefined_value();
+ return heap()->undefined_value();
}
@@ -1894,7 +1895,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
- if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
+ if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
Label miss;
GenerateNameCheck(name, &miss);
@@ -1943,7 +1944,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
// Check if the argument is a heap number and load its value.
__ bind(&not_smi);
- __ CheckMap(rax, Factory::heap_number_map(), &slow, true);
+ __ CheckMap(rax, factory()->heap_number_map(), &slow, true);
__ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
// Check the sign of the argument. If the argument is positive,
@@ -1972,16 +1973,72 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
__ bind(&miss);
// rcx: function name.
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
}
+MaybeObject* CallStubCompiler::CompileFastApiCall(
+ const CallOptimization& optimization,
+ Object* object,
+ JSObject* holder,
+ JSGlobalPropertyCell* cell,
+ JSFunction* function,
+ String* name) {
+ ASSERT(optimization.is_simple_api_call());
+ // Bail out if object is a global object as we don't want to
+ // repatch it to global receiver.
+ if (object->IsGlobalObject()) return heap()->undefined_value();
+ if (cell != NULL) return heap()->undefined_value();
+ int depth = optimization.GetPrototypeDepthOfExpectedType(
+ JSObject::cast(object), holder);
+ if (depth == kInvalidProtoDepth) return heap()->undefined_value();
+
+ Label miss, miss_before_stack_reserved;
+
+ GenerateNameCheck(name, &miss_before_stack_reserved);
+
+ // Get the receiver from the stack.
+ const int argc = arguments().immediate();
+ __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+ // Check that the receiver isn't a smi.
+ __ JumpIfSmi(rdx, &miss_before_stack_reserved);
+
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->call_const(), 1);
+ __ IncrementCounter(counters->call_const_fast_api(), 1);
+
+ // Allocate space for v8::Arguments implicit values. Must be initialized
+ // before calling any runtime function.
+ __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
+
+ // Check that the maps haven't changed and find a Holder as a side effect.
+ CheckPrototypes(JSObject::cast(object), rdx, holder,
+ rbx, rax, rdi, name, depth, &miss);
+
+ // Move the return address on top of the stack.
+ __ movq(rax, Operand(rsp, 3 * kPointerSize));
+ __ movq(Operand(rsp, 0 * kPointerSize), rax);
+
+ MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
+ if (result->IsFailure()) return result;
+
+ __ bind(&miss);
+ __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
+
+ __ bind(&miss_before_stack_reserved);
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
+
+ // Return the generated code.
+ return GetCode(function);
+}
+
+
MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
@@ -1997,20 +2054,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
- SharedFunctionInfo* function_info = function->shared();
- if (function_info->HasBuiltinFunctionId()) {
- BuiltinFunctionId id = function_info->builtin_function_id();
+ if (HasCustomCallGenerator(function)) {
MaybeObject* maybe_result = CompileCustomCall(
- id, object, holder, NULL, function, name);
+ object, holder, NULL, function, name);
Object* result;
if (!maybe_result->ToObject(&result)) return maybe_result;
// undefined means bail out to regular compiler.
if (!result->IsUndefined()) return result;
}
- Label miss_in_smi_check;
+ Label miss;
- GenerateNameCheck(name, &miss_in_smi_check);
+ GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
@@ -2018,42 +2073,26 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// Check that the receiver isn't a smi.
if (check != NUMBER_CHECK) {
- __ JumpIfSmi(rdx, &miss_in_smi_check);
+ __ JumpIfSmi(rdx, &miss);
}
// Make sure that it's okay not to patch the on stack receiver
// unless we're doing a receiver map check.
ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
- CallOptimization optimization(function);
- int depth = kInvalidProtoDepth;
- Label miss;
-
+ Counters* counters = isolate()->counters();
+ SharedFunctionInfo* function_info = function->shared();
switch (check) {
case RECEIVER_MAP_CHECK:
- __ IncrementCounter(&Counters::call_const, 1);
-
- if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
- depth = optimization.GetPrototypeDepthOfExpectedType(
- JSObject::cast(object), holder);
- }
-
- if (depth != kInvalidProtoDepth) {
- __ IncrementCounter(&Counters::call_const_fast_api, 1);
-
- // Allocate space for v8::Arguments implicit values. Must be initialized
- // before to call any runtime function.
- __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
- }
+ __ IncrementCounter(counters->call_const(), 1);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), rdx, holder,
- rbx, rax, rdi, name, depth, &miss);
+ rbx, rax, rdi, name, &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
if (object->IsGlobalObject()) {
- ASSERT(depth == kInvalidProtoDepth);
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
__ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
}
@@ -2123,31 +2162,12 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
UNREACHABLE();
}
- if (depth != kInvalidProtoDepth) {
- // Move the return address on top of the stack.
- __ movq(rax, Operand(rsp, 3 * kPointerSize));
- __ movq(Operand(rsp, 0 * kPointerSize), rax);
-
- // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
- // duplicate of return address and will be overwritten.
- MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
- if (result->IsFailure()) return result;
- } else {
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
- }
+ __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
// Handle call cache miss.
__ bind(&miss);
- if (depth != kInvalidProtoDepth) {
- __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
- }
-
- // Handle call cache miss.
- __ bind(&miss_in_smi_check);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(function);
@@ -2213,10 +2233,8 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
// Handle load cache miss.
__ bind(&miss);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(INTERCEPTOR, name);
@@ -2238,11 +2256,9 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
- SharedFunctionInfo* function_info = function->shared();
- if (function_info->HasBuiltinFunctionId()) {
- BuiltinFunctionId id = function_info->builtin_function_id();
+ if (HasCustomCallGenerator(function)) {
MaybeObject* maybe_result = CompileCustomCall(
- id, object, holder, cell, function, name);
+ object, holder, cell, function, name);
Object* result;
if (!maybe_result->ToObject(&result)) return maybe_result;
// undefined means bail out to regular compiler.
@@ -2270,7 +2286,8 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
__ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
// Jump to the cached code (tail call).
- __ IncrementCounter(&Counters::call_global_inline, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->call_global_inline(), 1);
ASSERT(function->is_compiled());
ParameterCount expected(function->shared()->formal_parameter_count());
if (V8::UseCrankshaft()) {
@@ -2286,11 +2303,9 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
}
// Handle call cache miss.
__ bind(&miss);
- __ IncrementCounter(&Counters::call_global_inline_miss, 1);
- Object* obj;
- { MaybeObject* maybe_obj = GenerateMissBranch();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
+ __ IncrementCounter(counters->call_global_inline_miss(), 1);
+ MaybeObject* maybe_result = GenerateMissBranch();
+ if (maybe_result->IsFailure()) return maybe_result;
// Return the generated code.
return GetCode(NORMAL, name);
@@ -2319,7 +2334,7 @@ MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
// Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2364,12 +2379,12 @@ MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
// Do tail-call to the runtime system.
ExternalReference store_callback_property =
- ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
+ ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
__ TailCallExternalReference(store_callback_property, 4, 1);
// Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2413,12 +2428,12 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
// Do tail-call to the runtime system.
ExternalReference store_ic_property =
- ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
+ ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
__ TailCallExternalReference(store_ic_property, 4, 1);
// Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2455,13 +2470,14 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
__ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rax);
// Return the value (register rax).
- __ IncrementCounter(&Counters::named_store_global_inline, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->named_store_global_inline(), 1);
__ ret(0);
// Handle store cache miss.
__ bind(&miss);
- __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
+ Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2481,7 +2497,8 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_store_field, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_store_field(), 1);
// Check that the name has not changed.
__ Cmp(rcx, Handle<String>(name));
@@ -2497,8 +2514,8 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
// Handle store cache miss.
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_store_field, 1);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
+ __ DecrementCounter(counters->keyed_store_field(), 1);
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2530,7 +2547,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
// Get the elements array and make sure it is a fast element array, not 'cow'.
__ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
__ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
- Factory::fixed_array_map());
+ factory()->fixed_array_map());
__ j(not_equal, &miss);
// Check that the key is within bounds.
@@ -2555,44 +2572,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
// Handle store cache miss.
__ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
- __ jmp(ic, RelocInfo::CODE_TARGET);
-
- // Return the generated code.
- return GetCode(NORMAL, NULL);
-}
-
-
-MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray(
- JSObject* receiver) {
- // ----------- S t a t e -------------
- // -- rax : value
- // -- rcx : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- // Check that the map matches.
- __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false);
-
- // Do the load.
- GenerateFastPixelArrayStore(masm(),
- rdx,
- rcx,
- rax,
- rdi,
- rbx,
- true,
- false,
- &miss,
- &miss,
- NULL,
- &miss);
-
- // Handle store cache miss.
- __ bind(&miss);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
+ Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
@@ -2641,7 +2621,7 @@ MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
- return GetCode(NONEXISTENT, Heap::empty_string());
+ return GetCode(NONEXISTENT, heap()->empty_string());
}
@@ -2780,12 +2760,13 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
__ Check(not_equal, "DontDelete cells can't contain the hole");
}
- __ IncrementCounter(&Counters::named_load_global_stub, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->named_load_global_stub(), 1);
__ movq(rax, rbx);
__ ret(0);
__ bind(&miss);
- __ IncrementCounter(&Counters::named_load_global_stub_miss, 1);
+ __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
@@ -2804,7 +2785,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_field, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_field(), 1);
// Check that the name has not changed.
__ Cmp(rax, Handle<String>(name));
@@ -2813,7 +2795,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_field, 1);
+ __ DecrementCounter(counters->keyed_load_field(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -2833,7 +2815,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_callback, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_callback(), 1);
// Check that the name has not changed.
__ Cmp(rax, Handle<String>(name));
@@ -2848,7 +2831,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_callback, 1);
+ __ DecrementCounter(counters->keyed_load_callback(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -2867,7 +2850,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_constant_function(), 1);
// Check that the name has not changed.
__ Cmp(rax, Handle<String>(name));
@@ -2876,7 +2860,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
GenerateLoadConstant(receiver, holder, rdx, rbx, rcx, rdi,
value, name, &miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
+ __ DecrementCounter(counters->keyed_load_constant_function(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -2894,7 +2878,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_interceptor(), 1);
// Check that the name has not changed.
__ Cmp(rax, Handle<String>(name));
@@ -2913,7 +2898,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
name,
&miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
+ __ DecrementCounter(counters->keyed_load_interceptor(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -2929,7 +2914,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_array_length, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_array_length(), 1);
// Check that the name has not changed.
__ Cmp(rax, Handle<String>(name));
@@ -2937,7 +2923,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_array_length, 1);
+ __ DecrementCounter(counters->keyed_load_array_length(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -2953,7 +2939,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_string_length, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_string_length(), 1);
// Check that the name has not changed.
__ Cmp(rax, Handle<String>(name));
@@ -2961,7 +2948,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_string_length, 1);
+ __ DecrementCounter(counters->keyed_load_string_length(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -2977,7 +2964,8 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
// -----------------------------------
Label miss;
- __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_function_prototype(), 1);
// Check that the name has not changed.
__ Cmp(rax, Handle<String>(name));
@@ -2985,7 +2973,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
__ bind(&miss);
- __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
+ __ DecrementCounter(counters->keyed_load_function_prototype(), 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
@@ -2997,7 +2985,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
- // -- esp[0] : return address
+ // -- rsp[0] : return address
// -----------------------------------
Label miss;
@@ -3039,35 +3027,6 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
}
-MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- Label miss;
-
- // Check that the map matches.
- __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false);
-
- GenerateFastPixelArrayLoad(masm(),
- rdx,
- rax,
- rbx,
- rcx,
- rax,
- &miss,
- &miss,
- &miss);
-
- __ bind(&miss);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(NORMAL, NULL);
-}
-
-
// Specialized stub for constructing objects from functions which only have only
// simple assignments of the form this.x = ...; in their body.
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
@@ -3080,7 +3039,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
Label generic_stub_call;
// Use r8 for holding undefined which is used in several places below.
- __ Move(r8, Factory::undefined_value());
+ __ Move(r8, factory()->undefined_value());
#ifdef ENABLE_DEBUGGER_SUPPORT
// Check to see whether there are any break points in the function code. If
@@ -3124,7 +3083,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// rbx: initial map
// rdx: JSObject (untagged)
__ movq(Operand(rdx, JSObject::kMapOffset), rbx);
- __ Move(rbx, Factory::empty_fixed_array());
+ __ Move(rbx, factory()->empty_fixed_array());
__ movq(Operand(rdx, JSObject::kPropertiesOffset), rbx);
__ movq(Operand(rdx, JSObject::kElementsOffset), rbx);
@@ -3183,14 +3142,16 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
__ pop(rcx);
__ lea(rsp, Operand(rsp, rbx, times_pointer_size, 1 * kPointerSize));
__ push(rcx);
- __ IncrementCounter(&Counters::constructed_objects, 1);
- __ IncrementCounter(&Counters::constructed_objects_stub, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->constructed_objects(), 1);
+ __ IncrementCounter(counters->constructed_objects_stub(), 1);
__ ret(0);
// Jump to the generic stub in case the specialized code cannot handle the
// construction.
__ bind(&generic_stub_call);
- Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
+ Code* code =
+ isolate()->builtins()->builtin(Builtins::kJSConstructStubGeneric);
Handle<Code> generic_construct_stub(code);
__ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
@@ -3200,7 +3161,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
- ExternalArrayType array_type, Code::Flags flags) {
+ JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -3214,24 +3175,9 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// Check that the key is a smi.
__ JumpIfNotSmi(rax, &slow);
- // Check that the object is a JS object.
- __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
- __ j(not_equal, &slow);
- // Check that the receiver does not require access checks. We need
- // to check this explicitly since this generic stub does not perform
- // map checks. The map is already in rdx.
- __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsAccessCheckNeeded));
- __ j(not_zero, &slow);
-
- // Check that the elements array is the appropriate type of
- // ExternalArray.
- // rax: index (as a smi)
- // rdx: JSObject
+ // Check that the map matches.
+ __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false);
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
- __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
- Heap::RootIndexForExternalArrayType(array_type));
- __ j(not_equal, &slow);
// Check that the index is in range.
__ SmiToInteger32(rcx, rax);
@@ -3249,6 +3195,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
case kExternalByteArray:
__ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
break;
+ case kExternalPixelArray:
case kExternalUnsignedByteArray:
__ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
break;
@@ -3319,7 +3266,8 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
// Slow case: Jump to runtime.
__ bind(&slow);
- __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
+ Counters* counters = isolate()->counters();
+ __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
// ----------- S t a t e -------------
// -- rax : key
@@ -3341,7 +3289,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
- ExternalArrayType array_type, Code::Flags flags) {
+ JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@@ -3352,29 +3300,13 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
// Check that the object isn't a smi.
__ JumpIfSmi(rdx, &slow);
- // Get the map from the receiver.
- __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks. We need
- // to do this because this generic stub does not perform map checks.
- __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsAccessCheckNeeded));
- __ j(not_zero, &slow);
- // Check that the key is a smi.
- __ JumpIfNotSmi(rcx, &slow);
- // Check that the object is a JS object.
- __ CmpInstanceType(rbx, JS_OBJECT_TYPE);
- __ j(not_equal, &slow);
-
- // Check that the elements array is the appropriate type of
- // ExternalArray.
- // rax: value
- // rcx: key (a smi)
- // rdx: receiver (a JSObject)
+ // Check that the map matches.
+ __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false);
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
- __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
- Heap::RootIndexForExternalArrayType(array_type));
- __ j(not_equal, &slow);
+
+ // Check that the key is a smi.
+ __ JumpIfNotSmi(rcx, &slow);
// Check that the index is in range.
__ SmiToInteger32(rdi, rcx); // Untag the index.
@@ -3390,12 +3322,28 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
// rbx: elements array
// rdi: untagged key
NearLabel check_heap_number;
- __ JumpIfNotSmi(rax, &check_heap_number);
+ if (array_type == kExternalPixelArray) {
+ // Float to pixel conversion is only implemented in the runtime for now.
+ __ JumpIfNotSmi(rax, &slow);
+ } else {
+ __ JumpIfNotSmi(rax, &check_heap_number);
+ }
// No more branches to slow case on this path. Key and receiver not needed.
__ SmiToInteger32(rdx, rax);
__ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
// rbx: base pointer of external storage
switch (array_type) {
+ case kExternalPixelArray:
+ { // Clamp the value to [0..255].
+ NearLabel done;
+ __ testl(rdx, Immediate(0xFFFFFF00));
+ __ j(zero, &done);
+ __ setcc(negative, rdx); // 1 if negative, 0 if positive.
+ __ decb(rdx); // 0 if negative, 255 if positive.
+ __ bind(&done);
+ }
+ __ movb(Operand(rbx, rdi, times_1, 0), rdx);
+ break;
case kExternalByteArray:
case kExternalUnsignedByteArray:
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
@@ -3419,62 +3367,65 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
}
__ ret(0);
- __ bind(&check_heap_number);
- // rax: value
- // rcx: key (a smi)
- // rdx: receiver (a JSObject)
- // rbx: elements array
- // rdi: untagged key
- __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
- __ j(not_equal, &slow);
- // No more branches to slow case on this path.
-
- // The WebGL specification leaves the behavior of storing NaN and
- // +/-Infinity into integer arrays basically undefined. For more
- // reproducible behavior, convert these to zero.
- __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
- __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
- // rdi: untagged index
- // rbx: base pointer of external storage
- // top of FPU stack: value
- if (array_type == kExternalFloatArray) {
- __ cvtsd2ss(xmm0, xmm0);
- __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
- __ ret(0);
- } else {
- // Perform float-to-int conversion with truncation (round-to-zero)
- // behavior.
-
- // Convert to int32 and store the low byte/word.
- // If the value is NaN or +/-infinity, the result is 0x80000000,
- // which is automatically zero when taken mod 2^n, n < 32.
- // rdx: value (converted to an untagged integer)
+ // TODO(danno): handle heap number -> pixel array conversion
+ if (array_type != kExternalPixelArray) {
+ __ bind(&check_heap_number);
+ // rax: value
+ // rcx: key (a smi)
+ // rdx: receiver (a JSObject)
+ // rbx: elements array
+ // rdi: untagged key
+ __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
+ __ j(not_equal, &slow);
+ // No more branches to slow case on this path.
+
+ // The WebGL specification leaves the behavior of storing NaN and
+ // +/-Infinity into integer arrays basically undefined. For more
+ // reproducible behavior, convert these to zero.
+ __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
+ __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
// rdi: untagged index
// rbx: base pointer of external storage
- switch (array_type) {
- case kExternalByteArray:
- case kExternalUnsignedByteArray:
- __ cvttsd2si(rdx, xmm0);
- __ movb(Operand(rbx, rdi, times_1, 0), rdx);
- break;
- case kExternalShortArray:
- case kExternalUnsignedShortArray:
- __ cvttsd2si(rdx, xmm0);
- __ movw(Operand(rbx, rdi, times_2, 0), rdx);
- break;
- case kExternalIntArray:
- case kExternalUnsignedIntArray: {
- // Convert to int64, so that NaN and infinities become
- // 0x8000000000000000, which is zero mod 2^32.
- __ cvttsd2siq(rdx, xmm0);
- __ movl(Operand(rbx, rdi, times_4, 0), rdx);
- break;
+ // top of FPU stack: value
+ if (array_type == kExternalFloatArray) {
+ __ cvtsd2ss(xmm0, xmm0);
+ __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
+ __ ret(0);
+ } else {
+ // Perform float-to-int conversion with truncation (round-to-zero)
+ // behavior.
+
+ // Convert to int32 and store the low byte/word.
+ // If the value is NaN or +/-infinity, the result is 0x80000000,
+ // which is automatically zero when taken mod 2^n, n < 32.
+ // rdx: value (converted to an untagged integer)
+ // rdi: untagged index
+ // rbx: base pointer of external storage
+ switch (array_type) {
+ case kExternalByteArray:
+ case kExternalUnsignedByteArray:
+ __ cvttsd2si(rdx, xmm0);
+ __ movb(Operand(rbx, rdi, times_1, 0), rdx);
+ break;
+ case kExternalShortArray:
+ case kExternalUnsignedShortArray:
+ __ cvttsd2si(rdx, xmm0);
+ __ movw(Operand(rbx, rdi, times_2, 0), rdx);
+ break;
+ case kExternalIntArray:
+ case kExternalUnsignedIntArray: {
+ // Convert to int64, so that NaN and infinities become
+ // 0x8000000000000000, which is zero mod 2^32.
+ __ cvttsd2siq(rdx, xmm0);
+ __ movl(Operand(rbx, rdi, times_4, 0), rdx);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
}
- default:
- UNREACHABLE();
- break;
+ __ ret(0);
}
- __ ret(0);
}
// Slow case: call runtime.
diff --git a/src/x64/virtual-frame-x64.cc b/src/x64/virtual-frame-x64.cc
index c4d7e656..10c327aa 100644
--- a/src/x64/virtual-frame-x64.cc
+++ b/src/x64/virtual-frame-x64.cc
@@ -113,7 +113,7 @@ void VirtualFrame::AllocateStackSlots() {
// them later. First sync everything above the stack pointer so we can
// use pushes to allocate and initialize the locals.
SyncRange(stack_pointer_ + 1, element_count() - 1);
- Handle<Object> undefined = Factory::undefined_value();
+ Handle<Object> undefined = FACTORY->undefined_value();
FrameElement initial_value =
FrameElement::ConstantElement(undefined, FrameElement::SYNCED);
if (count < kLocalVarBound) {
@@ -1019,7 +1019,7 @@ void VirtualFrame::SyncRange(int begin, int end) {
//------------------------------------------------------------------------------
// Virtual frame stub and IC calling functions.
-Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
+Result VirtualFrame::CallRuntime(const Runtime::Function* f, int arg_count) {
PrepareForCall(arg_count, arg_count);
ASSERT(cgen()->HasValidEntryRegisters());
__ CallRuntime(f, arg_count);
@@ -1115,7 +1115,8 @@ void VirtualFrame::MoveResultsToRegisters(Result* a,
Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
// Name and receiver are on the top of the frame. Both are dropped.
// The IC expects name in rcx and receiver in rax.
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kLoadIC_Initialize));
Result name = Pop();
Result receiver = Pop();
PrepareForCall(0, 0);
@@ -1132,7 +1133,8 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
PrepareForCall(0, 0);
MoveResultsToRegisters(&key, &receiver, rax, rdx);
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_Initialize));
return RawCallCodeObject(ic, mode);
}
@@ -1142,9 +1144,9 @@ Result VirtualFrame::CallStoreIC(Handle<String> name,
StrictModeFlag strict_mode) {
// Value and (if not contextual) receiver are on top of the frame.
// The IC expects name in rcx, value in rax, and receiver in rdx.
- Handle<Code> ic(Builtins::builtin(
- (strict_mode == kStrictMode) ? Builtins::StoreIC_Initialize_Strict
- : Builtins::StoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ (strict_mode == kStrictMode) ? Builtins::kStoreIC_Initialize_Strict
+ : Builtins::kStoreIC_Initialize));
Result value = Pop();
RelocInfo::Mode mode;
if (is_contextual) {
@@ -1208,9 +1210,9 @@ Result VirtualFrame::CallKeyedStoreIC(StrictModeFlag strict_mode) {
receiver.Unuse();
}
- Handle<Code> ic(Builtins::builtin(
- (strict_mode == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict
- : Builtins::KeyedStoreIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ (strict_mode == kStrictMode) ? Builtins::kKeyedStoreIC_Initialize_Strict
+ : Builtins::kKeyedStoreIC_Initialize));
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
}
@@ -1222,7 +1224,8 @@ Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
// and dropped by the call. The IC expects the name in rcx and the rest
// on the stack, and drops them all.
InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
+ Handle<Code> ic =
+ ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop);
Result name = Pop();
// Spill args, receiver, and function. The call will drop args and
// receiver.
@@ -1241,7 +1244,7 @@ Result VirtualFrame::CallKeyedCallIC(RelocInfo::Mode mode,
// on the stack, and drops them all.
InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
+ ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
Result name = Pop();
// Spill args, receiver, and function. The call will drop args and
// receiver.
@@ -1256,7 +1259,8 @@ Result VirtualFrame::CallConstructor(int arg_count) {
// Arguments, receiver, and function are on top of the frame. The
// IC expects arg count in rax, function in rdi, and the arguments
// and receiver on the stack.
- Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kJSConstructCall));
// Duplicate the function before preparing the frame.
PushElementAt(arg_count);
Result function = Pop();
diff --git a/src/x64/virtual-frame-x64.h b/src/x64/virtual-frame-x64.h
index 7396db17..aac98643 100644
--- a/src/x64/virtual-frame-x64.h
+++ b/src/x64/virtual-frame-x64.h
@@ -67,7 +67,9 @@ class VirtualFrame : public ZoneObject {
private:
bool previous_state_;
- CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
+ CodeGenerator* cgen() {
+ return CodeGeneratorScope::Current(Isolate::Current());
+ }
};
// An illegal index into the virtual frame.
@@ -79,7 +81,10 @@ class VirtualFrame : public ZoneObject {
// Construct a virtual frame as a clone of an existing one.
explicit inline VirtualFrame(VirtualFrame* original);
- CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
+ CodeGenerator* cgen() {
+ return CodeGeneratorScope::Current(Isolate::Current());
+ }
+
MacroAssembler* masm() { return cgen()->masm(); }
// Create a duplicate of an existing valid frame element.
@@ -315,7 +320,7 @@ class VirtualFrame : public ZoneObject {
// Call runtime given the number of arguments expected on (and
// removed from) the stack.
- Result CallRuntime(Runtime::Function* f, int arg_count);
+ Result CallRuntime(const Runtime::Function* f, int arg_count);
Result CallRuntime(Runtime::FunctionId id, int arg_count);
#ifdef ENABLE_DEBUGGER_SUPPORT
@@ -342,7 +347,6 @@ class VirtualFrame : public ZoneObject {
StrictModeFlag strict_mode);
// Call keyed store IC. Value, key, and receiver are found on top
- // of the frame. All three are dropped.
Result CallKeyedStoreIC(StrictModeFlag strict_mode);
// Call call IC. Function name, arguments, and receiver are found on top
diff --git a/src/zone-inl.h b/src/zone-inl.h
index 46729603..516fc4aa 100644
--- a/src/zone-inl.h
+++ b/src/zone-inl.h
@@ -28,6 +28,7 @@
#ifndef V8_ZONE_INL_H_
#define V8_ZONE_INL_H_
+#include "isolate.h"
#include "zone.h"
#include "v8-counters.h"
@@ -35,8 +36,19 @@ namespace v8 {
namespace internal {
+AssertNoZoneAllocation::AssertNoZoneAllocation()
+ : prev_(Isolate::Current()->zone_allow_allocation()) {
+ Isolate::Current()->set_zone_allow_allocation(false);
+}
+
+
+AssertNoZoneAllocation::~AssertNoZoneAllocation() {
+ Isolate::Current()->set_zone_allow_allocation(prev_);
+}
+
+
inline void* Zone::New(int size) {
- ASSERT(AssertNoZoneAllocation::allow_allocation());
+ ASSERT(Isolate::Current()->zone_allow_allocation());
ASSERT(ZoneScope::nesting() > 0);
// Round up the requested size to fit the alignment.
size = RoundUp(size, kAlignment);
@@ -54,7 +66,7 @@ inline void* Zone::New(int size) {
template <typename T>
T* Zone::NewArray(int length) {
- return static_cast<T*>(Zone::New(length * sizeof(T)));
+ return static_cast<T*>(New(length * sizeof(T)));
}
@@ -65,7 +77,7 @@ bool Zone::excess_allocation() {
void Zone::adjust_segment_bytes_allocated(int delta) {
segment_bytes_allocated_ += delta;
- Counters::zone_segment_bytes.Set(segment_bytes_allocated_);
+ isolate_->counters()->zone_segment_bytes()->Set(segment_bytes_allocated_);
}
@@ -78,6 +90,36 @@ ZoneSplayTree<Config>::~ZoneSplayTree() {
}
+// TODO(isolates): for performance reasons, this should be replaced with a new
+// operator that takes the zone in which the object should be
+// allocated.
+void* ZoneObject::operator new(size_t size) {
+ return ZONE->New(static_cast<int>(size));
+}
+
+
+inline void* ZoneListAllocationPolicy::New(int size) {
+ return ZONE->New(size);
+}
+
+
+ZoneScope::ZoneScope(ZoneScopeMode mode)
+ : isolate_(Isolate::Current()),
+ mode_(mode) {
+ isolate_->zone()->scope_nesting_++;
+}
+
+
+bool ZoneScope::ShouldDeleteOnExit() {
+ return isolate_->zone()->scope_nesting_ == 1 && mode_ == DELETE_ON_EXIT;
+}
+
+
+int ZoneScope::nesting() {
+ return Isolate::Current()->zone()->scope_nesting_;
+}
+
+
} } // namespace v8::internal
#endif // V8_ZONE_INL_H_
diff --git a/src/zone.cc b/src/zone.cc
index f8dbaabc..42ce8c5c 100644
--- a/src/zone.cc
+++ b/src/zone.cc
@@ -34,20 +34,28 @@ namespace v8 {
namespace internal {
-Address Zone::position_ = 0;
-Address Zone::limit_ = 0;
-int Zone::zone_excess_limit_ = 256 * MB;
-int Zone::segment_bytes_allocated_ = 0;
+Zone::Zone()
+ : zone_excess_limit_(256 * MB),
+ segment_bytes_allocated_(0),
+ position_(0),
+ limit_(0),
+ scope_nesting_(0),
+ segment_head_(NULL) {
+}
unsigned Zone::allocation_size_ = 0;
-bool AssertNoZoneAllocation::allow_allocation_ = true;
-int ZoneScope::nesting_ = 0;
+ZoneScope::~ZoneScope() {
+ ASSERT_EQ(Isolate::Current(), isolate_);
+ if (ShouldDeleteOnExit()) isolate_->zone()->DeleteAll();
+ isolate_->zone()->scope_nesting_--;
+}
+
// Segments represent chunks of memory: They have starting address
// (encoded in the this pointer) and a size in bytes. Segments are
// chained together forming a LIFO structure with the newest segment
-// available as Segment::head(). Segments are allocated using malloc()
+// available as segment_head_. Segments are allocated using malloc()
// and de-allocated using free().
class Segment {
@@ -61,45 +69,38 @@ class Segment {
Address start() const { return address(sizeof(Segment)); }
Address end() const { return address(size_); }
- static Segment* head() { return head_; }
- static void set_head(Segment* head) { head_ = head; }
-
- // Creates a new segment, sets it size, and pushes it to the front
- // of the segment chain. Returns the new segment.
- static Segment* New(int size) {
- Segment* result = reinterpret_cast<Segment*>(Malloced::New(size));
- Zone::adjust_segment_bytes_allocated(size);
- if (result != NULL) {
- result->next_ = head_;
- result->size_ = size;
- head_ = result;
- }
- return result;
- }
-
- // Deletes the given segment. Does not touch the segment chain.
- static void Delete(Segment* segment, int size) {
- Zone::adjust_segment_bytes_allocated(-size);
- Malloced::Delete(segment);
- }
-
- static int bytes_allocated() { return bytes_allocated_; }
-
private:
// Computes the address of the nth byte in this segment.
Address address(int n) const {
return Address(this) + n;
}
- static Segment* head_;
- static int bytes_allocated_;
Segment* next_;
int size_;
+
+ friend class Zone;
};
-Segment* Segment::head_ = NULL;
-int Segment::bytes_allocated_ = 0;
+// Creates a new segment, sets it size, and pushes it to the front
+// of the segment chain. Returns the new segment.
+Segment* Zone::NewSegment(int size) {
+ Segment* result = reinterpret_cast<Segment*>(Malloced::New(size));
+ adjust_segment_bytes_allocated(size);
+ if (result != NULL) {
+ result->next_ = segment_head_;
+ result->size_ = size;
+ segment_head_ = result;
+ }
+ return result;
+}
+
+
+// Deletes the given segment. Does not touch the segment chain.
+void Zone::DeleteSegment(Segment* segment, int size) {
+ adjust_segment_bytes_allocated(-size);
+ Malloced::Delete(segment);
+}
void Zone::DeleteAll() {
@@ -109,14 +110,14 @@ void Zone::DeleteAll() {
#endif
// Find a segment with a suitable size to keep around.
- Segment* keep = Segment::head();
+ Segment* keep = segment_head_;
while (keep != NULL && keep->size() > kMaximumKeptSegmentSize) {
keep = keep->next();
}
// Traverse the chained list of segments, zapping (in debug mode)
// and freeing every segment except the one we wish to keep.
- Segment* current = Segment::head();
+ Segment* current = segment_head_;
while (current != NULL) {
Segment* next = current->next();
if (current == keep) {
@@ -128,7 +129,7 @@ void Zone::DeleteAll() {
// Zap the entire current segment (including the header).
memset(current, kZapDeadByte, size);
#endif
- Segment::Delete(current, size);
+ DeleteSegment(current, size);
}
current = next;
}
@@ -150,7 +151,7 @@ void Zone::DeleteAll() {
}
// Update the head segment to be the kept segment (if any).
- Segment::set_head(keep);
+ segment_head_ = keep;
}
@@ -164,7 +165,7 @@ Address Zone::NewExpand(int size) {
// strategy, where we increase the segment size every time we expand
// except that we employ a maximum segment size when we delete. This
// is to avoid excessive malloc() and free() overhead.
- Segment* head = Segment::head();
+ Segment* head = segment_head_;
int old_size = (head == NULL) ? 0 : head->size();
static const int kSegmentOverhead = sizeof(Segment) + kAlignment;
int new_size = kSegmentOverhead + size + (old_size << 1);
@@ -177,7 +178,7 @@ Address Zone::NewExpand(int size) {
// requested size.
new_size = Max(kSegmentOverhead + size, kMaximumSegmentSize);
}
- Segment* segment = Segment::New(new_size);
+ Segment* segment = NewSegment(new_size);
if (segment == NULL) {
V8::FatalProcessOutOfMemory("Zone");
return NULL;
diff --git a/src/zone.h b/src/zone.h
index e299f158..13b55c4c 100644
--- a/src/zone.h
+++ b/src/zone.h
@@ -39,6 +39,7 @@ enum ZoneScopeMode {
DONT_DELETE_ON_EXIT
};
+class Segment;
// The Zone supports very fast allocation of small chunks of
// memory. The chunks cannot be deallocated individually, but instead
@@ -57,23 +58,25 @@ class Zone {
public:
// Allocate 'size' bytes of memory in the Zone; expands the Zone by
// allocating new segments of memory on demand using malloc().
- static inline void* New(int size);
+ inline void* New(int size);
template <typename T>
- static inline T* NewArray(int length);
+ inline T* NewArray(int length);
// Delete all objects and free all memory allocated in the Zone.
- static void DeleteAll();
+ void DeleteAll();
// Returns true if more memory has been allocated in zones than
// the limit allows.
- static inline bool excess_allocation();
+ inline bool excess_allocation();
- static inline void adjust_segment_bytes_allocated(int delta);
+ inline void adjust_segment_bytes_allocated(int delta);
static unsigned allocation_size_;
private:
+ friend class Isolate;
+ friend class ZoneScope;
// All pointers returned from New() have this alignment.
static const int kAlignment = kPointerSize;
@@ -88,30 +91,39 @@ class Zone {
static const int kMaximumKeptSegmentSize = 64 * KB;
// Report zone excess when allocation exceeds this limit.
- static int zone_excess_limit_;
+ int zone_excess_limit_;
// The number of bytes allocated in segments. Note that this number
// includes memory allocated from the OS but not yet allocated from
// the zone.
- static int segment_bytes_allocated_;
-
- // The Zone is intentionally a singleton; you should not try to
- // allocate instances of the class.
- Zone() { UNREACHABLE(); }
+ int segment_bytes_allocated_;
+ // Each isolate gets its own zone.
+ Zone();
// Expand the Zone to hold at least 'size' more bytes and allocate
// the bytes. Returns the address of the newly allocated chunk of
// memory in the Zone. Should only be called if there isn't enough
// room in the Zone already.
- static Address NewExpand(int size);
+ Address NewExpand(int size);
+
+ // Creates a new segment, sets it size, and pushes it to the front
+ // of the segment chain. Returns the new segment.
+ Segment* NewSegment(int size);
+ // Deletes the given segment. Does not touch the segment chain.
+ void DeleteSegment(Segment* segment, int size);
// The free region in the current (front) segment is represented as
// the half-open interval [position, limit). The 'position' variable
// is guaranteed to be aligned as dictated by kAlignment.
- static Address position_;
- static Address limit_;
+ Address position_;
+ Address limit_;
+
+ int scope_nesting_;
+
+ Segment* segment_head_;
+ Isolate* isolate_;
};
@@ -120,7 +132,7 @@ class Zone {
class ZoneObject {
public:
// Allocate a new ZoneObject of 'size' bytes in the Zone.
- void* operator new(size_t size) { return Zone::New(static_cast<int>(size)); }
+ inline void* operator new(size_t size);
// Ideally, the delete operator should be private instead of
// public, but unfortunately the compiler sometimes synthesizes
@@ -136,14 +148,10 @@ class ZoneObject {
class AssertNoZoneAllocation {
public:
- AssertNoZoneAllocation() : prev_(allow_allocation_) {
- allow_allocation_ = false;
- }
- ~AssertNoZoneAllocation() { allow_allocation_ = prev_; }
- static bool allow_allocation() { return allow_allocation_; }
+ inline AssertNoZoneAllocation();
+ inline ~AssertNoZoneAllocation();
private:
bool prev_;
- static bool allow_allocation_;
};
@@ -153,7 +161,7 @@ class AssertNoZoneAllocation {
class ZoneListAllocationPolicy {
public:
// Allocate 'size' bytes of memory in the zone.
- static void* New(int size) { return Zone::New(size); }
+ static inline void* New(int size);
// De-allocation attempts are silently ignored.
static void Delete(void* p) { }
@@ -189,18 +197,12 @@ typedef ZoneList<Handle<Map> > ZoneMapList;
// outer-most scope.
class ZoneScope BASE_EMBEDDED {
public:
- explicit ZoneScope(ZoneScopeMode mode) : mode_(mode) {
- nesting_++;
- }
+ // TODO(isolates): pass isolate pointer here.
+ inline explicit ZoneScope(ZoneScopeMode mode);
- virtual ~ZoneScope() {
- if (ShouldDeleteOnExit()) Zone::DeleteAll();
- --nesting_;
- }
+ virtual ~ZoneScope();
- bool ShouldDeleteOnExit() {
- return nesting_ == 1 && mode_ == DELETE_ON_EXIT;
- }
+ inline bool ShouldDeleteOnExit();
// For ZoneScopes that do not delete on exit by default, call this
// method to request deletion on exit.
@@ -208,11 +210,11 @@ class ZoneScope BASE_EMBEDDED {
mode_ = DELETE_ON_EXIT;
}
- static int nesting() { return nesting_; }
+ inline static int nesting();
private:
+ Isolate* isolate_;
ZoneScopeMode mode_;
- static int nesting_;
};
diff --git a/test/benchmarks/testcfg.py b/test/benchmarks/testcfg.py
new file mode 100644
index 00000000..51d85208
--- /dev/null
+++ b/test/benchmarks/testcfg.py
@@ -0,0 +1,100 @@
+# Copyright 2011 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import test
+import os
+from os.path import join, split
+
+def IsNumber(string):
+ try:
+ float(string)
+ return True
+ except ValueError:
+ return False
+
+
+class BenchmarkTestCase(test.TestCase):
+
+ def __init__(self, path, context, mode):
+ super(BenchmarkTestCase, self).__init__(context, split(path), mode)
+ self.root = path
+
+ def GetLabel(self):
+ return '%s benchmark %s' % (self.mode, self.GetName())
+
+ def IsFailureOutput(self, output):
+ if output.exit_code != 0:
+ return True
+ lines = output.stdout.splitlines()
+ for line in lines:
+ colon_index = line.find(':')
+ if colon_index >= 0:
+ if not IsNumber(line[colon_index+1:].strip()):
+ return True
+ return False
+
+ def GetCommand(self):
+ result = self.context.GetVmCommand(self, self.mode)
+ result.append(join(self.root, 'run.js'))
+ return result
+
+ def GetName(self):
+ return 'V8'
+
+ def BeforeRun(self):
+ os.chdir(self.root)
+
+ def AfterRun(self, result):
+ os.chdir(self.context.buildspace)
+
+ def GetSource(self):
+ return open(join(self.root, 'run.js')).read()
+
+ def GetCustomFlags(self, mode):
+ return []
+
+
+class BenchmarkTestConfiguration(test.TestConfiguration):
+
+ def __init__(self, context, root):
+ super(BenchmarkTestConfiguration, self).__init__(context, root)
+
+ def ListTests(self, current_path, path, mode, variant_flags):
+ path = self.context.workspace
+ path = join(path, 'benchmarks')
+ test = BenchmarkTestCase(path, self.context, mode)
+ return [test]
+
+ def GetBuildRequirements(self):
+ return ['sample', 'sample=shell']
+
+ def GetTestStatus(self, sections, defs):
+ pass
+
+def GetConfiguration(context, root):
+ return BenchmarkTestConfiguration(context, root)
diff --git a/test/cctest/SConscript b/test/cctest/SConscript
index 70381377..f4cb4a9a 100644
--- a/test/cctest/SConscript
+++ b/test/cctest/SConscript
@@ -41,8 +41,8 @@ SOURCES = {
'test-alloc.cc',
'test-api.cc',
'test-ast.cc',
- 'test-bignum.cc',
'test-bignum-dtoa.cc',
+ 'test-bignum.cc',
'test-circular-queue.cc',
'test-compiler.cc',
'test-conversions.cc',
@@ -59,15 +59,16 @@ SOURCES = {
'test-flags.cc',
'test-func-name-inference.cc',
'test-hashmap.cc',
- 'test-heap.cc',
'test-heap-profiler.cc',
+ 'test-heap.cc',
'test-list.cc',
'test-liveedit.cc',
'test-lock.cc',
- 'test-log.cc',
'test-log-utils.cc',
+ 'test-log.cc',
'test-mark-compact.cc',
'test-parsing.cc',
+ 'test-platform-tls.cc',
'test-profile-generator.cc',
'test-regexp.cc',
'test-reloc-info.cc',
@@ -95,7 +96,7 @@ SOURCES = {
'arch:x64': ['test-assembler-x64.cc',
'test-macro-assembler-x64.cc',
'test-log-stack-tracer.cc'],
- 'arch:mips': ['test-assembler-mips.cc', 'test-mips.cc'],
+ 'arch:mips': ['test-assembler-mips.cc'],
'os:linux': ['test-platform-linux.cc'],
'os:macos': ['test-platform-macos.cc'],
'os:nullos': ['test-platform-nullos.cc'],
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index 404b692b..277593c3 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -87,8 +87,9 @@ class CcTest {
class ApiTestFuzzer: public v8::internal::Thread {
public:
void CallTest();
- explicit ApiTestFuzzer(int num)
- : test_number_(num),
+ explicit ApiTestFuzzer(v8::internal::Isolate* isolate, int num)
+ : Thread(isolate, "ApiTestFuzzer"),
+ test_number_(num),
gate_(v8::internal::OS::CreateSemaphore(0)),
active_(true) {
}
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index e573eb29..986fb8d7 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -36,11 +36,6 @@ test-debug/DebuggerAgent: PASS, (PASS || FAIL) if $system == linux
# BUG(382): Weird test. Can't guarantee that it never times out.
test-api/ApplyInterruption: PASS || TIMEOUT
-# BUG(484): This test which we thought was originally corrected in r5236
-# is re-appearing. Disabled until bug in test is fixed. This only fails
-# when snapshot is on, so I am marking it PASS || FAIL
-test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL
-
# These tests always fail. They are here to test test.py. If
# they don't fail then test.py has failed.
test-serialize/TestThatAlwaysFails: FAIL
@@ -62,12 +57,6 @@ test-log/ProfLazyMode: SKIP
test-debug/DebuggerAgentProtocolOverflowHeader: SKIP
test-sockets/Socket: SKIP
-# BUG(1075): Some deserialization tests fail om ARM
-test-serialize/Deserialize: SKIP
-test-serialize/DeserializeFromSecondSerializationAndRunScript2: SKIP
-test-serialize/DeserializeAndRunScript2: SKIP
-test-serialize/DeserializeFromSecondSerialization: SKIP
-
##############################################################################
[ $arch == arm && $crankshaft ]
@@ -85,15 +74,21 @@ test-compiler: SKIP
test-cpu-profiler: SKIP
test-debug: SKIP
test-decls: SKIP
+test-deoptimization: SKIP
test-func-name-inference: SKIP
test-heap: SKIP
test-heap-profiler: SKIP
test-log: SKIP
test-log-utils: SKIP
test-mark-compact: SKIP
+test-parsing: SKIP
+test-profile-generator: SKIP
test-regexp: SKIP
test-serialize: SKIP
test-sockets: SKIP
test-strings: SKIP
test-threads: SKIP
test-thread-termination: SKIP
+
+##############################################################################
+# Tests that time out with Isolates
diff --git a/test/cctest/test-accessors.cc b/test/cctest/test-accessors.cc
index 25f5c395..b74f166f 100644
--- a/test/cctest/test-accessors.cc
+++ b/test/cctest/test-accessors.cc
@@ -243,7 +243,7 @@ static v8::Handle<Value> CheckAccessorArgsCorrect(Local<String> name,
ApiTestFuzzer::Fuzz();
CHECK(info.This() == info.Holder());
CHECK(info.Data()->Equals(v8::String::New("data")));
- i::Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
CHECK(info.This() == info.Holder());
CHECK(info.Data()->Equals(v8::String::New("data")));
return v8::Integer::New(17);
@@ -397,9 +397,9 @@ static v8::Handle<Value> StackCheck(Local<String> name,
for (int i = 0; !iter.done(); i++) {
i::StackFrame* frame = iter.frame();
CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
- CHECK(frame->code()->IsCode());
+ i::Code* code = frame->LookupCode(i::Isolate::Current());
+ CHECK(code->IsCode());
i::Address pc = frame->pc();
- i::Code* code = frame->code();
CHECK(code->contains(pc));
iter.Advance();
}
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index d2a28d7f..3d8157d9 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -27,7 +27,6 @@
#include "v8.h"
#include "accessors.h"
-#include "top.h"
#include "cctest.h"
@@ -38,13 +37,14 @@ using namespace v8::internal;
static MaybeObject* AllocateAfterFailures() {
static int attempts = 0;
if (++attempts < 3) return Failure::RetryAfterGC();
+ Heap* heap = Isolate::Current()->heap();
// New space.
- NewSpace* new_space = Heap::new_space();
+ NewSpace* new_space = heap->new_space();
static const int kNewSpaceFillerSize = ByteArray::SizeFor(0);
while (new_space->Available() > kNewSpaceFillerSize) {
int available_before = static_cast<int>(new_space->Available());
- CHECK(!Heap::AllocateByteArray(0)->IsFailure());
+ CHECK(!heap->AllocateByteArray(0)->IsFailure());
if (available_before == new_space->Available()) {
// It seems that we are avoiding new space allocations when
// allocation is forced, so no need to fill up new space
@@ -52,45 +52,46 @@ static MaybeObject* AllocateAfterFailures() {
break;
}
}
- CHECK(!Heap::AllocateByteArray(100)->IsFailure());
- CHECK(!Heap::AllocateFixedArray(100, NOT_TENURED)->IsFailure());
+ CHECK(!heap->AllocateByteArray(100)->IsFailure());
+ CHECK(!heap->AllocateFixedArray(100, NOT_TENURED)->IsFailure());
// Make sure we can allocate through optimized allocation functions
// for specific kinds.
- CHECK(!Heap::AllocateFixedArray(100)->IsFailure());
- CHECK(!Heap::AllocateHeapNumber(0.42)->IsFailure());
- CHECK(!Heap::AllocateArgumentsObject(Smi::FromInt(87), 10)->IsFailure());
- Object* object =
- Heap::AllocateJSObject(*Top::object_function())->ToObjectChecked();
- CHECK(!Heap::CopyJSObject(JSObject::cast(object))->IsFailure());
+ CHECK(!heap->AllocateFixedArray(100)->IsFailure());
+ CHECK(!heap->AllocateHeapNumber(0.42)->IsFailure());
+ CHECK(!heap->AllocateArgumentsObject(Smi::FromInt(87), 10)->IsFailure());
+ Object* object = heap->AllocateJSObject(
+ *Isolate::Current()->object_function())->ToObjectChecked();
+ CHECK(!heap->CopyJSObject(JSObject::cast(object))->IsFailure());
// Old data space.
- OldSpace* old_data_space = Heap::old_data_space();
+ OldSpace* old_data_space = heap->old_data_space();
static const int kOldDataSpaceFillerSize = ByteArray::SizeFor(0);
while (old_data_space->Available() > kOldDataSpaceFillerSize) {
- CHECK(!Heap::AllocateByteArray(0, TENURED)->IsFailure());
+ CHECK(!heap->AllocateByteArray(0, TENURED)->IsFailure());
}
- CHECK(!Heap::AllocateRawAsciiString(100, TENURED)->IsFailure());
+ CHECK(!heap->AllocateRawAsciiString(100, TENURED)->IsFailure());
// Large object space.
- while (!Heap::OldGenerationAllocationLimitReached()) {
- CHECK(!Heap::AllocateFixedArray(10000, TENURED)->IsFailure());
+ while (!heap->OldGenerationAllocationLimitReached()) {
+ CHECK(!heap->AllocateFixedArray(10000, TENURED)->IsFailure());
}
- CHECK(!Heap::AllocateFixedArray(10000, TENURED)->IsFailure());
+ CHECK(!heap->AllocateFixedArray(10000, TENURED)->IsFailure());
// Map space.
- MapSpace* map_space = Heap::map_space();
+ MapSpace* map_space = heap->map_space();
static const int kMapSpaceFillerSize = Map::kSize;
InstanceType instance_type = JS_OBJECT_TYPE;
int instance_size = JSObject::kHeaderSize;
while (map_space->Available() > kMapSpaceFillerSize) {
- CHECK(!Heap::AllocateMap(instance_type, instance_size)->IsFailure());
+ CHECK(!heap->AllocateMap(instance_type, instance_size)->IsFailure());
}
- CHECK(!Heap::AllocateMap(instance_type, instance_size)->IsFailure());
+ CHECK(!heap->AllocateMap(instance_type, instance_size)->IsFailure());
// Test that we can allocate in old pointer space and code space.
- CHECK(!Heap::AllocateFixedArray(100, TENURED)->IsFailure());
- CHECK(!Heap::CopyCode(Builtins::builtin(Builtins::Illegal))->IsFailure());
+ CHECK(!heap->AllocateFixedArray(100, TENURED)->IsFailure());
+ CHECK(!heap->CopyCode(Isolate::Current()->builtins()->builtin(
+ Builtins::kIllegal))->IsFailure());
// Return success.
return Smi::FromInt(42);
@@ -98,7 +99,7 @@ static MaybeObject* AllocateAfterFailures() {
static Handle<Object> Test() {
- CALL_HEAP_FUNCTION(AllocateAfterFailures(), Object);
+ CALL_HEAP_FUNCTION(ISOLATE, AllocateAfterFailures(), Object);
}
@@ -129,18 +130,19 @@ TEST(StressJS) {
v8::HandleScope scope;
env->Enter();
Handle<JSFunction> function =
- Factory::NewFunction(Factory::function_symbol(), Factory::null_value());
+ FACTORY->NewFunction(FACTORY->function_symbol(), FACTORY->null_value());
// Force the creation of an initial map and set the code to
// something empty.
- Factory::NewJSObject(function);
- function->ReplaceCode(Builtins::builtin(Builtins::EmptyFunction));
+ FACTORY->NewJSObject(function);
+ function->ReplaceCode(Isolate::Current()->builtins()->builtin(
+ Builtins::kEmptyFunction));
// Patch the map to have an accessor for "get".
Handle<Map> map(function->initial_map());
Handle<DescriptorArray> instance_descriptors(map->instance_descriptors());
- Handle<Proxy> proxy = Factory::NewProxy(&kDescriptor);
- instance_descriptors = Factory::CopyAppendProxyDescriptor(
+ Handle<Proxy> proxy = FACTORY->NewProxy(&kDescriptor);
+ instance_descriptors = FACTORY->CopyAppendProxyDescriptor(
instance_descriptors,
- Factory::NewStringFromAscii(Vector<const char>("get", 3)),
+ FACTORY->NewStringFromAscii(Vector<const char>("get", 3)),
proxy,
static_cast<PropertyAttributes>(0));
map->set_instance_descriptors(*instance_descriptors);
@@ -183,7 +185,8 @@ class Block {
TEST(CodeRange) {
const int code_range_size = 16*MB;
- CodeRange::Setup(code_range_size);
+ OS::Setup();
+ Isolate::Current()->code_range()->Setup(code_range_size);
int current_allocated = 0;
int total_allocated = 0;
List<Block> blocks(1000);
@@ -195,14 +198,16 @@ TEST(CodeRange) {
size_t requested = (Page::kPageSize << (Pseudorandom() % 6)) +
Pseudorandom() % 5000 + 1;
size_t allocated = 0;
- void* base = CodeRange::AllocateRawMemory(requested, &allocated);
+ void* base = Isolate::Current()->code_range()->
+ AllocateRawMemory(requested, &allocated);
blocks.Add(Block(base, static_cast<int>(allocated)));
current_allocated += static_cast<int>(allocated);
total_allocated += static_cast<int>(allocated);
} else {
// Free a block.
int index = Pseudorandom() % blocks.length();
- CodeRange::FreeRawMemory(blocks[index].base, blocks[index].size);
+ Isolate::Current()->code_range()->FreeRawMemory(
+ blocks[index].base, blocks[index].size);
current_allocated -= blocks[index].size;
if (index < blocks.length() - 1) {
blocks[index] = blocks.RemoveLast();
@@ -212,5 +217,5 @@ TEST(CodeRange) {
}
}
- CodeRange::TearDown();
+ Isolate::Current()->code_range()->TearDown();
}
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index cd264127..33d505ea 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -34,7 +34,6 @@
#include "execution.h"
#include "snapshot.h"
#include "platform.h"
-#include "top.h"
#include "utils.h"
#include "cctest.h"
#include "parser.h"
@@ -50,15 +49,19 @@ static bool IsNaN(double x) {
#endif
}
-using ::v8::ObjectTemplate;
-using ::v8::Value;
+using ::v8::AccessorInfo;
using ::v8::Context;
+using ::v8::Extension;
+using ::v8::Function;
+using ::v8::HandleScope;
using ::v8::Local;
-using ::v8::String;
+using ::v8::Object;
+using ::v8::ObjectTemplate;
+using ::v8::Persistent;
using ::v8::Script;
-using ::v8::Function;
-using ::v8::AccessorInfo;
-using ::v8::Extension;
+using ::v8::String;
+using ::v8::Value;
+using ::v8::V8;
namespace i = ::i;
@@ -394,11 +397,11 @@ THREADED_TEST(ScriptUsingStringResource) {
CHECK(source->IsExternal());
CHECK_EQ(resource,
static_cast<TestResource*>(source->GetExternalStringResource()));
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(0, TestResource::dispose_count);
}
- i::CompilationCache::Clear();
- i::Heap::CollectAllGarbage(false);
+ v8::internal::Isolate::Current()->compilation_cache()->Clear();
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(1, TestResource::dispose_count);
}
@@ -415,11 +418,11 @@ THREADED_TEST(ScriptUsingAsciiStringResource) {
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(0, TestAsciiResource::dispose_count);
}
- i::CompilationCache::Clear();
- i::Heap::CollectAllGarbage(false);
+ i::Isolate::Current()->compilation_cache()->Clear();
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(1, TestAsciiResource::dispose_count);
}
@@ -432,19 +435,19 @@ THREADED_TEST(ScriptMakingExternalString) {
LocalContext env;
Local<String> source = String::New(two_byte_source);
// Trigger GCs so that the newly allocated string moves to old gen.
- i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
- i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
bool success = source->MakeExternal(new TestResource(two_byte_source));
CHECK(success);
Local<Script> script = Script::Compile(source);
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(0, TestResource::dispose_count);
}
- i::CompilationCache::Clear();
- i::Heap::CollectAllGarbage(false);
+ i::Isolate::Current()->compilation_cache()->Clear();
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(1, TestResource::dispose_count);
}
@@ -457,8 +460,8 @@ THREADED_TEST(ScriptMakingExternalAsciiString) {
LocalContext env;
Local<String> source = v8_str(c_source);
// Trigger GCs so that the newly allocated string moves to old gen.
- i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
- i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
bool success = source->MakeExternal(
new TestAsciiResource(i::StrDup(c_source)));
CHECK(success);
@@ -466,11 +469,11 @@ THREADED_TEST(ScriptMakingExternalAsciiString) {
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(0, TestAsciiResource::dispose_count);
}
- i::CompilationCache::Clear();
- i::Heap::CollectAllGarbage(false);
+ i::Isolate::Current()->compilation_cache()->Clear();
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(1, TestAsciiResource::dispose_count);
}
@@ -480,8 +483,8 @@ TEST(MakingExternalStringConditions) {
LocalContext env;
// Free some space in the new space so that we can check freshness.
- i::Heap::CollectGarbage(i::NEW_SPACE);
- i::Heap::CollectGarbage(i::NEW_SPACE);
+ HEAP->CollectGarbage(i::NEW_SPACE);
+ HEAP->CollectGarbage(i::NEW_SPACE);
uint16_t* two_byte_string = AsciiToTwoByteString("small");
Local<String> small_string = String::New(two_byte_string);
@@ -490,8 +493,8 @@ TEST(MakingExternalStringConditions) {
// We should refuse to externalize newly created small string.
CHECK(!small_string->CanMakeExternal());
// Trigger GCs so that the newly allocated string moves to old gen.
- i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
- i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
// Old space strings should be accepted.
CHECK(small_string->CanMakeExternal());
@@ -526,15 +529,15 @@ TEST(MakingExternalAsciiStringConditions) {
LocalContext env;
// Free some space in the new space so that we can check freshness.
- i::Heap::CollectGarbage(i::NEW_SPACE);
- i::Heap::CollectGarbage(i::NEW_SPACE);
+ HEAP->CollectGarbage(i::NEW_SPACE);
+ HEAP->CollectGarbage(i::NEW_SPACE);
Local<String> small_string = String::New("small");
// We should refuse to externalize newly created small string.
CHECK(!small_string->CanMakeExternal());
// Trigger GCs so that the newly allocated string moves to old gen.
- i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
- i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
// Old space strings should be accepted.
CHECK(small_string->CanMakeExternal());
@@ -566,13 +569,13 @@ THREADED_TEST(UsingExternalString) {
String::NewExternal(new TestResource(two_byte_string));
i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
// Trigger GCs so that the newly allocated string moves to old gen.
- i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
- i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
- i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
+ HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
+ i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
CHECK(isymbol->IsSymbol());
}
- i::Heap::CollectAllGarbage(false);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
}
@@ -584,13 +587,13 @@ THREADED_TEST(UsingExternalAsciiString) {
new TestAsciiResource(i::StrDup(one_byte_string)));
i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
// Trigger GCs so that the newly allocated string moves to old gen.
- i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
- i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
- i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
+ HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
+ HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
+ i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
CHECK(isymbol->IsSymbol());
}
- i::Heap::CollectAllGarbage(false);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
}
@@ -603,12 +606,12 @@ THREADED_TEST(ScavengeExternalString) {
Local<String> string =
String::NewExternal(new TestResource(two_byte_string));
i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
- i::Heap::CollectGarbage(i::NEW_SPACE);
- in_new_space = i::Heap::InNewSpace(*istring);
- CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
+ HEAP->CollectGarbage(i::NEW_SPACE);
+ in_new_space = HEAP->InNewSpace(*istring);
+ CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
CHECK_EQ(0, TestResource::dispose_count);
}
- i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
+ HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
CHECK_EQ(1, TestResource::dispose_count);
}
@@ -622,12 +625,12 @@ THREADED_TEST(ScavengeExternalAsciiString) {
Local<String> string = String::NewExternal(
new TestAsciiResource(i::StrDup(one_byte_string)));
i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
- i::Heap::CollectGarbage(i::NEW_SPACE);
- in_new_space = i::Heap::InNewSpace(*istring);
- CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
+ HEAP->CollectGarbage(i::NEW_SPACE);
+ in_new_space = HEAP->InNewSpace(*istring);
+ CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
CHECK_EQ(0, TestAsciiResource::dispose_count);
}
- i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
+ HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
CHECK_EQ(1, TestAsciiResource::dispose_count);
}
@@ -667,11 +670,11 @@ TEST(ExternalStringWithDisposeHandling) {
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(0, TestAsciiResource::dispose_count);
}
- i::CompilationCache::Clear();
- i::Heap::CollectAllGarbage(false);
+ i::Isolate::Current()->compilation_cache()->Clear();
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
CHECK_EQ(0, TestAsciiResource::dispose_count);
@@ -688,11 +691,11 @@ TEST(ExternalStringWithDisposeHandling) {
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(0, TestAsciiResource::dispose_count);
}
- i::CompilationCache::Clear();
- i::Heap::CollectAllGarbage(false);
+ i::Isolate::Current()->compilation_cache()->Clear();
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
CHECK_EQ(1, TestAsciiResource::dispose_count);
}
@@ -738,9 +741,9 @@ THREADED_TEST(StringConcat) {
CHECK(value->IsNumber());
CHECK_EQ(68, value->Int32Value());
}
- i::CompilationCache::Clear();
- i::Heap::CollectAllGarbage(false);
- i::Heap::CollectAllGarbage(false);
+ i::Isolate::Current()->compilation_cache()->Clear();
+ HEAP->CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
}
@@ -1575,12 +1578,12 @@ THREADED_TEST(InternalFieldsNativePointers) {
// Check reading and writing aligned pointers.
obj->SetPointerInInternalField(0, aligned);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
// Check reading and writing unaligned pointers.
obj->SetPointerInInternalField(0, unaligned);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
delete[] data;
@@ -1606,19 +1609,19 @@ THREADED_TEST(InternalFieldsNativePointersAndExternal) {
CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
obj->SetPointerInInternalField(0, aligned);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
obj->SetPointerInInternalField(0, unaligned);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
obj->SetInternalField(0, v8::External::Wrap(aligned));
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
obj->SetInternalField(0, v8::External::Wrap(unaligned));
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
delete[] data;
@@ -1631,7 +1634,7 @@ THREADED_TEST(IdentityHash) {
// Ensure that the test starts with an fresh heap to test whether the hash
// code is based on the address.
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
Local<v8::Object> obj = v8::Object::New();
int hash = obj->GetIdentityHash();
int hash1 = obj->GetIdentityHash();
@@ -1641,7 +1644,7 @@ THREADED_TEST(IdentityHash) {
// objects should not be assigned the same hash code. If the test below fails
// the random number generator should be evaluated.
CHECK_NE(hash, hash2);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
int hash3 = v8::Object::New()->GetIdentityHash();
// Make sure that the identity hash is not based on the initial address of
// the object alone. If the test below fails the random number generator
@@ -1678,7 +1681,7 @@ THREADED_TEST(HiddenProperties) {
v8::Local<v8::String> empty = v8_str("");
v8::Local<v8::String> prop_name = v8_str("prop_name");
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
// Make sure delete of a non-existent hidden value works
CHECK(obj->DeleteHiddenValue(key));
@@ -1688,7 +1691,7 @@ THREADED_TEST(HiddenProperties) {
CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
// Make sure we do not find the hidden property.
CHECK(!obj->Has(empty));
@@ -1699,7 +1702,7 @@ THREADED_TEST(HiddenProperties) {
CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
CHECK_EQ(2003, obj->Get(empty)->Int32Value());
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
// Add another property and delete it afterwards to force the object in
// slow case.
@@ -1710,7 +1713,7 @@ THREADED_TEST(HiddenProperties) {
CHECK(obj->Delete(prop_name));
CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK(obj->DeleteHiddenValue(key));
CHECK(obj->GetHiddenValue(key).IsEmpty());
@@ -1789,6 +1792,180 @@ THREADED_TEST(GlobalHandle) {
}
+static int NumberOfWeakCalls = 0;
+static void WeakPointerCallback(Persistent<Value> handle, void* id) {
+ CHECK_EQ(reinterpret_cast<void*>(1234), id);
+ NumberOfWeakCalls++;
+ handle.Dispose();
+}
+
+THREADED_TEST(ApiObjectGroups) {
+ HandleScope scope;
+ LocalContext env;
+
+ NumberOfWeakCalls = 0;
+
+ Persistent<Object> g1s1;
+ Persistent<Object> g1s2;
+ Persistent<Object> g1c1;
+ Persistent<Object> g2s1;
+ Persistent<Object> g2s2;
+ Persistent<Object> g2c1;
+
+ {
+ HandleScope scope;
+ g1s1 = Persistent<Object>::New(Object::New());
+ g1s2 = Persistent<Object>::New(Object::New());
+ g1c1 = Persistent<Object>::New(Object::New());
+ g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+
+ g2s1 = Persistent<Object>::New(Object::New());
+ g2s2 = Persistent<Object>::New(Object::New());
+ g2c1 = Persistent<Object>::New(Object::New());
+ g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ }
+
+ Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
+
+ // Connect group 1 and 2, make a cycle.
+ CHECK(g1s2->Set(0, g2s2));
+ CHECK(g2s1->Set(0, g1s1));
+
+ {
+ Persistent<Value> g1_objects[] = { g1s1, g1s2 };
+ Persistent<Value> g1_children[] = { g1c1 };
+ Persistent<Value> g2_objects[] = { g2s1, g2s2 };
+ Persistent<Value> g2_children[] = { g2c1 };
+ V8::AddObjectGroup(g1_objects, 2);
+ V8::AddImplicitReferences(g1s1, g1_children, 1);
+ V8::AddObjectGroup(g2_objects, 2);
+ V8::AddImplicitReferences(g2s2, g2_children, 1);
+ }
+ // Do a full GC
+ HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
+
+ // All object should be alive.
+ CHECK_EQ(0, NumberOfWeakCalls);
+
+ // Weaken the root.
+ root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ // But make children strong roots---all the objects (except for children)
+ // should be collectable now.
+ g1c1.ClearWeak();
+ g2c1.ClearWeak();
+
+ // Groups are deleted, rebuild groups.
+ {
+ Persistent<Value> g1_objects[] = { g1s1, g1s2 };
+ Persistent<Value> g1_children[] = { g1c1 };
+ Persistent<Value> g2_objects[] = { g2s1, g2s2 };
+ Persistent<Value> g2_children[] = { g2c1 };
+ V8::AddObjectGroup(g1_objects, 2);
+ V8::AddImplicitReferences(g1s1, g1_children, 1);
+ V8::AddObjectGroup(g2_objects, 2);
+ V8::AddImplicitReferences(g2s2, g2_children, 1);
+ }
+
+ HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
+
+ // All objects should be gone. 5 global handles in total.
+ CHECK_EQ(5, NumberOfWeakCalls);
+
+ // And now make children weak again and collect them.
+ g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+
+ HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
+ CHECK_EQ(7, NumberOfWeakCalls);
+}
+
+
+THREADED_TEST(ApiObjectGroupsCycle) {
+ HandleScope scope;
+ LocalContext env;
+
+ NumberOfWeakCalls = 0;
+
+ Persistent<Object> g1s1;
+ Persistent<Object> g1s2;
+ Persistent<Object> g2s1;
+ Persistent<Object> g2s2;
+ Persistent<Object> g3s1;
+ Persistent<Object> g3s2;
+
+ {
+ HandleScope scope;
+ g1s1 = Persistent<Object>::New(Object::New());
+ g1s2 = Persistent<Object>::New(Object::New());
+ g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+
+ g2s1 = Persistent<Object>::New(Object::New());
+ g2s2 = Persistent<Object>::New(Object::New());
+ g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+
+ g3s1 = Persistent<Object>::New(Object::New());
+ g3s2 = Persistent<Object>::New(Object::New());
+ g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+ }
+
+ Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
+
+ // Connect groups. We're building the following cycle:
+ // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
+ // groups.
+ {
+ Persistent<Value> g1_objects[] = { g1s1, g1s2 };
+ Persistent<Value> g1_children[] = { g2s1 };
+ Persistent<Value> g2_objects[] = { g2s1, g2s2 };
+ Persistent<Value> g2_children[] = { g3s1 };
+ Persistent<Value> g3_objects[] = { g3s1, g3s2 };
+ Persistent<Value> g3_children[] = { g1s1 };
+ V8::AddObjectGroup(g1_objects, 2);
+ V8::AddImplicitReferences(g1s1, g1_children, 1);
+ V8::AddObjectGroup(g2_objects, 2);
+ V8::AddImplicitReferences(g2s1, g2_children, 1);
+ V8::AddObjectGroup(g3_objects, 2);
+ V8::AddImplicitReferences(g3s1, g3_children, 1);
+ }
+ // Do a full GC
+ HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
+
+ // All object should be alive.
+ CHECK_EQ(0, NumberOfWeakCalls);
+
+ // Weaken the root.
+ root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
+
+ // Groups are deleted, rebuild groups.
+ {
+ Persistent<Value> g1_objects[] = { g1s1, g1s2 };
+ Persistent<Value> g1_children[] = { g2s1 };
+ Persistent<Value> g2_objects[] = { g2s1, g2s2 };
+ Persistent<Value> g2_children[] = { g3s1 };
+ Persistent<Value> g3_objects[] = { g3s1, g3s2 };
+ Persistent<Value> g3_children[] = { g1s1 };
+ V8::AddObjectGroup(g1_objects, 2);
+ V8::AddImplicitReferences(g1s1, g1_children, 1);
+ V8::AddObjectGroup(g2_objects, 2);
+ V8::AddImplicitReferences(g2s1, g2_children, 1);
+ V8::AddObjectGroup(g3_objects, 2);
+ V8::AddImplicitReferences(g3s1, g3_children, 1);
+ }
+
+ HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
+
+ // All objects should be gone. 7 global handles in total.
+ CHECK_EQ(7, NumberOfWeakCalls);
+}
+
+
THREADED_TEST(ScriptException) {
v8::HandleScope scope;
LocalContext env;
@@ -1900,6 +2077,10 @@ THREADED_TEST(Array) {
CHECK_EQ(1, arr->Get(0)->Int32Value());
CHECK_EQ(2, arr->Get(1)->Int32Value());
CHECK_EQ(3, arr->Get(2)->Int32Value());
+ array = v8::Array::New(27);
+ CHECK_EQ(27, array->Length());
+ array = v8::Array::New(-27);
+ CHECK_EQ(0, array->Length());
}
@@ -2082,8 +2263,6 @@ TEST(OutOfMemoryNested) {
TEST(HugeConsStringOutOfMemory) {
// It's not possible to read a snapshot into a heap with different dimensions.
if (i::Snapshot::IsEnabled()) return;
- v8::HandleScope scope;
- LocalContext context;
// Set heap limits.
static const int K = 1024;
v8::ResourceConstraints constraints;
@@ -2094,6 +2273,9 @@ TEST(HugeConsStringOutOfMemory) {
// Execute a script that causes out of memory.
v8::V8::IgnoreOutOfMemoryException();
+ v8::HandleScope scope;
+ LocalContext context;
+
// Build huge string. This should fail with out of memory exception.
Local<Value> result = CompileRun(
"var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
@@ -2513,7 +2695,7 @@ v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
if (try_catch.HasCaught()) {
CHECK_EQ(expected, count);
CHECK(result.IsEmpty());
- CHECK(!i::Top::has_scheduled_exception());
+ CHECK(!i::Isolate::Current()->has_scheduled_exception());
} else {
CHECK_NE(expected, count);
}
@@ -3688,10 +3870,8 @@ THREADED_TEST(ExtensibleOnUndetectable) {
source = v8_str("undetectable.y = 2000;");
script = Script::Compile(source);
- v8::TryCatch try_catch;
Local<Value> result = script->Run();
- CHECK(result.IsEmpty());
- CHECK(try_catch.HasCaught());
+ ExpectBoolean("undetectable.y == undefined", true);
}
@@ -4205,7 +4385,7 @@ static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
obj.Dispose();
obj.Clear();
in_scavenge = true;
- i::Heap::PerformScavenge();
+ HEAP->PerformScavenge();
in_scavenge = false;
*(reinterpret_cast<bool*>(data)) = true;
}
@@ -4242,7 +4422,7 @@ THREADED_TEST(NoWeakRefCallbacksInScavenge) {
object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
while (!object_a_disposed) {
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
}
CHECK(!released_in_scavenge);
}
@@ -4260,7 +4440,7 @@ static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
CHECK_EQ(v8::Integer::New(3), args[2]);
CHECK_EQ(v8::Undefined(), args[3]);
v8::HandleScope scope;
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
return v8::Undefined();
}
@@ -4562,130 +4742,130 @@ THREADED_TEST(StringWrite) {
memset(utf8buf, 0x1, sizeof(utf8buf));
len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
- CHECK_EQ(len, 9);
- CHECK_EQ(charlen, 5);
- CHECK_EQ(strcmp(utf8buf, "abc\303\260\342\230\203"), 0);
+ CHECK_EQ(9, len);
+ CHECK_EQ(5, charlen);
+ CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
memset(utf8buf, 0x1, sizeof(utf8buf));
len = str2->WriteUtf8(utf8buf, 8, &charlen);
- CHECK_EQ(len, 8);
- CHECK_EQ(charlen, 5);
- CHECK_EQ(strncmp(utf8buf, "abc\303\260\342\230\203\1", 9), 0);
+ CHECK_EQ(8, len);
+ CHECK_EQ(5, charlen);
+ CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
memset(utf8buf, 0x1, sizeof(utf8buf));
len = str2->WriteUtf8(utf8buf, 7, &charlen);
- CHECK_EQ(len, 5);
- CHECK_EQ(charlen, 4);
- CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
+ CHECK_EQ(5, len);
+ CHECK_EQ(4, charlen);
+ CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
memset(utf8buf, 0x1, sizeof(utf8buf));
len = str2->WriteUtf8(utf8buf, 6, &charlen);
- CHECK_EQ(len, 5);
- CHECK_EQ(charlen, 4);
- CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
+ CHECK_EQ(5, len);
+ CHECK_EQ(4, charlen);
+ CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
memset(utf8buf, 0x1, sizeof(utf8buf));
len = str2->WriteUtf8(utf8buf, 5, &charlen);
- CHECK_EQ(len, 5);
- CHECK_EQ(charlen, 4);
- CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
+ CHECK_EQ(5, len);
+ CHECK_EQ(4, charlen);
+ CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
memset(utf8buf, 0x1, sizeof(utf8buf));
len = str2->WriteUtf8(utf8buf, 4, &charlen);
- CHECK_EQ(len, 3);
- CHECK_EQ(charlen, 3);
- CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
+ CHECK_EQ(3, len);
+ CHECK_EQ(3, charlen);
+ CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
memset(utf8buf, 0x1, sizeof(utf8buf));
len = str2->WriteUtf8(utf8buf, 3, &charlen);
- CHECK_EQ(len, 3);
- CHECK_EQ(charlen, 3);
- CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
+ CHECK_EQ(3, len);
+ CHECK_EQ(3, charlen);
+ CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
memset(utf8buf, 0x1, sizeof(utf8buf));
len = str2->WriteUtf8(utf8buf, 2, &charlen);
- CHECK_EQ(len, 2);
- CHECK_EQ(charlen, 2);
- CHECK_EQ(strncmp(utf8buf, "ab\1", 3), 0);
+ CHECK_EQ(2, len);
+ CHECK_EQ(2, charlen);
+ CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
memset(buf, 0x1, sizeof(buf));
memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf);
- CHECK_EQ(len, 5);
+ CHECK_EQ(5, len);
len = str->Write(wbuf);
- CHECK_EQ(len, 5);
- CHECK_EQ(strcmp("abcde", buf), 0);
+ CHECK_EQ(5, len);
+ CHECK_EQ(0, strcmp("abcde", buf));
uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
- CHECK_EQ(StrCmp16(answer1, wbuf), 0);
+ CHECK_EQ(0, StrCmp16(answer1, wbuf));
memset(buf, 0x1, sizeof(buf));
memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 0, 4);
- CHECK_EQ(len, 4);
+ CHECK_EQ(4, len);
len = str->Write(wbuf, 0, 4);
- CHECK_EQ(len, 4);
- CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
+ CHECK_EQ(4, len);
+ CHECK_EQ(0, strncmp("abcd\1", buf, 5));
uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
- CHECK_EQ(StrNCmp16(answer2, wbuf, 5), 0);
+ CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
memset(buf, 0x1, sizeof(buf));
memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 0, 5);
- CHECK_EQ(len, 5);
+ CHECK_EQ(5, len);
len = str->Write(wbuf, 0, 5);
- CHECK_EQ(len, 5);
- CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
+ CHECK_EQ(5, len);
+ CHECK_EQ(0, strncmp("abcde\1", buf, 6));
uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
- CHECK_EQ(StrNCmp16(answer3, wbuf, 6), 0);
+ CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
memset(buf, 0x1, sizeof(buf));
memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 0, 6);
- CHECK_EQ(len, 5);
+ CHECK_EQ(5, len);
len = str->Write(wbuf, 0, 6);
- CHECK_EQ(len, 5);
- CHECK_EQ(strcmp("abcde", buf), 0);
+ CHECK_EQ(5, len);
+ CHECK_EQ(0, strcmp("abcde", buf));
uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
- CHECK_EQ(StrCmp16(answer4, wbuf), 0);
+ CHECK_EQ(0, StrCmp16(answer4, wbuf));
memset(buf, 0x1, sizeof(buf));
memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 4, -1);
- CHECK_EQ(len, 1);
+ CHECK_EQ(1, len);
len = str->Write(wbuf, 4, -1);
- CHECK_EQ(len, 1);
- CHECK_EQ(strcmp("e", buf), 0);
+ CHECK_EQ(1, len);
+ CHECK_EQ(0, strcmp("e", buf));
uint16_t answer5[] = {'e', '\0'};
- CHECK_EQ(StrCmp16(answer5, wbuf), 0);
+ CHECK_EQ(0, StrCmp16(answer5, wbuf));
memset(buf, 0x1, sizeof(buf));
memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 4, 6);
- CHECK_EQ(len, 1);
+ CHECK_EQ(1, len);
len = str->Write(wbuf, 4, 6);
- CHECK_EQ(len, 1);
- CHECK_EQ(strcmp("e", buf), 0);
- CHECK_EQ(StrCmp16(answer5, wbuf), 0);
+ CHECK_EQ(1, len);
+ CHECK_EQ(0, strcmp("e", buf));
+ CHECK_EQ(0, StrCmp16(answer5, wbuf));
memset(buf, 0x1, sizeof(buf));
memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 4, 1);
- CHECK_EQ(len, 1);
+ CHECK_EQ(1, len);
len = str->Write(wbuf, 4, 1);
- CHECK_EQ(len, 1);
- CHECK_EQ(strncmp("e\1", buf, 2), 0);
+ CHECK_EQ(1, len);
+ CHECK_EQ(0, strncmp("e\1", buf, 2));
uint16_t answer6[] = {'e', 0x101};
- CHECK_EQ(StrNCmp16(answer6, wbuf, 2), 0);
+ CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
memset(buf, 0x1, sizeof(buf));
memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 3, 1);
- CHECK_EQ(len, 1);
+ CHECK_EQ(1, len);
len = str->Write(wbuf, 3, 1);
- CHECK_EQ(len, 1);
- CHECK_EQ(strncmp("d\1", buf, 2), 0);
+ CHECK_EQ(1, len);
+ CHECK_EQ(0, strncmp("d\1", buf, 2));
uint16_t answer7[] = {'d', 0x101};
- CHECK_EQ(StrNCmp16(answer7, wbuf, 2), 0);
+ CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
}
@@ -5659,6 +5839,14 @@ TEST(AccessControlES5) {
global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
IndexedAccessBlocker);
+ // Add accessible accessor.
+ global_template->SetAccessor(
+ v8_str("accessible_prop"),
+ EchoGetter, EchoSetter,
+ v8::Handle<Value>(),
+ v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
+
+
// Add an accessor that is not accessible by cross-domain JS code.
global_template->SetAccessor(v8_str("blocked_prop"),
UnreachableGetter, UnreachableSetter,
@@ -5699,6 +5887,18 @@ TEST(AccessControlES5) {
CompileRun("Object.seal(other)");
ExpectTrue("Object.isExtensible(other)");
+
+ // Regression test for issue 1250.
+ // Make sure that we can set the accessible accessors value using normal
+ // assignment.
+ CompileRun("other.accessible_prop = 42");
+ CHECK_EQ(42, g_echo_value);
+
+ v8::Handle<Value> value;
+ // We follow Safari in ignoring assignments to host object accessors.
+ CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
+ value = CompileRun("other.accessible_prop == 42");
+ CHECK(value->IsTrue());
}
@@ -6481,7 +6681,7 @@ THREADED_TEST(SetPrototypeThrows) {
v8::TryCatch try_catch;
CHECK(!o1->SetPrototype(o0));
CHECK(!try_catch.HasCaught());
- ASSERT(!i::Top::has_pending_exception());
+ ASSERT(!i::Isolate::Current()->has_pending_exception());
CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
}
@@ -6863,7 +7063,7 @@ static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
Local<String> name,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
return v8::Handle<Value>();
}
@@ -7593,7 +7793,7 @@ static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
++(*call_count);
if ((*call_count) % 20 == 0) {
- i::Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
}
return v8::Handle<Value>();
}
@@ -7631,7 +7831,7 @@ static void GenerateSomeGarbage() {
v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
static int count = 0;
if (count++ % 3 == 0) {
- i::Heap::CollectAllGarbage(true); // This should move the stub
+ HEAP-> CollectAllGarbage(true); // This should move the stub
GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
}
return v8::Handle<v8::Value>();
@@ -7686,7 +7886,7 @@ THREADED_TEST(CallICFastApi_DirectCall_Throw) {
v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
const v8::AccessorInfo& info) {
if (++p_getter_count % 3 == 0) {
- i::Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
GenerateSomeGarbage();
}
return v8::Handle<v8::Value>();
@@ -8601,7 +8801,8 @@ void ApiTestFuzzer::Setup(PartOfTest part) {
: RegisterThreadedTest::count();
active_tests_ = tests_being_run_ = end - start;
for (int i = 0; i < tests_being_run_; i++) {
- RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
+ RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(
+ i::Isolate::Current(), i + start);
}
for (int i = 0; i < active_tests_; i++) {
RegisterThreadedTest::nth(i)->fuzzer_->Start();
@@ -8823,11 +9024,11 @@ static void CheckSurvivingGlobalObjectsCount(int expected) {
// the first garbage collection but some of the maps have already
// been marked at that point. Therefore some of the maps are not
// collected until the second garbage collection.
- i::Heap::CollectAllGarbage(false);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
int count = GetGlobalObjectsCount();
#ifdef DEBUG
- if (count != expected) i::Heap::TracePathToGlobal();
+ if (count != expected) HEAP->TracePathToGlobal();
#endif
CHECK_EQ(expected, count);
}
@@ -8893,7 +9094,7 @@ THREADED_TEST(NewPersistentHandleFromWeakCallback) {
// weak callback of the first handle would be able to 'reallocate' it.
handle1.MakeWeak(NULL, NewPersistentHandleCallback);
handle2.Dispose();
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
}
@@ -8901,7 +9102,7 @@ v8::Persistent<v8::Object> to_be_disposed;
void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
to_be_disposed.Dispose();
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
handle.Dispose();
}
@@ -8917,7 +9118,7 @@ THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
}
handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
to_be_disposed = handle2;
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
}
void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
@@ -8943,7 +9144,7 @@ THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
}
handle2.MakeWeak(NULL, DisposingCallback);
handle3.MakeWeak(NULL, HandleCreatingCallback);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
}
@@ -9189,6 +9390,31 @@ THREADED_TEST(PropertyEnumeration) {
CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
}
+THREADED_TEST(PropertyEnumeration2) {
+ v8::HandleScope scope;
+ LocalContext context;
+ v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
+ "var result = [];"
+ "result[0] = {};"
+ "result[1] = {a: 1, b: 2};"
+ "result[2] = [1, 2, 3];"
+ "var proto = {x: 1, y: 2, z: 3};"
+ "var x = { __proto__: proto, w: 0, z: 1 };"
+ "result[3] = x;"
+ "result;"))->Run();
+ v8::Handle<v8::Array> elms = obj.As<v8::Array>();
+ CHECK_EQ(4, elms->Length());
+ int elmc0 = 0;
+ const char** elmv0 = NULL;
+ CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
+
+ v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
+ v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
+ CHECK_EQ(0, props->Length());
+ for (uint32_t i = 0; i < props->Length(); i++) {
+ printf("p[%d]\n", i);
+ }
+}
static bool NamedSetAccessBlocker(Local<v8::Object> obj,
Local<Value> name,
@@ -9681,7 +9907,7 @@ class RegExpInterruptTest {
gc_during_regexp_ = 0;
regexp_success_ = false;
gc_success_ = false;
- GCThread gc_thread(this);
+ GCThread gc_thread(i::Isolate::Current(), this);
gc_thread.Start();
v8::Locker::StartPreemption(1);
@@ -9700,8 +9926,8 @@ class RegExpInterruptTest {
class GCThread : public i::Thread {
public:
- explicit GCThread(RegExpInterruptTest* test)
- : test_(test) {}
+ explicit GCThread(i::Isolate* isolate, RegExpInterruptTest* test)
+ : Thread(isolate, "GCThread"), test_(test) {}
virtual void Run() {
test_->CollectGarbage();
}
@@ -9715,7 +9941,7 @@ class RegExpInterruptTest {
{
v8::Locker lock;
// TODO(lrn): Perhaps create some garbage before collecting.
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
gc_count_++;
}
i::OS::Sleep(1);
@@ -9803,7 +10029,7 @@ class ApplyInterruptTest {
gc_during_apply_ = 0;
apply_success_ = false;
gc_success_ = false;
- GCThread gc_thread(this);
+ GCThread gc_thread(i::Isolate::Current(), this);
gc_thread.Start();
v8::Locker::StartPreemption(1);
@@ -9822,8 +10048,8 @@ class ApplyInterruptTest {
class GCThread : public i::Thread {
public:
- explicit GCThread(ApplyInterruptTest* test)
- : test_(test) {}
+ explicit GCThread(i::Isolate* isolate, ApplyInterruptTest* test)
+ : Thread(isolate, "GCThread"), test_(test) {}
virtual void Run() {
test_->CollectGarbage();
}
@@ -9836,7 +10062,7 @@ class ApplyInterruptTest {
while (gc_during_apply_ < kRequiredGCs) {
{
v8::Locker lock;
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
gc_count_++;
}
i::OS::Sleep(1);
@@ -9965,17 +10191,17 @@ static void MorphAString(i::String* string,
CHECK(i::StringShape(string).IsExternal());
if (string->IsAsciiRepresentation()) {
// Check old map is not symbol or long.
- CHECK(string->map() == i::Heap::external_ascii_string_map());
+ CHECK(string->map() == HEAP->external_ascii_string_map());
// Morph external string to be TwoByte string.
- string->set_map(i::Heap::external_string_map());
+ string->set_map(HEAP->external_string_map());
i::ExternalTwoByteString* morphed =
i::ExternalTwoByteString::cast(string);
morphed->set_resource(uc16_resource);
} else {
// Check old map is not symbol or long.
- CHECK(string->map() == i::Heap::external_string_map());
+ CHECK(string->map() == HEAP->external_string_map());
// Morph external string to be ASCII string.
- string->set_map(i::Heap::external_ascii_string_map());
+ string->set_map(HEAP->external_ascii_string_map());
i::ExternalAsciiString* morphed =
i::ExternalAsciiString::cast(string);
morphed->set_resource(ascii_resource);
@@ -9999,9 +10225,9 @@ THREADED_TEST(MorphCompositeStringTest) {
i::StrLength(c_string)));
Local<String> lhs(v8::Utils::ToLocal(
- i::Factory::NewExternalStringFromAscii(&ascii_resource)));
+ FACTORY->NewExternalStringFromAscii(&ascii_resource)));
Local<String> rhs(v8::Utils::ToLocal(
- i::Factory::NewExternalStringFromAscii(&ascii_resource)));
+ FACTORY->NewExternalStringFromAscii(&ascii_resource)));
env->Global()->Set(v8_str("lhs"), lhs);
env->Global()->Set(v8_str("rhs"), rhs);
@@ -10086,18 +10312,18 @@ class RegExpStringModificationTest {
// Create the input string for the regexp - the one we are going to change
// properties of.
- input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
+ input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
// Inject the input as a global variable.
i::Handle<i::String> input_name =
- i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
- i::Top::global_context()->global()->SetProperty(
+ FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
+ i::Isolate::Current()->global_context()->global()->SetProperty(
*input_name,
*input_,
NONE,
i::kNonStrictMode)->ToObjectChecked();
- MorphThread morph_thread(this);
+ MorphThread morph_thread(i::Isolate::Current(), this);
morph_thread.Start();
v8::Locker::StartPreemption(1);
LongRunningRegExp();
@@ -10117,8 +10343,9 @@ class RegExpStringModificationTest {
class MorphThread : public i::Thread {
public:
- explicit MorphThread(RegExpStringModificationTest* test)
- : test_(test) {}
+ explicit MorphThread(i::Isolate* isolate,
+ RegExpStringModificationTest* test)
+ : Thread(isolate, "MorphThread"), test_(test) {}
virtual void Run() {
test_->MorphString();
}
@@ -10549,13 +10776,16 @@ THREADED_TEST(PixelArray) {
LocalContext context;
const int kElementCount = 260;
uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
- i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
- pixel_data);
- i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ i::Handle<i::ExternalPixelArray> pixels =
+ i::Handle<i::ExternalPixelArray>::cast(
+ FACTORY->NewExternalArray(kElementCount,
+ v8::kExternalPixelArray,
+ pixel_data));
+ HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
for (int i = 0; i < kElementCount; i++) {
pixels->set(i, i % 256);
}
- i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
for (int i = 0; i < kElementCount; i++) {
CHECK_EQ(i % 256, pixels->get(i));
CHECK_EQ(i % 256, pixel_data[i]);
@@ -10890,7 +11120,7 @@ THREADED_TEST(PixelArray) {
" return sum; "
"}"
"for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
- "for (var i = 0; i < 10000; ++i) {"
+ "for (var i = 0; i < 5000; ++i) {"
" result = pa_load(pixels);"
"}"
"result");
@@ -10907,7 +11137,7 @@ THREADED_TEST(PixelArray) {
" }"
" return sum; "
"}"
- "for (var i = 0; i < 100000; ++i) {"
+ "for (var i = 0; i < 5000; ++i) {"
" pa_init(pixels);"
"}"
"result = pa_load(pixels);"
@@ -10955,8 +11185,11 @@ THREADED_TEST(PixelArrayWithInterceptor) {
LocalContext context;
const int kElementCount = 260;
uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
- i::Handle<i::PixelArray> pixels =
- i::Factory::NewPixelArray(kElementCount, pixel_data);
+ i::Handle<i::ExternalPixelArray> pixels =
+ i::Handle<i::ExternalPixelArray>::cast(
+ FACTORY->NewExternalArray(kElementCount,
+ v8::kExternalPixelArray,
+ pixel_data));
for (int i = 0; i < kElementCount; i++) {
pixels->set(i, i % 256);
}
@@ -10984,6 +11217,7 @@ static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
switch (array_type) {
case v8::kExternalByteArray:
case v8::kExternalUnsignedByteArray:
+ case v8::kExternalPixelArray:
return 1;
break;
case v8::kExternalShortArray:
@@ -11016,12 +11250,12 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
static_cast<ElementType*>(malloc(kElementCount * element_size));
i::Handle<ExternalArrayClass> array =
i::Handle<ExternalArrayClass>::cast(
- i::Factory::NewExternalArray(kElementCount, array_type, array_data));
- i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ FACTORY->NewExternalArray(kElementCount, array_type, array_data));
+ HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
for (int i = 0; i < kElementCount; i++) {
array->set(i, static_cast<ElementType>(i));
}
- i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
for (int i = 0; i < kElementCount; i++) {
CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
@@ -11138,7 +11372,7 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
" }"
"}"
"sum;");
- i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
CHECK_EQ(28, result->Int32Value());
// Make sure out-of-range loads do not throw.
@@ -11205,8 +11439,10 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
" ext_array[i] = Infinity;"
"}"
"ext_array[5];");
- CHECK_EQ(0, result->Int32Value());
- CHECK_EQ(0,
+ int expected_value =
+ (array_type == v8::kExternalPixelArray) ? 255 : 0;
+ CHECK_EQ(expected_value, result->Int32Value());
+ CHECK_EQ(expected_value,
i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
result = CompileRun("for (var i = 0; i < 8; i++) {"
@@ -11227,10 +11463,14 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
const char* signed_data =
"var source_data = [0.6, 10.6, -0.6, -10.6];"
"var expected_results = [0, 10, 0, -10];";
+ const char* pixel_data =
+ "var source_data = [0.6, 10.6];"
+ "var expected_results = [1, 11];";
bool is_unsigned =
(array_type == v8::kExternalUnsignedByteArray ||
array_type == v8::kExternalUnsignedShortArray ||
array_type == v8::kExternalUnsignedIntArray);
+ bool is_pixel_data = array_type == v8::kExternalPixelArray;
i::OS::SNPrintF(test_buf,
"%s"
@@ -11243,11 +11483,42 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
" (ext_array[5] == expected_results[i]);"
"}"
"all_passed;",
- (is_unsigned ? unsigned_data : signed_data));
+ (is_unsigned ?
+ unsigned_data :
+ (is_pixel_data ? pixel_data : signed_data)));
result = CompileRun(test_buf.start());
CHECK_EQ(true, result->BooleanValue());
}
+ // Test crankshaft external array loads
+ for (int i = 0; i < kElementCount; i++) {
+ array->set(i, static_cast<ElementType>(i));
+ }
+ result = CompileRun("function ee_load_test_func(sum) {"
+ " for (var i=0;i<40;++i)"
+ " sum += ext_array[i];"
+ " return sum;"
+ "}"
+ "sum=0;"
+ "for (var i=0;i<10000;++i) {"
+ " sum=ee_load_test_func(sum);"
+ "}"
+ "sum;");
+ CHECK_EQ(7800000, result->Int32Value());
+
+ // Test crankshaft external array stores
+ result = CompileRun("function ee_store_test_func(sum) {"
+ " for (var i=0;i<40;++i)"
+ " sum += ext_array[i] = i;"
+ " return sum;"
+ "}"
+ "sum=0;"
+ "for (var i=0;i<10000;++i) {"
+ " sum=ee_store_test_func(sum);"
+ "}"
+ "sum;");
+ CHECK_EQ(7800000, result->Int32Value());
+
result = CompileRun("ext_array[3] = 33;"
"delete ext_array[3];"
"ext_array[3];");
@@ -11287,7 +11558,7 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
i::Handle<ExternalArrayClass> large_array =
i::Handle<ExternalArrayClass>::cast(
- i::Factory::NewExternalArray(kLargeElementCount,
+ FACTORY->NewExternalArray(kLargeElementCount,
array_type,
array_data));
v8::Handle<v8::Object> large_obj = v8::Object::New();
@@ -11354,6 +11625,95 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
free(large_array_data);
}
+ // The "" property descriptor is overloaded to store information about
+ // the external array. Ensure that setting and accessing the "" property
+ // works (it should overwrite the information cached about the external
+ // array in the DescriptorArray) in various situations.
+ result = CompileRun("ext_array[''] = 23; ext_array['']");
+ CHECK_EQ(23, result->Int32Value());
+
+ // Property "" set after the external array is associated with the object.
+ {
+ v8::Handle<v8::Object> obj2 = v8::Object::New();
+ obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
+ obj2->Set(v8_str(""), v8::Int32::New(1503));
+ // Set the elements to be the external array.
+ obj2->SetIndexedPropertiesToExternalArrayData(array_data,
+ array_type,
+ kElementCount);
+ context->Global()->Set(v8_str("ext_array"), obj2);
+ result = CompileRun("ext_array['']");
+ CHECK_EQ(1503, result->Int32Value());
+ }
+
+ // Property "" set after the external array is associated with the object.
+ {
+ v8::Handle<v8::Object> obj2 = v8::Object::New();
+ obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
+ // Set the elements to be the external array.
+ obj2->SetIndexedPropertiesToExternalArrayData(array_data,
+ array_type,
+ kElementCount);
+ obj2->Set(v8_str(""), v8::Int32::New(1503));
+ context->Global()->Set(v8_str("ext_array"), obj2);
+ result = CompileRun("ext_array['']");
+ CHECK_EQ(1503, result->Int32Value());
+ }
+
+ // Should reuse the map from previous test.
+ {
+ v8::Handle<v8::Object> obj2 = v8::Object::New();
+ obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
+ // Set the elements to be the external array. Should re-use the map
+ // from previous test.
+ obj2->SetIndexedPropertiesToExternalArrayData(array_data,
+ array_type,
+ kElementCount);
+ context->Global()->Set(v8_str("ext_array"), obj2);
+ result = CompileRun("ext_array['']");
+ }
+
+ // Property "" is a constant function that shouldn't not be interfered with
+ // when an external array is set.
+ {
+ v8::Handle<v8::Object> obj2 = v8::Object::New();
+ // Start
+ obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
+
+ // Add a constant function to an object.
+ context->Global()->Set(v8_str("ext_array"), obj2);
+ result = CompileRun("ext_array[''] = function() {return 1503;};"
+ "ext_array['']();");
+
+ // Add an external array transition to the same map that
+ // has the constant transition.
+ v8::Handle<v8::Object> obj3 = v8::Object::New();
+ obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
+ obj3->SetIndexedPropertiesToExternalArrayData(array_data,
+ array_type,
+ kElementCount);
+ context->Global()->Set(v8_str("ext_array"), obj3);
+ }
+
+ // If a external array transition is in the map, it should get clobbered
+ // by a constant function.
+ {
+ // Add an external array transition.
+ v8::Handle<v8::Object> obj3 = v8::Object::New();
+ obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
+ obj3->SetIndexedPropertiesToExternalArrayData(array_data,
+ array_type,
+ kElementCount);
+
+ // Add a constant function to the same map that just got an external array
+ // transition.
+ v8::Handle<v8::Object> obj2 = v8::Object::New();
+ obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
+ context->Global()->Set(v8_str("ext_array"), obj2);
+ result = CompileRun("ext_array[''] = function() {return 1503;};"
+ "ext_array['']();");
+ }
+
free(array_data);
}
@@ -11374,6 +11734,14 @@ THREADED_TEST(ExternalUnsignedByteArray) {
}
+THREADED_TEST(ExternalPixelArray) {
+ ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
+ v8::kExternalPixelArray,
+ 0,
+ 255);
+}
+
+
THREADED_TEST(ExternalShortArray) {
ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
v8::kExternalShortArray,
@@ -11451,6 +11819,7 @@ THREADED_TEST(ExternalArrayInfo) {
ExternalArrayInfoTestHelper(v8::kExternalIntArray);
ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
+ ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
}
@@ -11714,7 +12083,8 @@ THREADED_TEST(IdleNotification) {
static uint32_t* stack_limit;
static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
- stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
+ stack_limit = reinterpret_cast<uint32_t*>(
+ i::Isolate::Current()->stack_guard()->real_climit());
return v8::Undefined();
}
@@ -11980,7 +12350,7 @@ TEST(Regress528) {
other_context->Enter();
CompileRun(source_simple);
other_context->Exit();
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
@@ -12002,7 +12372,7 @@ TEST(Regress528) {
other_context->Enter();
CompileRun(source_eval);
other_context->Exit();
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
@@ -12029,7 +12399,7 @@ TEST(Regress528) {
other_context->Enter();
CompileRun(source_exception);
other_context->Exit();
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
if (GetGlobalObjectsCount() == 1) break;
}
CHECK_GE(2, gc_count);
@@ -12247,26 +12617,26 @@ TEST(GCCallbacks) {
v8::V8::AddGCEpilogueCallback(EpilogueCallback);
CHECK_EQ(0, prologue_call_count);
CHECK_EQ(0, epilogue_call_count);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(1, prologue_call_count);
CHECK_EQ(1, epilogue_call_count);
v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(1, prologue_call_count_second);
CHECK_EQ(1, epilogue_call_count_second);
v8::V8::RemoveGCPrologueCallback(PrologueCallback);
v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(2, prologue_call_count_second);
CHECK_EQ(2, epilogue_call_count_second);
v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(2, prologue_call_count_second);
@@ -12294,7 +12664,7 @@ THREADED_TEST(AddToJSFunctionResultCache) {
" return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
" return 'PASSED';"
"})()";
- i::Heap::ClearJSFunctionResultCaches();
+ HEAP->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
@@ -12318,7 +12688,7 @@ THREADED_TEST(FillJSFunctionResultCache) {
" return 'FAILED: k0CacheSize is too small';"
" return 'PASSED';"
"})()";
- i::Heap::ClearJSFunctionResultCaches();
+ HEAP->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
@@ -12343,7 +12713,7 @@ THREADED_TEST(RoundRobinGetFromCache) {
" };"
" return 'PASSED';"
"})()";
- i::Heap::ClearJSFunctionResultCaches();
+ HEAP->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
@@ -12368,7 +12738,7 @@ THREADED_TEST(ReverseGetFromCache) {
" };"
" return 'PASSED';"
"})()";
- i::Heap::ClearJSFunctionResultCaches();
+ HEAP->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
@@ -12386,7 +12756,7 @@ THREADED_TEST(TestEviction) {
" };"
" return 'PASSED';"
"})()";
- i::Heap::ClearJSFunctionResultCaches();
+ HEAP->ClearJSFunctionResultCaches();
ExpectString(code, "PASSED");
}
@@ -12476,7 +12846,7 @@ THREADED_TEST(TwoByteStringInAsciiCons) {
void FailedAccessCheckCallbackGC(Local<v8::Object> target,
v8::AccessType type,
Local<v8::Value> data) {
- i::Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
}
@@ -12557,6 +12927,374 @@ TEST(GCInFailedAccessCheckCallback) {
v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
}
+TEST(DefaultIsolateGetCurrent) {
+ CHECK(v8::Isolate::GetCurrent() != NULL);
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
+ printf("*** %s\n", "DefaultIsolateGetCurrent success");
+}
+
+TEST(IsolateNewDispose) {
+ v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
+ v8::Isolate* isolate = v8::Isolate::New();
+ CHECK(isolate != NULL);
+ CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
+ CHECK(current_isolate != isolate);
+ CHECK(current_isolate == v8::Isolate::GetCurrent());
+
+ v8::V8::SetFatalErrorHandler(StoringErrorCallback);
+ last_location = last_message = NULL;
+ isolate->Dispose();
+ CHECK_EQ(last_location, NULL);
+ CHECK_EQ(last_message, NULL);
+}
+
+TEST(IsolateEnterExitDefault) {
+ v8::HandleScope scope;
+ LocalContext context;
+ v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
+ CHECK(current_isolate != NULL); // Default isolate.
+ ExpectString("'hello'", "hello");
+ current_isolate->Enter();
+ ExpectString("'still working'", "still working");
+ current_isolate->Exit();
+ ExpectString("'still working 2'", "still working 2");
+ current_isolate->Exit();
+ // Default isolate is always, well, 'default current'.
+ CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
+ // Still working since default isolate is auto-entering any thread
+ // that has no isolate and attempts to execute V8 APIs.
+ ExpectString("'still working 3'", "still working 3");
+}
+
+TEST(DisposeDefaultIsolate) {
+ v8::V8::SetFatalErrorHandler(StoringErrorCallback);
+
+ // Run some V8 code to trigger default isolate to become 'current'.
+ v8::HandleScope scope;
+ LocalContext context;
+ ExpectString("'run some V8'", "run some V8");
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
+ last_location = last_message = NULL;
+ isolate->Dispose();
+ // It is not possible to dispose default isolate via Isolate API.
+ CHECK_NE(last_location, NULL);
+ CHECK_NE(last_message, NULL);
+}
+
+TEST(RunDefaultAndAnotherIsolate) {
+ v8::HandleScope scope;
+ LocalContext context;
+
+ // Enter new isolate.
+ v8::Isolate* isolate = v8::Isolate::New();
+ CHECK(isolate);
+ isolate->Enter();
+ { // Need this block because subsequent Exit() will deallocate Heap,
+ // so we need all scope objects to be deconstructed when it happens.
+ v8::HandleScope scope_new;
+ LocalContext context_new;
+
+ // Run something in new isolate.
+ CompileRun("var foo = 153;");
+ ExpectTrue("function f() { return foo == 153; }; f()");
+ }
+ isolate->Exit();
+
+ // This runs automatically in default isolate.
+ // Variables in another isolate should be not available.
+ ExpectTrue("function f() {"
+ " try {"
+ " foo;"
+ " return false;"
+ " } catch(e) {"
+ " return true;"
+ " }"
+ "};"
+ "var bar = 371;"
+ "f()");
+
+ v8::V8::SetFatalErrorHandler(StoringErrorCallback);
+ last_location = last_message = NULL;
+ isolate->Dispose();
+ CHECK_EQ(last_location, NULL);
+ CHECK_EQ(last_message, NULL);
+
+ // Check that default isolate still runs.
+ ExpectTrue("function f() { return bar == 371; }; f()");
+}
+
+TEST(DisposeIsolateWhenInUse) {
+ v8::Isolate* isolate = v8::Isolate::New();
+ CHECK(isolate);
+ isolate->Enter();
+ v8::HandleScope scope;
+ LocalContext context;
+ // Run something in this isolate.
+ ExpectTrue("true");
+ v8::V8::SetFatalErrorHandler(StoringErrorCallback);
+ last_location = last_message = NULL;
+ // Still entered, should fail.
+ isolate->Dispose();
+ CHECK_NE(last_location, NULL);
+ CHECK_NE(last_message, NULL);
+}
+
+TEST(RunTwoIsolatesOnSingleThread) {
+ // Run isolate 1.
+ v8::Isolate* isolate1 = v8::Isolate::New();
+ isolate1->Enter();
+ v8::Persistent<v8::Context> context1 = v8::Context::New();
+
+ {
+ v8::Context::Scope cscope(context1);
+ v8::HandleScope scope;
+ // Run something in new isolate.
+ CompileRun("var foo = 'isolate 1';");
+ ExpectString("function f() { return foo; }; f()", "isolate 1");
+ }
+
+ // Run isolate 2.
+ v8::Isolate* isolate2 = v8::Isolate::New();
+ v8::Persistent<v8::Context> context2;
+
+ {
+ v8::Isolate::Scope iscope(isolate2);
+ context2 = v8::Context::New();
+ v8::Context::Scope cscope(context2);
+ v8::HandleScope scope;
+
+ // Run something in new isolate.
+ CompileRun("var foo = 'isolate 2';");
+ ExpectString("function f() { return foo; }; f()", "isolate 2");
+ }
+
+ {
+ v8::Context::Scope cscope(context1);
+ v8::HandleScope scope;
+ // Now again in isolate 1
+ ExpectString("function f() { return foo; }; f()", "isolate 1");
+ }
+
+ isolate1->Exit();
+
+ // Run some stuff in default isolate.
+ v8::Persistent<v8::Context> context_default = v8::Context::New();
+
+ {
+ v8::Context::Scope cscope(context_default);
+ v8::HandleScope scope;
+ // Variables in other isolates should be not available, verify there
+ // is an exception.
+ ExpectTrue("function f() {"
+ " try {"
+ " foo;"
+ " return false;"
+ " } catch(e) {"
+ " return true;"
+ " }"
+ "};"
+ "var isDefaultIsolate = true;"
+ "f()");
+ }
+
+ isolate1->Enter();
+
+ {
+ v8::Isolate::Scope iscope(isolate2);
+ v8::Context::Scope cscope(context2);
+ v8::HandleScope scope;
+ ExpectString("function f() { return foo; }; f()", "isolate 2");
+ }
+
+ {
+ v8::Context::Scope cscope(context1);
+ v8::HandleScope scope;
+ ExpectString("function f() { return foo; }; f()", "isolate 1");
+ }
+
+ {
+ v8::Isolate::Scope iscope(isolate2);
+ context2.Dispose();
+ }
+
+ context1.Dispose();
+ isolate1->Exit();
+
+ v8::V8::SetFatalErrorHandler(StoringErrorCallback);
+ last_location = last_message = NULL;
+
+ isolate1->Dispose();
+ CHECK_EQ(last_location, NULL);
+ CHECK_EQ(last_message, NULL);
+
+ isolate2->Dispose();
+ CHECK_EQ(last_location, NULL);
+ CHECK_EQ(last_message, NULL);
+
+ // Check that default isolate still runs.
+ {
+ v8::Context::Scope cscope(context_default);
+ v8::HandleScope scope;
+ ExpectTrue("function f() { return isDefaultIsolate; }; f()");
+ }
+}
+
+static int CalcFibonacci(v8::Isolate* isolate, int limit) {
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope scope;
+ LocalContext context;
+ i::ScopedVector<char> code(1024);
+ i::OS::SNPrintF(code, "function fib(n) {"
+ " if (n <= 2) return 1;"
+ " return fib(n-1) + fib(n-2);"
+ "}"
+ "fib(%d)", limit);
+ Local<Value> value = CompileRun(code.start());
+ CHECK(value->IsNumber());
+ return static_cast<int>(value->NumberValue());
+}
+
+class IsolateThread : public v8::internal::Thread {
+ public:
+ explicit IsolateThread(v8::Isolate* isolate, int fib_limit)
+ : Thread(NULL, "IsolateThread"),
+ isolate_(isolate),
+ fib_limit_(fib_limit),
+ result_(0) { }
+
+ void Run() {
+ result_ = CalcFibonacci(isolate_, fib_limit_);
+ }
+
+ int result() { return result_; }
+
+ private:
+ v8::Isolate* isolate_;
+ int fib_limit_;
+ int result_;
+};
+
+TEST(MultipleIsolatesOnIndividualThreads) {
+ v8::Isolate* isolate1 = v8::Isolate::New();
+ v8::Isolate* isolate2 = v8::Isolate::New();
+
+ IsolateThread thread1(isolate1, 21);
+ IsolateThread thread2(isolate2, 12);
+
+ // Compute some fibonacci numbers on 3 threads in 3 isolates.
+ thread1.Start();
+ thread2.Start();
+
+ int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
+ int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
+
+ thread1.Join();
+ thread2.Join();
+
+ // Compare results. The actual fibonacci numbers for 12 and 21 are taken
+ // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
+ CHECK_EQ(result1, 10946);
+ CHECK_EQ(result2, 144);
+ CHECK_EQ(result1, thread1.result());
+ CHECK_EQ(result2, thread2.result());
+
+ isolate1->Dispose();
+ isolate2->Dispose();
+}
+
+
+class InitDefaultIsolateThread : public v8::internal::Thread {
+ public:
+ enum TestCase {
+ IgnoreOOM,
+ SetResourceConstraints,
+ SetFatalHandler,
+ SetCounterFunction,
+ SetCreateHistogramFunction,
+ SetAddHistogramSampleFunction
+ };
+
+ explicit InitDefaultIsolateThread(TestCase testCase)
+ : Thread(NULL, "InitDefaultIsolateThread"),
+ testCase_(testCase),
+ result_(false) { }
+
+ void Run() {
+ switch (testCase_) {
+ case IgnoreOOM:
+ v8::V8::IgnoreOutOfMemoryException();
+ break;
+
+ case SetResourceConstraints: {
+ static const int K = 1024;
+ v8::ResourceConstraints constraints;
+ constraints.set_max_young_space_size(256 * K);
+ constraints.set_max_old_space_size(4 * K * K);
+ v8::SetResourceConstraints(&constraints);
+ break;
+ }
+
+ case SetFatalHandler:
+ v8::V8::SetFatalErrorHandler(NULL);
+ break;
+
+ case SetCounterFunction:
+ v8::V8::SetCounterFunction(NULL);
+ break;
+
+ case SetCreateHistogramFunction:
+ v8::V8::SetCreateHistogramFunction(NULL);
+ break;
+
+ case SetAddHistogramSampleFunction:
+ v8::V8::SetAddHistogramSampleFunction(NULL);
+ break;
+ }
+ result_ = true;
+ }
+
+ bool result() { return result_; }
+
+ private:
+ TestCase testCase_;
+ bool result_;
+};
+
+
+static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
+ InitDefaultIsolateThread thread(testCase);
+ thread.Start();
+ thread.Join();
+ CHECK_EQ(thread.result(), true);
+}
+
+TEST(InitializeDefaultIsolateOnSecondaryThread1) {
+ InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
+}
+
+TEST(InitializeDefaultIsolateOnSecondaryThread2) {
+ InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
+}
+
+TEST(InitializeDefaultIsolateOnSecondaryThread3) {
+ InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
+}
+
+TEST(InitializeDefaultIsolateOnSecondaryThread4) {
+ InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
+}
+
+TEST(InitializeDefaultIsolateOnSecondaryThread5) {
+ InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
+}
+
+TEST(InitializeDefaultIsolateOnSecondaryThread6) {
+ InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
+}
+
TEST(StringCheckMultipleContexts) {
const char* code =
@@ -12660,7 +13398,7 @@ TEST(DontDeleteCellLoadIC) {
"})()",
"ReferenceError: cell is not defined");
CompileRun("cell = \"new_second\";");
- i::Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
ExpectString("readCell()", "new_second");
ExpectString("readCell()", "new_second");
}
diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc
index 43cf580a..a91886e7 100644
--- a/test/cctest/test-assembler-arm.cc
+++ b/test/cctest/test-assembler-arm.cc
@@ -65,10 +65,10 @@ TEST(0) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
@@ -102,10 +102,10 @@ TEST(1) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
@@ -139,7 +139,7 @@ TEST(2) {
// some relocated stuff here, not executed
__ RecordComment("dead code, just testing relocations");
- __ mov(r0, Operand(Factory::true_value()));
+ __ mov(r0, Operand(FACTORY->true_value()));
__ RecordComment("dead code, just testing immediate operands");
__ mov(r0, Operand(-1));
__ mov(r0, Operand(0xFF000000));
@@ -148,10 +148,10 @@ TEST(2) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
@@ -196,10 +196,10 @@ TEST(3) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
@@ -232,6 +232,8 @@ TEST(4) {
double g;
double h;
int i;
+ double m;
+ double n;
float x;
float y;
} T;
@@ -243,7 +245,7 @@ TEST(4) {
Label L, C;
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ mov(ip, Operand(sp));
@@ -297,14 +299,22 @@ TEST(4) {
__ vabs(d0, d2);
__ vstr(d0, r4, OFFSET_OF(T, h));
+ // Test vneg.
+ __ vldr(d1, r4, OFFSET_OF(T, m));
+ __ vneg(d0, d1);
+ __ vstr(d0, r4, OFFSET_OF(T, m));
+ __ vldr(d1, r4, OFFSET_OF(T, n));
+ __ vneg(d0, d1);
+ __ vstr(d0, r4, OFFSET_OF(T, n));
+
__ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
@@ -319,12 +329,16 @@ TEST(4) {
t.g = -2718.2818;
t.h = 31415926.5;
t.i = 0;
+ t.m = -2718.2818;
+ t.n = 123.456;
t.x = 4.5;
t.y = 9.0;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(4.5, t.y);
CHECK_EQ(9.0, t.x);
+ CHECK_EQ(-123.456, t.n);
+ CHECK_EQ(2718.2818, t.m);
CHECK_EQ(2, t.i);
CHECK_EQ(2718.2818, t.g);
CHECK_EQ(31415926.5, t.h);
@@ -345,7 +359,7 @@ TEST(5) {
Assembler assm(NULL, 0);
- if (CpuFeatures::IsSupported(ARMv7)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
CpuFeatures::Scope scope(ARMv7);
// On entry, r0 = 0xAAAAAAAA = 0b10..10101010.
__ ubfx(r0, r0, 1, 12); // 0b00..010101010101 = 0x555
@@ -357,10 +371,10 @@ TEST(5) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
@@ -381,7 +395,7 @@ TEST(6) {
Assembler assm(NULL, 0);
- if (CpuFeatures::IsSupported(ARMv7)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
CpuFeatures::Scope scope(ARMv7);
__ usat(r1, 8, Operand(r0)); // Sat 0xFFFF to 0-255 = 0xFF.
__ usat(r2, 12, Operand(r0, ASR, 9)); // Sat (0xFFFF>>9) to 0-4095 = 0x7F.
@@ -392,10 +406,10 @@ TEST(6) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
@@ -424,7 +438,7 @@ static void TestRoundingMode(VCVTTypes types,
Assembler assm(NULL, 0);
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
Label wrong_exception;
@@ -468,10 +482,10 @@ static void TestRoundingMode(VCVTTypes types,
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
diff --git a/test/cctest/test-assembler-ia32.cc b/test/cctest/test-assembler-ia32.cc
index 14692ff1..694bd57b 100644
--- a/test/cctest/test-assembler-ia32.cc
+++ b/test/cctest/test-assembler-ia32.cc
@@ -69,10 +69,10 @@ TEST(AssemblerIa320) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(desc,
- Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->
- ToObjectChecked();
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef OBJECT_PRINT
Code::cast(code)->Print();
@@ -107,10 +107,10 @@ TEST(AssemblerIa321) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(desc,
- Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->
- ToObjectChecked();
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef OBJECT_PRINT
Code::cast(code)->Print();
@@ -144,16 +144,15 @@ TEST(AssemblerIa322) {
__ ret(0);
// some relocated stuff here, not executed
- __ mov(eax, Factory::true_value());
+ __ mov(eax, FACTORY->true_value());
__ jmp(NULL, RelocInfo::RUNTIME_ENTRY);
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
-
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef OBJECT_PRINT
Code::cast(code)->Print();
@@ -168,7 +167,7 @@ TEST(AssemblerIa322) {
typedef int (*F3)(float x);
TEST(AssemblerIa323) {
- if (!CpuFeatures::IsSupported(SSE2)) return;
+ if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) return;
InitializeVM();
v8::HandleScope scope;
@@ -176,7 +175,7 @@ TEST(AssemblerIa323) {
v8::internal::byte buffer[256];
Assembler assm(buffer, sizeof buffer);
- CHECK(CpuFeatures::IsSupported(SSE2));
+ CHECK(Isolate::Current()->cpu_features()->IsSupported(SSE2));
{ CpuFeatures::Scope fscope(SSE2);
__ cvttss2si(eax, Operand(esp, 4));
__ ret(0);
@@ -184,10 +183,10 @@ TEST(AssemblerIa323) {
CodeDesc desc;
assm.GetCode(&desc);
- Code* code = Code::cast(Heap::CreateCode(
+ Code* code = Code::cast(HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked());
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
// don't print the code - our disassembler can't handle cvttss2si
// instead print bytes
Disassembler::Dump(stdout,
@@ -203,7 +202,7 @@ TEST(AssemblerIa323) {
typedef int (*F4)(double x);
TEST(AssemblerIa324) {
- if (!CpuFeatures::IsSupported(SSE2)) return;
+ if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) return;
InitializeVM();
v8::HandleScope scope;
@@ -211,17 +210,17 @@ TEST(AssemblerIa324) {
v8::internal::byte buffer[256];
Assembler assm(buffer, sizeof buffer);
- CHECK(CpuFeatures::IsSupported(SSE2));
+ CHECK(Isolate::Current()->cpu_features()->IsSupported(SSE2));
CpuFeatures::Scope fscope(SSE2);
__ cvttsd2si(eax, Operand(esp, 4));
__ ret(0);
CodeDesc desc;
assm.GetCode(&desc);
- Code* code = Code::cast(Heap::CreateCode(
+ Code* code = Code::cast(HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked());
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
// don't print the code - our disassembler can't handle cvttsd2si
// instead print bytes
Disassembler::Dump(stdout,
@@ -247,10 +246,10 @@ TEST(AssemblerIa325) {
CodeDesc desc;
assm.GetCode(&desc);
- Code* code = Code::cast(Heap::CreateCode(
+ Code* code = Code::cast(HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked());
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
F0 f = FUNCTION_CAST<F0>(code->entry());
int res = f();
CHECK_EQ(42, res);
@@ -260,11 +259,11 @@ TEST(AssemblerIa325) {
typedef double (*F5)(double x, double y);
TEST(AssemblerIa326) {
- if (!CpuFeatures::IsSupported(SSE2)) return;
+ if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) return;
InitializeVM();
v8::HandleScope scope;
- CHECK(CpuFeatures::IsSupported(SSE2));
+ CHECK(Isolate::Current()->cpu_features()->IsSupported(SSE2));
CpuFeatures::Scope fscope(SSE2);
v8::internal::byte buffer[256];
Assembler assm(buffer, sizeof buffer);
@@ -284,10 +283,10 @@ TEST(AssemblerIa326) {
CodeDesc desc;
assm.GetCode(&desc);
- Code* code = Code::cast(Heap::CreateCode(
+ Code* code = Code::cast(HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked());
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
#ifdef DEBUG
::printf("\n---\n");
// don't print the code - our disassembler can't handle SSE instructions
@@ -306,11 +305,11 @@ TEST(AssemblerIa326) {
typedef double (*F6)(int x);
TEST(AssemblerIa328) {
- if (!CpuFeatures::IsSupported(SSE2)) return;
+ if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) return;
InitializeVM();
v8::HandleScope scope;
- CHECK(CpuFeatures::IsSupported(SSE2));
+ CHECK(Isolate::Current()->cpu_features()->IsSupported(SSE2));
CpuFeatures::Scope fscope(SSE2);
v8::internal::byte buffer[256];
Assembler assm(buffer, sizeof buffer);
@@ -324,10 +323,10 @@ TEST(AssemblerIa328) {
__ ret(0);
CodeDesc desc;
assm.GetCode(&desc);
- Code* code = Code::cast(Heap::CreateCode(
+ Code* code = Code::cast(HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked());
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
CHECK(code->IsCode());
#ifdef OBJECT_PRINT
Code::cast(code)->Print();
@@ -379,10 +378,10 @@ TEST(AssemblerIa329) {
CodeDesc desc;
assm.GetCode(&desc);
- Code* code = Code::cast(Heap::CreateCode(
+ Code* code = Code::cast(HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked());
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
CHECK(code->IsCode());
#ifdef OBJECT_PRINT
Code::cast(code)->Print();
diff --git a/test/cctest/test-assembler-mips.cc b/test/cctest/test-assembler-mips.cc
index ecb42e2f..8cd56f76 100644
--- a/test/cctest/test-assembler-mips.cc
+++ b/test/cctest/test-assembler-mips.cc
@@ -59,6 +59,7 @@ static void InitializeVM() {
#define __ assm.
+
TEST(MIPS0) {
InitializeVM();
v8::HandleScope scope;
@@ -72,14 +73,11 @@ TEST(MIPS0) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(desc,
- NULL,
- Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()));
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
-#ifdef DEBUG
- Code::cast(code)->Print();
-#endif
F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry());
int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 0xab0, 0xc, 0, 0, 0));
::printf("f() = %d\n", res);
@@ -100,12 +98,12 @@ TEST(MIPS1) {
__ nop();
__ bind(&L);
- __ add(v0, v0, a1);
+ __ addu(v0, v0, a1);
__ addiu(a1, a1, -1);
__ bind(&C);
__ xori(v1, a1, 0);
- __ Branch(ne, &L, v1, Operand(0, RelocInfo::NONE));
+ __ Branch(&L, ne, v1, Operand(0));
__ nop();
__ jr(ra);
@@ -113,14 +111,11 @@ TEST(MIPS1) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(desc,
- NULL,
- Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()));
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
-#ifdef DEBUG
- Code::cast(code)->Print();
-#endif
F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 50, 0, 0, 0, 0));
::printf("f() = %d\n", res);
@@ -166,62 +161,81 @@ TEST(MIPS2) {
__ srav(v0, v0, t0); // 0xff234560
__ sllv(v0, v0, t0); // 0xf2345600
__ srlv(v0, v0, t0); // 0x0f234560
- __ Branch(ne, &error, v0, Operand(0x0f234560));
+ __ Branch(&error, ne, v0, Operand(0x0f234560));
__ nop();
- __ add(v0, t0, t1); // 0x00001238
- __ sub(v0, v0, t0); // 0x00001234
- __ Branch(ne, &error, v0, Operand(0x00001234));
+ __ addu(v0, t0, t1); // 0x00001238
+ __ subu(v0, v0, t0); // 0x00001234
+ __ Branch(&error, ne, v0, Operand(0x00001234));
__ nop();
__ addu(v1, t3, t0);
- __ Branch(ne, &error, v1, Operand(0x80000003));
+ __ Branch(&error, ne, v1, Operand(0x80000003));
__ nop();
__ subu(v1, t7, t0); // 0x7ffffffc
- __ Branch(ne, &error, v1, Operand(0x7ffffffc));
+ __ Branch(&error, ne, v1, Operand(0x7ffffffc));
__ nop();
__ and_(v0, t1, t2); // 0x00001230
__ or_(v0, v0, t1); // 0x00001234
__ xor_(v0, v0, t2); // 0x1234444c
__ nor(v0, v0, t2); // 0xedcba987
- __ Branch(ne, &error, v0, Operand(0xedcba983));
+ __ Branch(&error, ne, v0, Operand(0xedcba983));
__ nop();
__ slt(v0, t7, t3);
- __ Branch(ne, &error, v0, Operand(0x1));
+ __ Branch(&error, ne, v0, Operand(0x1));
__ nop();
__ sltu(v0, t7, t3);
- __ Branch(ne, &error, v0, Operand(0x0));
+ __ Branch(&error, ne, v0, Operand(0x0));
__ nop();
// End of SPECIAL class.
- __ addi(v0, zero_reg, 0x7421); // 0x00007421
- __ addi(v0, v0, -0x1); // 0x00007420
+ __ addiu(v0, zero_reg, 0x7421); // 0x00007421
+ __ addiu(v0, v0, -0x1); // 0x00007420
__ addiu(v0, v0, -0x20); // 0x00007400
- __ Branch(ne, &error, v0, Operand(0x00007400));
+ __ Branch(&error, ne, v0, Operand(0x00007400));
__ nop();
__ addiu(v1, t3, 0x1); // 0x80000000
- __ Branch(ne, &error, v1, Operand(0x80000000));
+ __ Branch(&error, ne, v1, Operand(0x80000000));
__ nop();
__ slti(v0, t1, 0x00002000); // 0x1
__ slti(v0, v0, 0xffff8000); // 0x0
- __ Branch(ne, &error, v0, Operand(0x0));
+ __ Branch(&error, ne, v0, Operand(0x0));
__ nop();
__ sltiu(v0, t1, 0x00002000); // 0x1
__ sltiu(v0, v0, 0x00008000); // 0x1
- __ Branch(ne, &error, v0, Operand(0x1));
+ __ Branch(&error, ne, v0, Operand(0x1));
__ nop();
__ andi(v0, t1, 0xf0f0); // 0x00001030
__ ori(v0, v0, 0x8a00); // 0x00009a30
__ xori(v0, v0, 0x83cc); // 0x000019fc
- __ Branch(ne, &error, v0, Operand(0x000019fc));
+ __ Branch(&error, ne, v0, Operand(0x000019fc));
__ nop();
__ lui(v1, 0x8123); // 0x81230000
- __ Branch(ne, &error, v1, Operand(0x81230000));
+ __ Branch(&error, ne, v1, Operand(0x81230000));
__ nop();
+ // Bit twiddling instructions & conditional moves.
+ // Uses t0-t7 as set above.
+ __ clz(v0, t0); // 29
+ __ clz(v1, t1); // 19
+ __ addu(v0, v0, v1); // 48
+ __ clz(v1, t2); // 3
+ __ addu(v0, v0, v1); // 51
+ __ clz(v1, t7); // 0
+ __ addu(v0, v0, v1); // 51
+ __ Branch(&error, ne, v0, Operand(51));
+ __ movn(a0, t3, t0); // Move a0<-t3 (t0 is NOT 0).
+ __ Ins(a0, t1, 12, 8); // 0x7ff34fff
+ __ Branch(&error, ne, a0, Operand(0x7ff34fff));
+ __ movz(a0, t6, t7); // a0 not updated (t7 is NOT 0).
+ __ Ext(a1, a0, 8, 12); // 0x34f
+ __ Branch(&error, ne, a1, Operand(0x34f));
+ __ movz(a0, t6, v1); // a0<-t6, v0 is 0, from 8 instr back.
+ __ Branch(&error, ne, a0, Operand(t6));
+
// Everything was correctly executed. Load the expected result.
__ li(v0, 0x31415926);
__ b(&exit);
@@ -229,6 +243,7 @@ TEST(MIPS2) {
__ bind(&error);
// Got an error. Return a wrong result.
+ __ li(v0, 666);
__ bind(&exit);
__ jr(ra);
@@ -236,18 +251,1061 @@ TEST(MIPS2) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(desc,
- NULL,
- Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()));
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
-#ifdef DEBUG
- Code::cast(code)->Print();
-#endif
F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry());
int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 0xab0, 0xc, 0, 0, 0));
::printf("f() = %d\n", res);
CHECK_EQ(0x31415926, res);
}
+
+TEST(MIPS3) {
+ // Test floating point instructions.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ double g;
+ } T;
+ T t;
+
+ // Create a function that accepts &t, and loads, manipulates, and stores
+ // the doubles t.a ... t.f.
+ MacroAssembler assm(NULL, 0);
+ Label L, C;
+
+ if (Isolate::Current()->cpu_features()->IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+
+ __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+ __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
+ __ add_d(f8, f4, f6);
+ __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, c)) ); // c = a + b.
+
+ __ mov_d(f10, f8); // c
+ __ neg_d(f12, f6); // -b
+ __ sub_d(f10, f10, f12);
+ __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, d)) ); // d = c - (-b).
+
+ __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, b)) ); // b = a.
+
+ __ li(t0, 120);
+ __ mtc1(t0, f14);
+ __ cvt_d_w(f14, f14); // f14 = 120.0.
+ __ mul_d(f10, f10, f14);
+ __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, e)) ); // e = d * 120 = 1.8066e16.
+
+ __ div_d(f12, f10, f4);
+ __ sdc1(f12, MemOperand(a0, OFFSET_OF(T, f)) ); // f = e / a = 120.44.
+
+ __ sqrt_d(f14, f12);
+ __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) );
+ // g = sqrt(f) = 10.97451593465515908537
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ t.a = 1.5e14;
+ t.b = 2.75e11;
+ t.c = 0.0;
+ t.d = 0.0;
+ t.e = 0.0;
+ t.f = 0.0;
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+ CHECK_EQ(1.5e14, t.a);
+ CHECK_EQ(1.5e14, t.b);
+ CHECK_EQ(1.50275e14, t.c);
+ CHECK_EQ(1.50550e14, t.d);
+ CHECK_EQ(1.8066e16, t.e);
+ CHECK_EQ(120.44, t.f);
+ CHECK_EQ(10.97451593465515908537, t.g);
+ }
+}
+
+
+TEST(MIPS4) {
+ // Test moves between floating point and integer registers.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ double a;
+ double b;
+ double c;
+ } T;
+ T t;
+
+ Assembler assm(NULL, 0);
+ Label L, C;
+
+ if (Isolate::Current()->cpu_features()->IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+
+ __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+ __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
+
+ // Swap f4 and f6, by using four integer registers, t0-t3.
+ __ mfc1(t0, f4);
+ __ mfc1(t1, f5);
+ __ mfc1(t2, f6);
+ __ mfc1(t3, f7);
+
+ __ mtc1(t0, f6);
+ __ mtc1(t1, f7);
+ __ mtc1(t2, f4);
+ __ mtc1(t3, f5);
+
+ // Store the swapped f4 and f5 back to memory.
+ __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+ __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, c)) );
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ t.a = 1.5e22;
+ t.b = 2.75e11;
+ t.c = 17.17;
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(2.75e11, t.a);
+ CHECK_EQ(2.75e11, t.b);
+ CHECK_EQ(1.5e22, t.c);
+ }
+}
+
+
+TEST(MIPS5) {
+ // Test conversions between doubles and integers.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ double a;
+ double b;
+ int i;
+ int j;
+ } T;
+ T t;
+
+ Assembler assm(NULL, 0);
+ Label L, C;
+
+ if (Isolate::Current()->cpu_features()->IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+
+ // Load all structure elements to registers.
+ __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+ __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, i)) );
+ __ lw(t1, MemOperand(a0, OFFSET_OF(T, j)) );
+
+ // Convert double in f4 to int in element i.
+ __ cvt_w_d(f8, f4);
+ __ mfc1(t2, f8);
+ __ sw(t2, MemOperand(a0, OFFSET_OF(T, i)) );
+
+ // Convert double in f6 to int in element j.
+ __ cvt_w_d(f10, f6);
+ __ mfc1(t3, f10);
+ __ sw(t3, MemOperand(a0, OFFSET_OF(T, j)) );
+
+ // Convert int in original i (t0) to double in a.
+ __ mtc1(t0, f12);
+ __ cvt_d_w(f0, f12);
+ __ sdc1(f0, MemOperand(a0, OFFSET_OF(T, a)) );
+
+ // Convert int in original j (t1) to double in b.
+ __ mtc1(t1, f14);
+ __ cvt_d_w(f2, f14);
+ __ sdc1(f2, MemOperand(a0, OFFSET_OF(T, b)) );
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ t.a = 1.5e4;
+ t.b = 2.75e8;
+ t.i = 12345678;
+ t.j = -100000;
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(12345678.0, t.a);
+ CHECK_EQ(-100000.0, t.b);
+ CHECK_EQ(15000, t.i);
+ CHECK_EQ(275000000, t.j);
+ }
+}
+
+
+TEST(MIPS6) {
+ // Test simple memory loads and stores.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ uint32_t ui;
+ int32_t si;
+ int32_t r1;
+ int32_t r2;
+ int32_t r3;
+ int32_t r4;
+ int32_t r5;
+ int32_t r6;
+ } T;
+ T t;
+
+ Assembler assm(NULL, 0);
+ Label L, C;
+
+ // Basic word load/store.
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, ui)) );
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, r1)) );
+
+ // lh with positive data.
+ __ lh(t1, MemOperand(a0, OFFSET_OF(T, ui)) );
+ __ sw(t1, MemOperand(a0, OFFSET_OF(T, r2)) );
+
+ // lh with negative data.
+ __ lh(t2, MemOperand(a0, OFFSET_OF(T, si)) );
+ __ sw(t2, MemOperand(a0, OFFSET_OF(T, r3)) );
+
+ // lhu with negative data.
+ __ lhu(t3, MemOperand(a0, OFFSET_OF(T, si)) );
+ __ sw(t3, MemOperand(a0, OFFSET_OF(T, r4)) );
+
+ // lb with negative data.
+ __ lb(t4, MemOperand(a0, OFFSET_OF(T, si)) );
+ __ sw(t4, MemOperand(a0, OFFSET_OF(T, r5)) );
+
+ // sh writes only 1/2 of word.
+ __ lui(t5, 0x3333);
+ __ ori(t5, t5, 0x3333);
+ __ sw(t5, MemOperand(a0, OFFSET_OF(T, r6)) );
+ __ lhu(t5, MemOperand(a0, OFFSET_OF(T, si)) );
+ __ sh(t5, MemOperand(a0, OFFSET_OF(T, r6)) );
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ t.ui = 0x11223344;
+ t.si = 0x99aabbcc;
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(0x11223344, t.r1);
+ CHECK_EQ(0x3344, t.r2);
+ CHECK_EQ(0xffffbbcc, t.r3);
+ CHECK_EQ(0x0000bbcc, t.r4);
+ CHECK_EQ(0xffffffcc, t.r5);
+ CHECK_EQ(0x3333bbcc, t.r6);
+}
+
+
+TEST(MIPS7) {
+ // Test floating point compare and branch instructions.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ int32_t result;
+ } T;
+ T t;
+
+ // Create a function that accepts &t, and loads, manipulates, and stores
+ // the doubles t.a ... t.f.
+ MacroAssembler assm(NULL, 0);
+ Label neither_is_nan, less_than, outa_here;
+
+ if (Isolate::Current()->cpu_features()->IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+
+ __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+ __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
+ __ c(UN, D, f4, f6);
+ __ bc1f(&neither_is_nan);
+ __ nop();
+ __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
+ __ Branch(&outa_here);
+
+ __ bind(&neither_is_nan);
+
+ __ c(OLT, D, f6, f4, 2);
+ __ bc1t(&less_than, 2);
+ __ nop();
+ __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
+ __ Branch(&outa_here);
+
+ __ bind(&less_than);
+ __ Addu(t0, zero_reg, Operand(1));
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, result)) ); // Set true.
+
+
+ // This test-case should have additional tests.
+
+ __ bind(&outa_here);
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ t.a = 1.5e14;
+ t.b = 2.75e11;
+ t.c = 2.0;
+ t.d = -4.0;
+ t.e = 0.0;
+ t.f = 0.0;
+ t.result = 0;
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+ CHECK_EQ(1.5e14, t.a);
+ CHECK_EQ(2.75e11, t.b);
+ CHECK_EQ(1, t.result);
+ }
+}
+
+
+TEST(MIPS8) {
+ // Test ROTR and ROTRV instructions.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ int32_t input;
+ int32_t result_rotr_4;
+ int32_t result_rotr_8;
+ int32_t result_rotr_12;
+ int32_t result_rotr_16;
+ int32_t result_rotr_20;
+ int32_t result_rotr_24;
+ int32_t result_rotr_28;
+ int32_t result_rotrv_4;
+ int32_t result_rotrv_8;
+ int32_t result_rotrv_12;
+ int32_t result_rotrv_16;
+ int32_t result_rotrv_20;
+ int32_t result_rotrv_24;
+ int32_t result_rotrv_28;
+ } T;
+ T t;
+
+ MacroAssembler assm(NULL, 0);
+
+ // Basic word load.
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, input)) );
+
+ // ROTR instruction (called through the Ror macro).
+ __ Ror(t1, t0, 0x0004);
+ __ Ror(t2, t0, 0x0008);
+ __ Ror(t3, t0, 0x000c);
+ __ Ror(t4, t0, 0x0010);
+ __ Ror(t5, t0, 0x0014);
+ __ Ror(t6, t0, 0x0018);
+ __ Ror(t7, t0, 0x001c);
+
+ // Basic word store.
+ __ sw(t1, MemOperand(a0, OFFSET_OF(T, result_rotr_4)) );
+ __ sw(t2, MemOperand(a0, OFFSET_OF(T, result_rotr_8)) );
+ __ sw(t3, MemOperand(a0, OFFSET_OF(T, result_rotr_12)) );
+ __ sw(t4, MemOperand(a0, OFFSET_OF(T, result_rotr_16)) );
+ __ sw(t5, MemOperand(a0, OFFSET_OF(T, result_rotr_20)) );
+ __ sw(t6, MemOperand(a0, OFFSET_OF(T, result_rotr_24)) );
+ __ sw(t7, MemOperand(a0, OFFSET_OF(T, result_rotr_28)) );
+
+ // ROTRV instruction (called through the Ror macro).
+ __ li(t7, 0x0004);
+ __ Ror(t1, t0, t7);
+ __ li(t7, 0x0008);
+ __ Ror(t2, t0, t7);
+ __ li(t7, 0x000C);
+ __ Ror(t3, t0, t7);
+ __ li(t7, 0x0010);
+ __ Ror(t4, t0, t7);
+ __ li(t7, 0x0014);
+ __ Ror(t5, t0, t7);
+ __ li(t7, 0x0018);
+ __ Ror(t6, t0, t7);
+ __ li(t7, 0x001C);
+ __ Ror(t7, t0, t7);
+
+ // Basic word store.
+ __ sw(t1, MemOperand(a0, OFFSET_OF(T, result_rotrv_4)) );
+ __ sw(t2, MemOperand(a0, OFFSET_OF(T, result_rotrv_8)) );
+ __ sw(t3, MemOperand(a0, OFFSET_OF(T, result_rotrv_12)) );
+ __ sw(t4, MemOperand(a0, OFFSET_OF(T, result_rotrv_16)) );
+ __ sw(t5, MemOperand(a0, OFFSET_OF(T, result_rotrv_20)) );
+ __ sw(t6, MemOperand(a0, OFFSET_OF(T, result_rotrv_24)) );
+ __ sw(t7, MemOperand(a0, OFFSET_OF(T, result_rotrv_28)) );
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ t.input = 0x12345678;
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0x0, 0, 0, 0);
+ USE(dummy);
+ CHECK_EQ(0x81234567, t.result_rotr_4);
+ CHECK_EQ(0x78123456, t.result_rotr_8);
+ CHECK_EQ(0x67812345, t.result_rotr_12);
+ CHECK_EQ(0x56781234, t.result_rotr_16);
+ CHECK_EQ(0x45678123, t.result_rotr_20);
+ CHECK_EQ(0x34567812, t.result_rotr_24);
+ CHECK_EQ(0x23456781, t.result_rotr_28);
+
+ CHECK_EQ(0x81234567, t.result_rotrv_4);
+ CHECK_EQ(0x78123456, t.result_rotrv_8);
+ CHECK_EQ(0x67812345, t.result_rotrv_12);
+ CHECK_EQ(0x56781234, t.result_rotrv_16);
+ CHECK_EQ(0x45678123, t.result_rotrv_20);
+ CHECK_EQ(0x34567812, t.result_rotrv_24);
+ CHECK_EQ(0x23456781, t.result_rotrv_28);
+}
+
+
+TEST(MIPS9) {
+ // Test BRANCH improvements.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ MacroAssembler assm(NULL, 0);
+ Label exit, exit2, exit3;
+
+ __ Branch(&exit, ge, a0, Operand(0x00000000));
+ __ Branch(&exit2, ge, a0, Operand(0x00001FFF));
+ __ Branch(&exit3, ge, a0, Operand(0x0001FFFF));
+
+ __ bind(&exit);
+ __ bind(&exit2);
+ __ bind(&exit3);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+}
+
+
+TEST(MIPS10) {
+ // Test conversions between doubles and long integers.
+ // Test hos the long ints map to FP regs pairs.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ double a;
+ double b;
+ int32_t dbl_mant;
+ int32_t dbl_exp;
+ int32_t long_hi;
+ int32_t long_lo;
+ int32_t b_long_hi;
+ int32_t b_long_lo;
+ } T;
+ T t;
+
+ Assembler assm(NULL, 0);
+ Label L, C;
+
+ if (Isolate::Current()->cpu_features()->IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+
+ // Load all structure elements to registers.
+ __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, a)));
+
+ // Save the raw bits of the double.
+ __ mfc1(t0, f0);
+ __ mfc1(t1, f1);
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, dbl_mant)));
+ __ sw(t1, MemOperand(a0, OFFSET_OF(T, dbl_exp)));
+
+ // Convert double in f0 to long, save hi/lo parts.
+ __ cvt_l_d(f0, f0);
+ __ mfc1(t0, f0); // f0 has LS 32 bits of long.
+ __ mfc1(t1, f1); // f1 has MS 32 bits of long.
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, long_lo)));
+ __ sw(t1, MemOperand(a0, OFFSET_OF(T, long_hi)));
+
+ // Convert the b long integers to double b.
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, b_long_lo)));
+ __ lw(t1, MemOperand(a0, OFFSET_OF(T, b_long_hi)));
+ __ mtc1(t0, f8); // f8 has LS 32-bits.
+ __ mtc1(t1, f9); // f9 has MS 32-bits.
+ __ cvt_d_l(f10, f8);
+ __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, b)));
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ t.a = 2.147483647e9; // 0x7fffffff -> 0x41DFFFFFFFC00000 as double.
+ t.b_long_hi = 0x000000ff; // 0xFF00FF00FF -> 0x426FE01FE01FE000 as double.
+ t.b_long_lo = 0x00ff00ff;
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(0x41DFFFFF, t.dbl_exp);
+ CHECK_EQ(0xFFC00000, t.dbl_mant);
+ CHECK_EQ(0, t.long_hi);
+ CHECK_EQ(0x7fffffff, t.long_lo);
+ // 0xFF00FF00FF -> 1.095233372415e12.
+ CHECK_EQ(1.095233372415e12, t.b);
+ }
+}
+
+
+TEST(MIPS11) {
+ // Test LWL, LWR, SWL and SWR instructions.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ int32_t reg_init;
+ int32_t mem_init;
+ int32_t lwl_0;
+ int32_t lwl_1;
+ int32_t lwl_2;
+ int32_t lwl_3;
+ int32_t lwr_0;
+ int32_t lwr_1;
+ int32_t lwr_2;
+ int32_t lwr_3;
+ int32_t swl_0;
+ int32_t swl_1;
+ int32_t swl_2;
+ int32_t swl_3;
+ int32_t swr_0;
+ int32_t swr_1;
+ int32_t swr_2;
+ int32_t swr_3;
+ } T;
+ T t;
+
+ Assembler assm(NULL, 0);
+
+ // Test all combinations of LWL and vAddr.
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ lwl(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, lwl_0)) );
+
+ __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ lwl(t1, MemOperand(a0, OFFSET_OF(T, mem_init) + 1) );
+ __ sw(t1, MemOperand(a0, OFFSET_OF(T, lwl_1)) );
+
+ __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ lwl(t2, MemOperand(a0, OFFSET_OF(T, mem_init) + 2) );
+ __ sw(t2, MemOperand(a0, OFFSET_OF(T, lwl_2)) );
+
+ __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ lwl(t3, MemOperand(a0, OFFSET_OF(T, mem_init) + 3) );
+ __ sw(t3, MemOperand(a0, OFFSET_OF(T, lwl_3)) );
+
+ // Test all combinations of LWR and vAddr.
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ lwr(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, lwr_0)) );
+
+ __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ lwr(t1, MemOperand(a0, OFFSET_OF(T, mem_init) + 1) );
+ __ sw(t1, MemOperand(a0, OFFSET_OF(T, lwr_1)) );
+
+ __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ lwr(t2, MemOperand(a0, OFFSET_OF(T, mem_init) + 2) );
+ __ sw(t2, MemOperand(a0, OFFSET_OF(T, lwr_2)) );
+
+ __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ lwr(t3, MemOperand(a0, OFFSET_OF(T, mem_init) + 3) );
+ __ sw(t3, MemOperand(a0, OFFSET_OF(T, lwr_3)) );
+
+ // Test all combinations of SWL and vAddr.
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, swl_0)) );
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ swl(t0, MemOperand(a0, OFFSET_OF(T, swl_0)) );
+
+ __ lw(t1, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t1, MemOperand(a0, OFFSET_OF(T, swl_1)) );
+ __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ swl(t1, MemOperand(a0, OFFSET_OF(T, swl_1) + 1) );
+
+ __ lw(t2, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t2, MemOperand(a0, OFFSET_OF(T, swl_2)) );
+ __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ swl(t2, MemOperand(a0, OFFSET_OF(T, swl_2) + 2) );
+
+ __ lw(t3, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t3, MemOperand(a0, OFFSET_OF(T, swl_3)) );
+ __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ swl(t3, MemOperand(a0, OFFSET_OF(T, swl_3) + 3) );
+
+ // Test all combinations of SWR and vAddr.
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, swr_0)) );
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ swr(t0, MemOperand(a0, OFFSET_OF(T, swr_0)) );
+
+ __ lw(t1, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t1, MemOperand(a0, OFFSET_OF(T, swr_1)) );
+ __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ swr(t1, MemOperand(a0, OFFSET_OF(T, swr_1) + 1) );
+
+ __ lw(t2, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t2, MemOperand(a0, OFFSET_OF(T, swr_2)) );
+ __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ swr(t2, MemOperand(a0, OFFSET_OF(T, swr_2) + 2) );
+
+ __ lw(t3, MemOperand(a0, OFFSET_OF(T, mem_init)) );
+ __ sw(t3, MemOperand(a0, OFFSET_OF(T, swr_3)) );
+ __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) );
+ __ swr(t3, MemOperand(a0, OFFSET_OF(T, swr_3) + 3) );
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ t.reg_init = 0xaabbccdd;
+ t.mem_init = 0x11223344;
+
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(0x44bbccdd, t.lwl_0);
+ CHECK_EQ(0x3344ccdd, t.lwl_1);
+ CHECK_EQ(0x223344dd, t.lwl_2);
+ CHECK_EQ(0x11223344, t.lwl_3);
+
+ CHECK_EQ(0x11223344, t.lwr_0);
+ CHECK_EQ(0xaa112233, t.lwr_1);
+ CHECK_EQ(0xaabb1122, t.lwr_2);
+ CHECK_EQ(0xaabbcc11, t.lwr_3);
+
+ CHECK_EQ(0x112233aa, t.swl_0);
+ CHECK_EQ(0x1122aabb, t.swl_1);
+ CHECK_EQ(0x11aabbcc, t.swl_2);
+ CHECK_EQ(0xaabbccdd, t.swl_3);
+
+ CHECK_EQ(0xaabbccdd, t.swr_0);
+ CHECK_EQ(0xbbccdd44, t.swr_1);
+ CHECK_EQ(0xccdd3344, t.swr_2);
+ CHECK_EQ(0xdd223344, t.swr_3);
+}
+
+
+TEST(MIPS12) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ int32_t x;
+ int32_t y;
+ int32_t y1;
+ int32_t y2;
+ int32_t y3;
+ int32_t y4;
+ } T;
+ T t;
+
+ MacroAssembler assm(NULL, 0);
+
+ __ mov(t6, fp); // Save frame pointer.
+ __ mov(fp, a0); // Access struct T by fp.
+ __ lw(t0, MemOperand(a0, OFFSET_OF(T, y)) );
+ __ lw(t3, MemOperand(a0, OFFSET_OF(T, y4)) );
+
+ __ addu(t1, t0, t3);
+ __ subu(t4, t0, t3);
+ __ nop();
+ __ Push(t0); // These instructions disappear after opt.
+ __ Pop();
+ __ addu(t0, t0, t0);
+ __ nop();
+ __ Pop(); // These instructions disappear after opt.
+ __ Push(t3);
+ __ nop();
+ __ Push(t3); // These instructions disappear after opt.
+ __ Pop(t3);
+ __ nop();
+ __ Push(t3);
+ __ Pop(t4);
+ __ nop();
+ __ sw(t0, MemOperand(fp, OFFSET_OF(T, y)) );
+ __ lw(t0, MemOperand(fp, OFFSET_OF(T, y)) );
+ __ nop();
+ __ sw(t0, MemOperand(fp, OFFSET_OF(T, y)) );
+ __ lw(t1, MemOperand(fp, OFFSET_OF(T, y)) );
+ __ nop();
+ __ Push(t1);
+ __ lw(t1, MemOperand(fp, OFFSET_OF(T, y)) );
+ __ Pop(t1);
+ __ nop();
+ __ Push(t1);
+ __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) );
+ __ Pop(t1);
+ __ nop();
+ __ Push(t1);
+ __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) );
+ __ Pop(t2);
+ __ nop();
+ __ Push(t2);
+ __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) );
+ __ Pop(t1);
+ __ nop();
+ __ Push(t1);
+ __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) );
+ __ Pop(t3);
+ __ nop();
+
+ __ mov(fp, t6);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ t.x = 1;
+ t.y = 2;
+ t.y1 = 3;
+ t.y2 = 4;
+ t.y3 = 0XBABA;
+ t.y4 = 0xDEDA;
+
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(3, t.y1);
+}
+
+
+TEST(MIPS13) {
+ // Test Cvt_d_uw and Trunc_uw_d macros.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ double cvt_big_out;
+ double cvt_small_out;
+ uint32_t trunc_big_out;
+ uint32_t trunc_small_out;
+ uint32_t cvt_big_in;
+ uint32_t cvt_small_in;
+ } T;
+ T t;
+
+ MacroAssembler assm(NULL, 0);
+
+ if (Isolate::Current()->cpu_features()->IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_small_in)));
+ __ Cvt_d_uw(f10, t0);
+ __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, cvt_small_out)));
+
+ __ Trunc_uw_d(f10, f10);
+ __ swc1(f10, MemOperand(a0, OFFSET_OF(T, trunc_small_out)));
+
+ __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_big_in)));
+ __ Cvt_d_uw(f8, t0);
+ __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, cvt_big_out)));
+
+ __ Trunc_uw_d(f8, f8);
+ __ swc1(f8, MemOperand(a0, OFFSET_OF(T, trunc_big_out)));
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+
+ t.cvt_big_in = 0xFFFFFFFF;
+ t.cvt_small_in = 333;
+
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(t.cvt_big_out, static_cast<double>(t.cvt_big_in));
+ CHECK_EQ(t.cvt_small_out, static_cast<double>(t.cvt_small_in));
+
+ CHECK_EQ(static_cast<int>(t.trunc_big_out), static_cast<int>(t.cvt_big_in));
+ CHECK_EQ(static_cast<int>(t.trunc_small_out),
+ static_cast<int>(t.cvt_small_in));
+ }
+}
+
+
+TEST(MIPS14) {
+ // Test round, floor, ceil, trunc, cvt.
+ InitializeVM();
+ v8::HandleScope scope;
+
+#define ROUND_STRUCT_ELEMENT(x) \
+ int32_t x##_up_out; \
+ int32_t x##_down_out; \
+ int32_t neg_##x##_up_out; \
+ int32_t neg_##x##_down_out; \
+ int32_t x##_err1_out; \
+ int32_t x##_err2_out; \
+ int32_t x##_err3_out; \
+ int32_t x##_err4_out; \
+ int32_t x##_invalid_result;
+
+ typedef struct {
+ double round_up_in;
+ double round_down_in;
+ double neg_round_up_in;
+ double neg_round_down_in;
+ double err1_in;
+ double err2_in;
+ double err3_in;
+ double err4_in;
+
+ ROUND_STRUCT_ELEMENT(round)
+ ROUND_STRUCT_ELEMENT(floor)
+ ROUND_STRUCT_ELEMENT(ceil)
+ ROUND_STRUCT_ELEMENT(trunc)
+ ROUND_STRUCT_ELEMENT(cvt)
+ } T;
+ T t;
+
+#undef ROUND_STRUCT_ELEMENT
+
+ MacroAssembler assm(NULL, 0);
+
+ if (Isolate::Current()->cpu_features()->IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+
+ // Save FCSR.
+ __ cfc1(a1, FCSR);
+ // Disable FPU exceptions.
+ __ ctc1(zero_reg, FCSR);
+#define RUN_ROUND_TEST(x) \
+ __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_up_in))); \
+ __ x##_w_d(f0, f0); \
+ __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_up_out))); \
+ \
+ __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_down_in))); \
+ __ x##_w_d(f0, f0); \
+ __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_down_out))); \
+ \
+ __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_up_in))); \
+ __ x##_w_d(f0, f0); \
+ __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_up_out))); \
+ \
+ __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_down_in))); \
+ __ x##_w_d(f0, f0); \
+ __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_down_out))); \
+ \
+ __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err1_in))); \
+ __ ctc1(zero_reg, FCSR); \
+ __ x##_w_d(f0, f0); \
+ __ cfc1(a2, FCSR); \
+ __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err1_out))); \
+ \
+ __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err2_in))); \
+ __ ctc1(zero_reg, FCSR); \
+ __ x##_w_d(f0, f0); \
+ __ cfc1(a2, FCSR); \
+ __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err2_out))); \
+ \
+ __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err3_in))); \
+ __ ctc1(zero_reg, FCSR); \
+ __ x##_w_d(f0, f0); \
+ __ cfc1(a2, FCSR); \
+ __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err3_out))); \
+ \
+ __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err4_in))); \
+ __ ctc1(zero_reg, FCSR); \
+ __ x##_w_d(f0, f0); \
+ __ cfc1(a2, FCSR); \
+ __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err4_out))); \
+ __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_invalid_result)));
+
+ RUN_ROUND_TEST(round)
+ RUN_ROUND_TEST(floor)
+ RUN_ROUND_TEST(ceil)
+ RUN_ROUND_TEST(trunc)
+ RUN_ROUND_TEST(cvt)
+
+ // Restore FCSR.
+ __ ctc1(a1, FCSR);
+
+#undef RUN_ROUND_TEST
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+
+ t.round_up_in = 123.51;
+ t.round_down_in = 123.49;
+ t.neg_round_up_in = -123.5;
+ t.neg_round_down_in = -123.49;
+ t.err1_in = 123.51;
+ t.err2_in = 1;
+ t.err3_in = static_cast<double>(1) + 0xFFFFFFFF;
+ t.err4_in = NAN;
+
+ Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+ USE(dummy);
+
+#define GET_FPU_ERR(x) ((x >> 2) & (32 - 1))
+
+ CHECK_EQ(124, t.round_up_out);
+ CHECK_EQ(123, t.round_down_out);
+ CHECK_EQ(-124, t.neg_round_up_out);
+ CHECK_EQ(-123, t.neg_round_down_out);
+
+ // Inaccurate.
+ CHECK_EQ(1, GET_FPU_ERR(t.round_err1_out));
+ // No error.
+ CHECK_EQ(0, GET_FPU_ERR(t.round_err2_out));
+ // Invalid operation.
+ CHECK_EQ(16, GET_FPU_ERR(t.round_err3_out));
+ CHECK_EQ(16, GET_FPU_ERR(t.round_err4_out));
+ CHECK_EQ(kFPUInvalidResult, t.round_invalid_result);
+
+ CHECK_EQ(123, t.floor_up_out);
+ CHECK_EQ(123, t.floor_down_out);
+ CHECK_EQ(-124, t.neg_floor_up_out);
+ CHECK_EQ(-124, t.neg_floor_down_out);
+
+ // Inaccurate.
+ CHECK_EQ(1, GET_FPU_ERR(t.floor_err1_out));
+ // No error.
+ CHECK_EQ(0, GET_FPU_ERR(t.floor_err2_out));
+ // Invalid operation.
+ CHECK_EQ(16, GET_FPU_ERR(t.floor_err3_out));
+ CHECK_EQ(16, GET_FPU_ERR(t.floor_err4_out));
+ CHECK_EQ(kFPUInvalidResult, t.floor_invalid_result);
+
+ CHECK_EQ(124, t.ceil_up_out);
+ CHECK_EQ(124, t.ceil_down_out);
+ CHECK_EQ(-123, t.neg_ceil_up_out);
+ CHECK_EQ(-123, t.neg_ceil_down_out);
+
+ // Inaccurate.
+ CHECK_EQ(1, GET_FPU_ERR(t.ceil_err1_out));
+ // No error.
+ CHECK_EQ(0, GET_FPU_ERR(t.ceil_err2_out));
+ // Invalid operation.
+ CHECK_EQ(16, GET_FPU_ERR(t.ceil_err3_out));
+ CHECK_EQ(16, GET_FPU_ERR(t.ceil_err4_out));
+ CHECK_EQ(kFPUInvalidResult, t.ceil_invalid_result);
+
+ // In rounding mode 0 cvt should behave like round.
+ CHECK_EQ(t.round_up_out, t.cvt_up_out);
+ CHECK_EQ(t.round_down_out, t.cvt_down_out);
+ CHECK_EQ(t.neg_round_up_out, t.neg_cvt_up_out);
+ CHECK_EQ(t.neg_round_down_out, t.neg_cvt_down_out);
+
+ // Inaccurate.
+ CHECK_EQ(1, GET_FPU_ERR(t.cvt_err1_out));
+ // No error.
+ CHECK_EQ(0, GET_FPU_ERR(t.cvt_err2_out));
+ // Invalid operation.
+ CHECK_EQ(16, GET_FPU_ERR(t.cvt_err3_out));
+ CHECK_EQ(16, GET_FPU_ERR(t.cvt_err4_out));
+ CHECK_EQ(kFPUInvalidResult, t.cvt_invalid_result);
+ }
+}
+
+
#undef __
diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc
index 5d292df0..7e2115a1 100644
--- a/test/cctest/test-assembler-x64.cc
+++ b/test/cctest/test-assembler-x64.cc
@@ -50,8 +50,8 @@ using v8::internal::rbp;
using v8::internal::rsp;
using v8::internal::r8;
using v8::internal::r9;
-using v8::internal::r12;
using v8::internal::r13;
+using v8::internal::r15;
using v8::internal::times_1;
using v8::internal::FUNCTION_CAST;
@@ -86,6 +86,7 @@ static const v8::internal::Register arg2 = rsi;
TEST(AssemblerX64ReturnOperation) {
+ OS::Setup();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -107,6 +108,7 @@ TEST(AssemblerX64ReturnOperation) {
}
TEST(AssemblerX64StackOperations) {
+ OS::Setup();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -138,6 +140,7 @@ TEST(AssemblerX64StackOperations) {
}
TEST(AssemblerX64ArithmeticOperations) {
+ OS::Setup();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -159,6 +162,7 @@ TEST(AssemblerX64ArithmeticOperations) {
}
TEST(AssemblerX64ImulOperation) {
+ OS::Setup();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -186,6 +190,7 @@ TEST(AssemblerX64ImulOperation) {
}
TEST(AssemblerX64MemoryOperands) {
+ OS::Setup();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -219,6 +224,7 @@ TEST(AssemblerX64MemoryOperands) {
}
TEST(AssemblerX64ControlFlow) {
+ OS::Setup();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -247,6 +253,7 @@ TEST(AssemblerX64ControlFlow) {
}
TEST(AssemblerX64LoopImmediates) {
+ OS::Setup();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -317,7 +324,7 @@ TEST(OperandRegisterDependency) {
CHECK(Operand(rsp, offset).AddressUsesRegister(rsp));
CHECK(!Operand(rsp, offset).AddressUsesRegister(rax));
- CHECK(!Operand(rsp, offset).AddressUsesRegister(r12));
+ CHECK(!Operand(rsp, offset).AddressUsesRegister(r15));
CHECK(Operand(rbp, offset).AddressUsesRegister(rbp));
CHECK(!Operand(rbp, offset).AddressUsesRegister(rax));
@@ -333,7 +340,7 @@ TEST(OperandRegisterDependency) {
CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp));
CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp));
CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax));
- CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r12));
+ CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r15));
CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13));
}
}
diff --git a/test/cctest/test-ast.cc b/test/cctest/test-ast.cc
index 9c292bcf..6183357b 100644
--- a/test/cctest/test-ast.cc
+++ b/test/cctest/test-ast.cc
@@ -35,6 +35,7 @@
using namespace v8::internal;
TEST(List) {
+ v8::internal::V8::Initialize(NULL);
List<AstNode*>* list = new List<AstNode*>(0);
CHECK_EQ(0, list->length());
diff --git a/test/cctest/test-circular-queue.cc b/test/cctest/test-circular-queue.cc
index ce9a42e8..9dd4981c 100644
--- a/test/cctest/test-circular-queue.cc
+++ b/test/cctest/test-circular-queue.cc
@@ -84,11 +84,13 @@ class ProducerThread: public i::Thread {
public:
typedef SamplingCircularQueue::Cell Record;
- ProducerThread(SamplingCircularQueue* scq,
+ ProducerThread(i::Isolate* isolate,
+ SamplingCircularQueue* scq,
int records_per_chunk,
Record value,
i::Semaphore* finished)
- : scq_(scq),
+ : Thread(isolate, "producer"),
+ scq_(scq),
records_per_chunk_(records_per_chunk),
value_(value),
finished_(finished) { }
@@ -131,9 +133,10 @@ TEST(SamplingCircularQueueMultithreading) {
// Check that we are using non-reserved values.
CHECK_NE(SamplingCircularQueue::kClear, 1);
CHECK_NE(SamplingCircularQueue::kEnd, 1);
- ProducerThread producer1(&scq, kRecordsPerChunk, 1, semaphore);
- ProducerThread producer2(&scq, kRecordsPerChunk, 10, semaphore);
- ProducerThread producer3(&scq, kRecordsPerChunk, 20, semaphore);
+ i::Isolate* isolate = i::Isolate::Current();
+ ProducerThread producer1(isolate, &scq, kRecordsPerChunk, 1, semaphore);
+ ProducerThread producer2(isolate, &scq, kRecordsPerChunk, 10, semaphore);
+ ProducerThread producer3(isolate, &scq, kRecordsPerChunk, 20, semaphore);
CHECK_EQ(NULL, scq.StartDequeue());
producer1.Start();
diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc
index 9f21b78d..d3dd9c6f 100644
--- a/test/cctest/test-compiler.cc
+++ b/test/cctest/test-compiler.cc
@@ -34,7 +34,6 @@
#include "execution.h"
#include "factory.h"
#include "platform.h"
-#include "top.h"
#include "cctest.h"
using namespace v8::internal;
@@ -99,21 +98,21 @@ static void InitializeVM() {
static MaybeObject* GetGlobalProperty(const char* name) {
- Handle<String> symbol = Factory::LookupAsciiSymbol(name);
- return Top::context()->global()->GetProperty(*symbol);
+ Handle<String> symbol = FACTORY->LookupAsciiSymbol(name);
+ return Isolate::Current()->context()->global()->GetProperty(*symbol);
}
static void SetGlobalProperty(const char* name, Object* value) {
Handle<Object> object(value);
- Handle<String> symbol = Factory::LookupAsciiSymbol(name);
- Handle<JSObject> global(Top::context()->global());
+ Handle<String> symbol = FACTORY->LookupAsciiSymbol(name);
+ Handle<JSObject> global(Isolate::Current()->context()->global());
SetProperty(global, symbol, object, NONE, kNonStrictMode);
}
static Handle<JSFunction> Compile(const char* source) {
- Handle<String> source_code(Factory::NewStringFromUtf8(CStrVector(source)));
+ Handle<String> source_code(FACTORY->NewStringFromUtf8(CStrVector(source)));
Handle<SharedFunctionInfo> shared_function =
Compiler::Compile(source_code,
Handle<String>(),
@@ -123,8 +122,8 @@ static Handle<JSFunction> Compile(const char* source) {
NULL,
Handle<String>::null(),
NOT_NATIVES_CODE);
- return Factory::NewFunctionFromSharedFunctionInfo(shared_function,
- Top::global_context());
+ return FACTORY->NewFunctionFromSharedFunctionInfo(shared_function,
+ Isolate::Current()->global_context());
}
@@ -137,7 +136,7 @@ static double Inc(int x) {
if (fun.is_null()) return -1;
bool has_pending_exception;
- Handle<JSObject> global(Top::context()->global());
+ Handle<JSObject> global(Isolate::Current()->context()->global());
Execution::Call(fun, global, 0, NULL, &has_pending_exception);
CHECK(!has_pending_exception);
return GetGlobalProperty("result")->ToObjectChecked()->Number();
@@ -158,7 +157,7 @@ static double Add(int x, int y) {
SetGlobalProperty("x", Smi::FromInt(x));
SetGlobalProperty("y", Smi::FromInt(y));
bool has_pending_exception;
- Handle<JSObject> global(Top::context()->global());
+ Handle<JSObject> global(Isolate::Current()->context()->global());
Execution::Call(fun, global, 0, NULL, &has_pending_exception);
CHECK(!has_pending_exception);
return GetGlobalProperty("result")->ToObjectChecked()->Number();
@@ -178,7 +177,7 @@ static double Abs(int x) {
SetGlobalProperty("x", Smi::FromInt(x));
bool has_pending_exception;
- Handle<JSObject> global(Top::context()->global());
+ Handle<JSObject> global(Isolate::Current()->context()->global());
Execution::Call(fun, global, 0, NULL, &has_pending_exception);
CHECK(!has_pending_exception);
return GetGlobalProperty("result")->ToObjectChecked()->Number();
@@ -199,7 +198,7 @@ static double Sum(int n) {
SetGlobalProperty("n", Smi::FromInt(n));
bool has_pending_exception;
- Handle<JSObject> global(Top::context()->global());
+ Handle<JSObject> global(Isolate::Current()->context()->global());
Execution::Call(fun, global, 0, NULL, &has_pending_exception);
CHECK(!has_pending_exception);
return GetGlobalProperty("result")->ToObjectChecked()->Number();
@@ -220,7 +219,7 @@ TEST(Print) {
Handle<JSFunction> fun = Compile(source);
if (fun.is_null()) return;
bool has_pending_exception;
- Handle<JSObject> global(Top::context()->global());
+ Handle<JSObject> global(Isolate::Current()->context()->global());
Execution::Call(fun, global, 0, NULL, &has_pending_exception);
CHECK(!has_pending_exception);
}
@@ -253,7 +252,7 @@ TEST(Stuff) {
Handle<JSFunction> fun = Compile(source);
CHECK(!fun.is_null());
bool has_pending_exception;
- Handle<JSObject> global(Top::context()->global());
+ Handle<JSObject> global(Isolate::Current()->context()->global());
Execution::Call(fun, global, 0, NULL, &has_pending_exception);
CHECK(!has_pending_exception);
CHECK_EQ(511.0, GetGlobalProperty("r")->ToObjectChecked()->Number());
@@ -268,11 +267,12 @@ TEST(UncaughtThrow) {
Handle<JSFunction> fun = Compile(source);
CHECK(!fun.is_null());
bool has_pending_exception;
- Handle<JSObject> global(Top::context()->global());
+ Handle<JSObject> global(Isolate::Current()->context()->global());
Handle<Object> result =
Execution::Call(fun, global, 0, NULL, &has_pending_exception);
CHECK(has_pending_exception);
- CHECK_EQ(42.0, Top::pending_exception()->ToObjectChecked()->Number());
+ CHECK_EQ(42.0, Isolate::Current()->pending_exception()->
+ ToObjectChecked()->Number());
}
@@ -293,18 +293,18 @@ TEST(C2JSFrames) {
// Run the generated code to populate the global object with 'foo'.
bool has_pending_exception;
- Handle<JSObject> global(Top::context()->global());
+ Handle<JSObject> global(Isolate::Current()->context()->global());
Execution::Call(fun0, global, 0, NULL, &has_pending_exception);
CHECK(!has_pending_exception);
- Object* foo_symbol = Factory::LookupAsciiSymbol("foo")->ToObjectChecked();
- MaybeObject* fun1_object =
- Top::context()->global()->GetProperty(String::cast(foo_symbol));
+ Object* foo_symbol = FACTORY->LookupAsciiSymbol("foo")->ToObjectChecked();
+ MaybeObject* fun1_object = Isolate::Current()->context()->global()->
+ GetProperty(String::cast(foo_symbol));
Handle<Object> fun1(fun1_object->ToObjectChecked());
CHECK(fun1->IsJSFunction());
Object** argv[1] = {
- Handle<Object>::cast(Factory::LookupAsciiSymbol("hello")).location()
+ Handle<Object>::cast(FACTORY->LookupAsciiSymbol("hello")).location()
};
Execution::Call(Handle<JSFunction>::cast(fun1), global, 1, argv,
&has_pending_exception);
@@ -318,8 +318,8 @@ TEST(Regression236) {
InitializeVM();
v8::HandleScope scope;
- Handle<Script> script = Factory::NewScript(Factory::empty_string());
- script->set_source(Heap::undefined_value());
+ Handle<Script> script = FACTORY->NewScript(FACTORY->empty_string());
+ script->set_source(HEAP->undefined_value());
CHECK_EQ(-1, GetScriptLineNumber(script, 0));
CHECK_EQ(-1, GetScriptLineNumber(script, 100));
CHECK_EQ(-1, GetScriptLineNumber(script, -1));
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 7f06bc34..749ac154 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -7,6 +7,7 @@
#include "v8.h"
#include "cpu-profiler-inl.h"
#include "cctest.h"
+#include "../include/v8-profiler.h"
namespace i = v8::internal;
@@ -23,7 +24,7 @@ using i::TokenEnumerator;
TEST(StartStop) {
CpuProfilesCollection profiles;
ProfileGenerator generator(&profiles);
- ProfilerEventsProcessor processor(&generator);
+ ProfilerEventsProcessor processor(i::Isolate::Current(), &generator);
processor.Start();
while (!processor.running()) {
i::Thread::YieldCPU();
@@ -87,7 +88,7 @@ TEST(CodeEvents) {
CpuProfilesCollection profiles;
profiles.StartProfiling("", 1);
ProfileGenerator generator(&profiles);
- ProfilerEventsProcessor processor(&generator);
+ ProfilerEventsProcessor processor(i::Isolate::Current(), &generator);
processor.Start();
while (!processor.running()) {
i::Thread::YieldCPU();
@@ -96,11 +97,11 @@ TEST(CodeEvents) {
// Enqueue code creation events.
i::HandleScope scope;
const char* aaa_str = "aaa";
- i::Handle<i::String> aaa_name = i::Factory::NewStringFromAscii(
+ i::Handle<i::String> aaa_name = FACTORY->NewStringFromAscii(
i::Vector<const char>(aaa_str, i::StrLength(aaa_str)));
processor.CodeCreateEvent(i::Logger::FUNCTION_TAG,
*aaa_name,
- i::Heap::empty_string(),
+ HEAP->empty_string(),
0,
ToAddress(0x1000),
0x100,
@@ -151,7 +152,7 @@ TEST(TickEvents) {
CpuProfilesCollection profiles;
profiles.StartProfiling("", 1);
ProfileGenerator generator(&profiles);
- ProfilerEventsProcessor processor(&generator);
+ ProfilerEventsProcessor processor(i::Isolate::Current(), &generator);
processor.Start();
while (!processor.running()) {
i::Thread::YieldCPU();
@@ -236,4 +237,138 @@ TEST(CrashIfStoppingLastNonExistentProfile) {
CpuProfiler::TearDown();
}
+
+TEST(DeleteAllCpuProfiles) {
+ InitializeVM();
+ TestSetup test_setup;
+ CpuProfiler::Setup();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+ CpuProfiler::DeleteAllProfiles();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+
+ CpuProfiler::StartProfiling("1");
+ CpuProfiler::StopProfiling("1");
+ CHECK_EQ(1, CpuProfiler::GetProfilesCount());
+ CpuProfiler::DeleteAllProfiles();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+ CpuProfiler::StartProfiling("1");
+ CpuProfiler::StartProfiling("2");
+ CpuProfiler::StopProfiling("2");
+ CpuProfiler::StopProfiling("1");
+ CHECK_EQ(2, CpuProfiler::GetProfilesCount());
+ CpuProfiler::DeleteAllProfiles();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+
+ // Test profiling cancellation by the 'delete' command.
+ CpuProfiler::StartProfiling("1");
+ CpuProfiler::StartProfiling("2");
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+ CpuProfiler::DeleteAllProfiles();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+
+ CpuProfiler::TearDown();
+}
+
+
+TEST(DeleteCpuProfile) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
+ v8::Local<v8::String> name1 = v8::String::New("1");
+ v8::CpuProfiler::StartProfiling(name1);
+ const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
+ CHECK_NE(NULL, p1);
+ CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
+ unsigned uid1 = p1->GetUid();
+ CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
+ const_cast<v8::CpuProfile*>(p1)->Delete();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
+
+ v8::Local<v8::String> name2 = v8::String::New("2");
+ v8::CpuProfiler::StartProfiling(name2);
+ const v8::CpuProfile* p2 = v8::CpuProfiler::StopProfiling(name2);
+ CHECK_NE(NULL, p2);
+ CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
+ unsigned uid2 = p2->GetUid();
+ CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
+ CHECK_EQ(p2, v8::CpuProfiler::FindProfile(uid2));
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
+ v8::Local<v8::String> name3 = v8::String::New("3");
+ v8::CpuProfiler::StartProfiling(name3);
+ const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
+ CHECK_NE(NULL, p3);
+ CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
+ unsigned uid3 = p3->GetUid();
+ CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
+ CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
+ const_cast<v8::CpuProfile*>(p2)->Delete();
+ CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
+ CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
+ const_cast<v8::CpuProfile*>(p3)->Delete();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
+}
+
+
+TEST(DeleteCpuProfileDifferentTokens) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount());
+ v8::Local<v8::String> name1 = v8::String::New("1");
+ v8::CpuProfiler::StartProfiling(name1);
+ const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1);
+ CHECK_NE(NULL, p1);
+ CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
+ unsigned uid1 = p1->GetUid();
+ CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1));
+ v8::Local<v8::String> token1 = v8::String::New("token1");
+ const v8::CpuProfile* p1_t1 = v8::CpuProfiler::FindProfile(uid1, token1);
+ CHECK_NE(NULL, p1_t1);
+ CHECK_NE(p1, p1_t1);
+ CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
+ const_cast<v8::CpuProfile*>(p1)->Delete();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1));
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1, token1));
+ const_cast<v8::CpuProfile*>(p1_t1)->Delete();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+
+ v8::Local<v8::String> name2 = v8::String::New("2");
+ v8::CpuProfiler::StartProfiling(name2);
+ v8::Local<v8::String> token2 = v8::String::New("token2");
+ const v8::CpuProfile* p2_t2 = v8::CpuProfiler::StopProfiling(name2, token2);
+ CHECK_NE(NULL, p2_t2);
+ CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
+ unsigned uid2 = p2_t2->GetUid();
+ CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
+ const v8::CpuProfile* p2 = v8::CpuProfiler::FindProfile(uid2);
+ CHECK_NE(p2_t2, p2);
+ v8::Local<v8::String> name3 = v8::String::New("3");
+ v8::CpuProfiler::StartProfiling(name3);
+ const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3);
+ CHECK_NE(NULL, p3);
+ CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount());
+ unsigned uid3 = p3->GetUid();
+ CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
+ CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
+ const_cast<v8::CpuProfile*>(p2_t2)->Delete();
+ CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
+ CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
+ const_cast<v8::CpuProfile*>(p2)->Delete();
+ CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount());
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2));
+ CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3));
+ const_cast<v8::CpuProfile*>(p3)->Delete();
+ CHECK_EQ(0, CpuProfiler::GetProfilesCount());
+ CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3));
+}
+
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/test/cctest/test-dataflow.cc b/test/cctest/test-dataflow.cc
index 5894de2a..feae0b06 100644
--- a/test/cctest/test-dataflow.cc
+++ b/test/cctest/test-dataflow.cc
@@ -35,6 +35,7 @@
using namespace v8::internal;
TEST(BitVector) {
+ v8::internal::V8::Initialize(NULL);
ZoneScope zone(DELETE_ON_EXIT);
{
BitVector v(15);
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 7245e54b..b81129e6 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -143,17 +143,18 @@ class DebugLocalContext {
inline v8::Context* operator*() { return *context_; }
inline bool IsReady() { return !context_.IsEmpty(); }
void ExposeDebug() {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
// Expose the debug context global object in the global object for testing.
- Debug::Load();
- Debug::debug_context()->set_security_token(
+ debug->Load();
+ debug->debug_context()->set_security_token(
v8::Utils::OpenHandle(*context_)->security_token());
Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
v8::Utils::OpenHandle(*context_->Global())));
Handle<v8::internal::String> debug_string =
- v8::internal::Factory::LookupAsciiSymbol("debug");
+ FACTORY->LookupAsciiSymbol("debug");
SetProperty(global, debug_string,
- Handle<Object>(Debug::debug_context()->global_proxy()), DONT_ENUM,
+ Handle<Object>(debug->debug_context()->global_proxy()), DONT_ENUM,
::v8::internal::kNonStrictMode);
}
private:
@@ -196,7 +197,8 @@ static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
static int break_point = 0;
Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
- Debug::SetBreakPoint(
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
+ debug->SetBreakPoint(
shared,
Handle<Object>(v8::internal::Smi::FromInt(++break_point)),
&position);
@@ -279,7 +281,8 @@ static int SetScriptBreakPointByNameFromJS(const char* script_name,
// Clear a break point.
static void ClearBreakPoint(int break_point) {
- Debug::ClearBreakPoint(
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
+ debug->ClearBreakPoint(
Handle<Object>(v8::internal::Smi::FromInt(break_point)));
}
@@ -339,8 +342,9 @@ static void ChangeScriptBreakPointIgnoreCountFromJS(int break_point_number,
// Change break on exception.
static void ChangeBreakOnException(bool caught, bool uncaught) {
- Debug::ChangeBreakOnException(v8::internal::BreakException, caught);
- Debug::ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
+ debug->ChangeBreakOnException(v8::internal::BreakException, caught);
+ debug->ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
}
@@ -365,7 +369,8 @@ static void ChangeBreakOnExceptionFromJS(bool caught, bool uncaught) {
// Prepare to step to next break location.
static void PrepareStep(StepAction step_action) {
- Debug::PrepareStep(step_action, 1);
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
+ debug->PrepareStep(step_action, 1);
}
@@ -376,7 +381,9 @@ namespace internal {
// Collect the currently debugged functions.
Handle<FixedArray> GetDebuggedFunctions() {
- v8::internal::DebugInfoListNode* node = Debug::debug_info_list_;
+ Debug* debug = Isolate::Current()->debug();
+
+ v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
// Find the number of debugged functions.
int count = 0;
@@ -387,7 +394,7 @@ Handle<FixedArray> GetDebuggedFunctions() {
// Allocate array for the debugged functions
Handle<FixedArray> debugged_functions =
- v8::internal::Factory::NewFixedArray(count);
+ FACTORY->NewFixedArray(count);
// Run through the debug info objects and collect all functions.
count = 0;
@@ -402,7 +409,9 @@ Handle<FixedArray> GetDebuggedFunctions() {
static Handle<Code> ComputeCallDebugBreak(int argc) {
CALL_HEAP_FUNCTION(
- v8::internal::StubCache::ComputeCallDebugBreak(argc, Code::CALL_IC),
+ v8::internal::Isolate::Current(),
+ v8::internal::Isolate::Current()->stub_cache()->ComputeCallDebugBreak(
+ argc, Code::CALL_IC),
Code);
}
@@ -411,12 +420,12 @@ static Handle<Code> ComputeCallDebugBreak(int argc) {
void CheckDebuggerUnloaded(bool check_functions) {
// Check that the debugger context is cleared and that there is no debug
// information stored for the debugger.
- CHECK(Debug::debug_context().is_null());
- CHECK_EQ(NULL, Debug::debug_info_list_);
+ CHECK(Isolate::Current()->debug()->debug_context().is_null());
+ CHECK_EQ(NULL, Isolate::Current()->debug()->debug_info_list_);
// Collect garbage to ensure weak handles are cleared.
- Heap::CollectAllGarbage(false);
- Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
// Iterate the head and check that there are no debugger related objects left.
HeapIterator iterator;
@@ -444,8 +453,8 @@ void CheckDebuggerUnloaded(bool check_functions) {
void ForceUnloadDebugger() {
- Debugger::never_unload_debugger_ = false;
- Debugger::UnloadDebugger();
+ Isolate::Current()->debugger()->never_unload_debugger_ = false;
+ Isolate::Current()->debugger()->UnloadDebugger();
}
@@ -480,6 +489,8 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
const char* source, const char* name,
int position, v8::internal::RelocInfo::Mode mode,
Code* debug_break) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
+
// Create function and set the break point.
Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
*CompileFunction(env, source, name));
@@ -501,8 +512,8 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
// Clear the break point and check that the debug break function is no longer
// there
ClearBreakPoint(bp);
- CHECK(!Debug::HasDebugInfo(shared));
- CHECK(Debug::EnsureDebugInfo(shared));
+ CHECK(!debug->HasDebugInfo(shared));
+ CHECK(debug->EnsureDebugInfo(shared));
TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
it2.FindBreakLocationFromPosition(position);
CHECK_EQ(mode, it2.it()->rinfo()->rmode());
@@ -634,8 +645,9 @@ static void DebugEventBreakPointHitCount(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ Debug* debug = v8::internal::Isolate::Current()->debug();
// When hitting a debug event listener there must be a break set.
- CHECK_NE(v8::internal::Debug::break_id(), 0);
+ CHECK_NE(debug->break_id(), 0);
// Count the number of breaks.
if (event == v8::Break) {
@@ -738,8 +750,10 @@ static void DebugEventCounter(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
+
// When hitting a debug event listener there must be a break set.
- CHECK_NE(v8::internal::Debug::break_id(), 0);
+ CHECK_NE(debug->break_id(), 0);
// Count the number of breaks.
if (event == v8::Break) {
@@ -796,8 +810,9 @@ static void DebugEventEvaluate(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
// When hitting a debug event listener there must be a break set.
- CHECK_NE(v8::internal::Debug::break_id(), 0);
+ CHECK_NE(debug->break_id(), 0);
if (event == v8::Break) {
for (int i = 0; checks[i].expr != NULL; i++) {
@@ -822,8 +837,9 @@ static void DebugEventRemoveBreakPoint(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
// When hitting a debug event listener there must be a break set.
- CHECK_NE(v8::internal::Debug::break_id(), 0);
+ CHECK_NE(debug->break_id(), 0);
if (event == v8::Break) {
break_point_hit_count++;
@@ -840,8 +856,9 @@ static void DebugEventStep(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
// When hitting a debug event listener there must be a break set.
- CHECK_NE(v8::internal::Debug::break_id(), 0);
+ CHECK_NE(debug->break_id(), 0);
if (event == v8::Break) {
break_point_hit_count++;
@@ -866,8 +883,9 @@ static void DebugEventStepSequence(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
// When hitting a debug event listener there must be a break set.
- CHECK_NE(v8::internal::Debug::break_id(), 0);
+ CHECK_NE(debug->break_id(), 0);
if (event == v8::Break || event == v8::Exception) {
// Check that the current function is the expected.
@@ -896,8 +914,9 @@ static void DebugEventBreakPointCollectGarbage(
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
// When hitting a debug event listener there must be a break set.
- CHECK_NE(v8::internal::Debug::break_id(), 0);
+ CHECK_NE(debug->break_id(), 0);
// Perform a garbage collection when break point is hit and continue. Based
// on the number of break points hit either scavenge or mark compact
@@ -906,10 +925,10 @@ static void DebugEventBreakPointCollectGarbage(
break_point_hit_count++;
if (break_point_hit_count % 2 == 0) {
// Scavenge.
- Heap::CollectGarbage(v8::internal::NEW_SPACE);
+ HEAP->CollectGarbage(v8::internal::NEW_SPACE);
} else {
// Mark sweep compact.
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
}
}
}
@@ -921,8 +940,9 @@ static void DebugEventBreak(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
// When hitting a debug event listener there must be a break set.
- CHECK_NE(v8::internal::Debug::break_id(), 0);
+ CHECK_NE(debug->break_id(), 0);
if (event == v8::Break) {
// Count the number of breaks.
@@ -930,7 +950,7 @@ static void DebugEventBreak(v8::DebugEvent event,
// Run the garbage collector to enforce heap verification if option
// --verify-heap is set.
- Heap::CollectGarbage(v8::internal::NEW_SPACE);
+ HEAP->CollectGarbage(v8::internal::NEW_SPACE);
// Set the break flag again to come back here as soon as possible.
v8::Debug::DebugBreak();
@@ -946,8 +966,9 @@ static void DebugEventBreakMax(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
// When hitting a debug event listener there must be a break set.
- CHECK_NE(v8::internal::Debug::break_id(), 0);
+ CHECK_NE(debug->break_id(), 0);
if (event == v8::Break) {
if (break_point_hit_count < max_break_point_hit_count) {
@@ -987,6 +1008,7 @@ static void MessageCallbackCount(v8::Handle<v8::Message> message,
// of break locations.
TEST(DebugStub) {
using ::v8::internal::Builtins;
+ using ::v8::internal::Isolate;
v8::HandleScope scope;
DebugLocalContext env;
@@ -999,12 +1021,14 @@ TEST(DebugStub) {
"function f2(){x=1;}", "f2",
0,
v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
- Builtins::builtin(Builtins::StoreIC_DebugBreak));
+ Isolate::Current()->builtins()->builtin(
+ Builtins::kStoreIC_DebugBreak));
CheckDebugBreakFunction(&env,
"function f3(){var a=x;}", "f3",
0,
v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
- Builtins::builtin(Builtins::LoadIC_DebugBreak));
+ Isolate::Current()->builtins()->builtin(
+ Builtins::kLoadIC_DebugBreak));
// TODO(1240753): Make the test architecture independent or split
// parts of the debugger into architecture dependent files. This
@@ -1017,14 +1041,16 @@ TEST(DebugStub) {
"f4",
0,
v8::internal::RelocInfo::CODE_TARGET,
- Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
+ Isolate::Current()->builtins()->builtin(
+ Builtins::kKeyedStoreIC_DebugBreak));
CheckDebugBreakFunction(
&env,
"function f5(){var index='propertyName'; var a={}; return a[index];}",
"f5",
0,
v8::internal::RelocInfo::CODE_TARGET,
- Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
+ Isolate::Current()->builtins()->builtin(
+ Builtins::kKeyedLoadIC_DebugBreak));
#endif
// Check the debug break code stubs for call ICs with different number of
@@ -1139,7 +1165,7 @@ TEST(BreakPointICLoad) {
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(0, break_point_hit_count);
- // Run with breakpoint
+ // Run with breakpoint.
int bp = SetBreakPoint(foo, 0);
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(1, break_point_hit_count);
@@ -1172,7 +1198,7 @@ TEST(BreakPointICCall) {
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(0, break_point_hit_count);
- // Run with breakpoint.
+ // Run with breakpoint
int bp = SetBreakPoint(foo, 0);
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(1, break_point_hit_count);
@@ -1367,12 +1393,12 @@ static void CallAndGC(v8::Local<v8::Object> recv,
CHECK_EQ(1 + i * 3, break_point_hit_count);
// Scavenge and call function.
- Heap::CollectGarbage(v8::internal::NEW_SPACE);
+ HEAP->CollectGarbage(v8::internal::NEW_SPACE);
f->Call(recv, 0, NULL);
CHECK_EQ(2 + i * 3, break_point_hit_count);
// Mark sweep (and perhaps compact) and call function.
- Heap::CollectAllGarbage(force_compaction);
+ HEAP->CollectAllGarbage(force_compaction);
f->Call(recv, 0, NULL);
CHECK_EQ(3 + i * 3, break_point_hit_count);
}
@@ -2199,7 +2225,7 @@ TEST(ScriptBreakPointLineTopLevel) {
}
f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
- Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
SetScriptBreakPointByNameFromJS("test.html", 3, -1);
@@ -3698,7 +3724,7 @@ TEST(BreakOnException) {
DebugLocalContext env;
env.ExposeDebug();
- v8::internal::Top::TraceException(false);
+ v8::internal::Isolate::Current()->TraceException(false);
// Create functions for testing break on exception.
v8::Local<v8::Function> throws =
@@ -3845,7 +3871,7 @@ TEST(BreakOnCompileException) {
// For this test, we want to break on uncaught exceptions:
ChangeBreakOnException(false, true);
- v8::internal::Top::TraceException(false);
+ v8::internal::Isolate::Current()->TraceException(false);
// Create a function for checking the function when hitting a break point.
frame_count = CompileFunction(&env, frame_count_source, "frame_count");
@@ -4694,6 +4720,8 @@ Barriers message_queue_barriers;
// placing JSON debugger commands in the queue.
class MessageQueueDebuggerThread : public v8::internal::Thread {
public:
+ explicit MessageQueueDebuggerThread(v8::internal::Isolate* isolate)
+ : Thread(isolate, "MessageQueueDebuggerThread") { }
void Run();
};
@@ -4793,10 +4821,12 @@ void MessageQueueDebuggerThread::Run() {
// Main thread continues running source_3 to end, waits for this thread.
}
-MessageQueueDebuggerThread message_queue_debugger_thread;
// This thread runs the v8 engine.
TEST(MessageQueues) {
+ MessageQueueDebuggerThread message_queue_debugger_thread(
+ i::Isolate::Current());
+
// Create a V8 environment
v8::HandleScope scope;
DebugLocalContext env;
@@ -4942,11 +4972,15 @@ Barriers threaded_debugging_barriers;
class V8Thread : public v8::internal::Thread {
public:
+ explicit V8Thread(v8::internal::Isolate* isolate)
+ : Thread(isolate, "V8Thread") { }
void Run();
};
class DebuggerThread : public v8::internal::Thread {
public:
+ explicit DebuggerThread(v8::internal::Isolate* isolate)
+ : Thread(isolate, "DebuggerThread") { }
void Run();
};
@@ -5021,10 +5055,11 @@ void DebuggerThread::Run() {
v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
}
-DebuggerThread debugger_thread;
-V8Thread v8_thread;
TEST(ThreadedDebugging) {
+ DebuggerThread debugger_thread(i::Isolate::Current());
+ V8Thread v8_thread(i::Isolate::Current());
+
// Create a V8 environment
threaded_debugging_barriers.Initialize();
@@ -5044,13 +5079,17 @@ TEST(ThreadedDebugging) {
class BreakpointsV8Thread : public v8::internal::Thread {
public:
+ explicit BreakpointsV8Thread(v8::internal::Isolate* isolate)
+ : Thread(isolate, "BreakpointsV8Thread") { }
void Run();
};
class BreakpointsDebuggerThread : public v8::internal::Thread {
public:
- explicit BreakpointsDebuggerThread(bool global_evaluate)
- : global_evaluate_(global_evaluate) {}
+ explicit BreakpointsDebuggerThread(v8::internal::Isolate* isolate,
+ bool global_evaluate)
+ : Thread(isolate, "BreakpointsDebuggerThread"),
+ global_evaluate_(global_evaluate) {}
void Run();
private:
@@ -5226,8 +5265,9 @@ void BreakpointsDebuggerThread::Run() {
void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
i::FLAG_debugger_auto_break = true;
- BreakpointsDebuggerThread breakpoints_debugger_thread(global_evaluate);
- BreakpointsV8Thread breakpoints_v8_thread;
+ BreakpointsDebuggerThread breakpoints_debugger_thread(i::Isolate::Current(),
+ global_evaluate);
+ BreakpointsV8Thread breakpoints_v8_thread(i::Isolate::Current());
// Create a V8 environment
Barriers stack_allocated_breakpoints_barriers;
@@ -5609,11 +5649,15 @@ TEST(DebuggerClearMessageHandlerWhileActive) {
class HostDispatchV8Thread : public v8::internal::Thread {
public:
+ explicit HostDispatchV8Thread(v8::internal::Isolate* isolate)
+ : Thread(isolate, "HostDispatchV8Thread") { }
void Run();
};
class HostDispatchDebuggerThread : public v8::internal::Thread {
public:
+ explicit HostDispatchDebuggerThread(v8::internal::Isolate* isolate)
+ : Thread(isolate, "HostDispatchDebuggerThread") { }
void Run();
};
@@ -5683,11 +5727,11 @@ void HostDispatchDebuggerThread::Run() {
v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
}
-HostDispatchDebuggerThread host_dispatch_debugger_thread;
-HostDispatchV8Thread host_dispatch_v8_thread;
-
TEST(DebuggerHostDispatch) {
+ HostDispatchDebuggerThread host_dispatch_debugger_thread(
+ i::Isolate::Current());
+ HostDispatchV8Thread host_dispatch_v8_thread(i::Isolate::Current());
i::FLAG_debugger_auto_break = true;
// Create a V8 environment
@@ -5711,11 +5755,15 @@ TEST(DebuggerHostDispatch) {
class DebugMessageDispatchV8Thread : public v8::internal::Thread {
public:
+ explicit DebugMessageDispatchV8Thread(v8::internal::Isolate* isolate)
+ : Thread(isolate, "DebugMessageDispatchV8Thread") { }
void Run();
};
class DebugMessageDispatchDebuggerThread : public v8::internal::Thread {
public:
+ explicit DebugMessageDispatchDebuggerThread(v8::internal::Isolate* isolate)
+ : Thread(isolate, "DebugMessageDispatchDebuggerThread") { }
void Run();
};
@@ -5747,11 +5795,13 @@ void DebugMessageDispatchDebuggerThread::Run() {
debug_message_dispatch_barriers->barrier_2.Wait();
}
-DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
-DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
-
TEST(DebuggerDebugMessageDispatch) {
+ DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread(
+ i::Isolate::Current());
+ DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread(
+ i::Isolate::Current());
+
i::FLAG_debugger_auto_break = true;
// Create a V8 environment
@@ -5769,6 +5819,7 @@ TEST(DebuggerDebugMessageDispatch) {
TEST(DebuggerAgent) {
+ i::Debugger* debugger = i::Isolate::Current()->debugger();
// Make sure these ports is not used by other tests to allow tests to run in
// parallel.
const int kPort1 = 5858;
@@ -5786,18 +5837,18 @@ TEST(DebuggerAgent) {
i::Socket::Setup();
// Test starting and stopping the agent without any client connection.
- i::Debugger::StartAgent("test", kPort1);
- i::Debugger::StopAgent();
+ debugger->StartAgent("test", kPort1);
+ debugger->StopAgent();
// Test starting the agent, connecting a client and shutting down the agent
// with the client connected.
- ok = i::Debugger::StartAgent("test", kPort2);
+ ok = debugger->StartAgent("test", kPort2);
CHECK(ok);
- i::Debugger::WaitForAgent();
+ debugger->WaitForAgent();
i::Socket* client = i::OS::CreateSocket();
ok = client->Connect("localhost", port2_str);
CHECK(ok);
- i::Debugger::StopAgent();
+ debugger->StopAgent();
delete client;
// Test starting and stopping the agent with the required port already
@@ -5805,8 +5856,8 @@ TEST(DebuggerAgent) {
i::Socket* server = i::OS::CreateSocket();
server->Bind(kPort3);
- i::Debugger::StartAgent("test", kPort3);
- i::Debugger::StopAgent();
+ debugger->StartAgent("test", kPort3);
+ debugger->StopAgent();
delete server;
}
@@ -5814,8 +5865,11 @@ TEST(DebuggerAgent) {
class DebuggerAgentProtocolServerThread : public i::Thread {
public:
- explicit DebuggerAgentProtocolServerThread(int port)
- : port_(port), server_(NULL), client_(NULL),
+ explicit DebuggerAgentProtocolServerThread(i::Isolate* isolate, int port)
+ : Thread(isolate, "DebuggerAgentProtocolServerThread"),
+ port_(port),
+ server_(NULL),
+ client_(NULL),
listening_(OS::CreateSemaphore(0)) {
}
~DebuggerAgentProtocolServerThread() {
@@ -5877,7 +5931,7 @@ TEST(DebuggerAgentProtocolOverflowHeader) {
// Create a socket server to receive a debugger agent message.
DebuggerAgentProtocolServerThread* server =
- new DebuggerAgentProtocolServerThread(kPort);
+ new DebuggerAgentProtocolServerThread(i::Isolate::Current(), kPort);
server->Start();
server->WaitForListening();
@@ -6376,17 +6430,18 @@ static void DebugEventScriptCollectedEvent(v8::DebugEvent event,
// Test that scripts collected are reported through the debug event listener.
TEST(ScriptCollectedEvent) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
break_point_hit_count = 0;
script_collected_count = 0;
v8::HandleScope scope;
DebugLocalContext env;
// Request the loaded scripts to initialize the debugger script cache.
- Debug::GetLoadedScripts();
+ debug->GetLoadedScripts();
// Do garbage collection to ensure that only the script in this test will be
// collected afterwards.
- Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
script_collected_count = 0;
v8::Debug::SetDebugEventListener(DebugEventScriptCollectedEvent,
@@ -6398,7 +6453,7 @@ TEST(ScriptCollectedEvent) {
// Do garbage collection to collect the script above which is no longer
// referenced.
- Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(2, script_collected_count);
@@ -6422,6 +6477,7 @@ static void ScriptCollectedMessageHandler(const v8::Debug::Message& message) {
// Test that GetEventContext doesn't fail and return empty handle for
// ScriptCollected events.
TEST(ScriptCollectedEventContext) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
script_collected_message_count = 0;
v8::HandleScope scope;
@@ -6429,11 +6485,11 @@ TEST(ScriptCollectedEventContext) {
DebugLocalContext env;
// Request the loaded scripts to initialize the debugger script cache.
- Debug::GetLoadedScripts();
+ debug->GetLoadedScripts();
// Do garbage collection to ensure that only the script in this test will be
// collected afterwards.
- Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
v8::Debug::SetMessageHandler2(ScriptCollectedMessageHandler);
{
@@ -6444,7 +6500,7 @@ TEST(ScriptCollectedEventContext) {
// Do garbage collection to collect the script above which is no longer
// referenced.
- Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK_EQ(2, script_collected_message_count);
@@ -6592,6 +6648,7 @@ TEST(ProvisionalBreakpointOnLineOutOfRange) {
static void BreakMessageHandler(const v8::Debug::Message& message) {
+ i::Isolate* isolate = i::Isolate::Current();
if (message.IsEvent() && message.GetEvent() == v8::Break) {
// Count the number of breaks.
break_point_hit_count++;
@@ -6603,18 +6660,18 @@ static void BreakMessageHandler(const v8::Debug::Message& message) {
} else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
v8::HandleScope scope;
- bool is_debug_break = i::StackGuard::IsDebugBreak();
+ bool is_debug_break = isolate->stack_guard()->IsDebugBreak();
// Force DebugBreak flag while serializer is working.
- i::StackGuard::DebugBreak();
+ isolate->stack_guard()->DebugBreak();
// Force serialization to trigger some internal JS execution.
v8::Handle<v8::String> json = message.GetJSON();
// Restore previous state.
if (is_debug_break) {
- i::StackGuard::DebugBreak();
+ isolate->stack_guard()->DebugBreak();
} else {
- i::StackGuard::Continue(i::DEBUGBREAK);
+ isolate->stack_guard()->Continue(i::DEBUGBREAK);
}
}
}
@@ -6843,6 +6900,7 @@ static void DebugEventGetAtgumentPropertyValue(
TEST(CallingContextIsNotDebugContext) {
+ v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
// Create and enter a debugee context.
v8::HandleScope scope;
DebugLocalContext env;
@@ -6851,7 +6909,7 @@ TEST(CallingContextIsNotDebugContext) {
// Save handles to the debugger and debugee contexts to be used in
// NamedGetterWithCallingContextCheck.
debugee_context = v8::Local<v8::Context>(*env);
- debugger_context = v8::Utils::ToLocal(Debug::debug_context());
+ debugger_context = v8::Utils::ToLocal(debug->debug_context());
// Create object with 'a' property accessor.
v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
diff --git a/test/cctest/test-decls.cc b/test/cctest/test-decls.cc
index 6ea4c849..61983918 100644
--- a/test/cctest/test-decls.cc
+++ b/test/cctest/test-decls.cc
@@ -130,7 +130,7 @@ void DeclarationContext::Check(const char* source,
InitializeIfNeeded();
// A retry after a GC may pollute the counts, so perform gc now
// to avoid that.
- v8::internal::Heap::CollectGarbage(v8::internal::NEW_SPACE);
+ HEAP->CollectGarbage(v8::internal::NEW_SPACE);
HandleScope scope;
TryCatch catcher;
catcher.SetVerbose(true);
diff --git a/test/cctest/test-deoptimization.cc b/test/cctest/test-deoptimization.cc
index 17453552..5ab84f96 100644
--- a/test/cctest/test-deoptimization.cc
+++ b/test/cctest/test-deoptimization.cc
@@ -30,20 +30,21 @@
#include "v8.h"
#include "api.h"
+#include "cctest.h"
#include "compilation-cache.h"
#include "debug.h"
#include "deoptimizer.h"
+#include "isolate.h"
#include "platform.h"
#include "stub-cache.h"
-#include "cctest.h"
-
-using ::v8::internal::Handle;
-using ::v8::internal::Object;
-using ::v8::internal::JSFunction;
using ::v8::internal::Deoptimizer;
using ::v8::internal::EmbeddedVector;
+using ::v8::internal::Handle;
+using ::v8::internal::Isolate;
+using ::v8::internal::JSFunction;
using ::v8::internal::OS;
+using ::v8::internal::Object;
// Size of temp buffer for formatting small strings.
#define SMALL_STRING_BUFFER_SIZE 80
@@ -124,7 +125,7 @@ TEST(DeoptimizeSimple) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
// Test lazy deoptimization of a simple function. Call the function after the
// deoptimization while it is still activated further down the stack.
@@ -140,7 +141,7 @@ TEST(DeoptimizeSimple) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -164,7 +165,7 @@ TEST(DeoptimizeSimpleWithArguments) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
// Test lazy deoptimization of a simple function with some arguments. Call the
// function after the deoptimization while it is still activated further down
@@ -181,7 +182,7 @@ TEST(DeoptimizeSimpleWithArguments) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -207,7 +208,7 @@ TEST(DeoptimizeSimpleNested) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(6, env->Global()->Get(v8_str("result"))->Int32Value());
CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
}
@@ -232,7 +233,7 @@ TEST(DeoptimizeRecursive) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(11, env->Global()->Get(v8_str("calls"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
v8::Local<v8::Function> fun =
v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
@@ -266,7 +267,7 @@ TEST(DeoptimizeMultiple) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -289,7 +290,7 @@ TEST(DeoptimizeConstructor) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK(env->Global()->Get(v8_str("result"))->IsTrue());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
{
AlwaysOptimizeAllowNativesSyntaxNoInlining options;
@@ -306,7 +307,7 @@ TEST(DeoptimizeConstructor) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(3, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -337,7 +338,7 @@ TEST(DeoptimizeConstructorMultiple) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -385,7 +386,7 @@ TEST(DeoptimizeBinaryOperationADDString) {
CHECK(result->IsString());
v8::String::AsciiValue ascii(result);
CHECK_EQ("a+an X", *ascii);
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -444,7 +445,7 @@ TEST(DeoptimizeBinaryOperationADD) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(15, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -458,7 +459,7 @@ TEST(DeoptimizeBinaryOperationSUB) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(-1, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -472,7 +473,7 @@ TEST(DeoptimizeBinaryOperationMUL) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(56, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -486,7 +487,7 @@ TEST(DeoptimizeBinaryOperationDIV) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(0, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -500,7 +501,7 @@ TEST(DeoptimizeBinaryOperationMOD) {
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(7, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -545,7 +546,7 @@ TEST(DeoptimizeCompare) {
CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(true, env->Global()->Get(v8_str("result"))->BooleanValue());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -627,7 +628,7 @@ TEST(DeoptimizeLoadICStoreIC) {
CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
CHECK_EQ(4, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
@@ -710,5 +711,5 @@ TEST(DeoptimizeLoadICStoreICNested) {
CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
- CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(Isolate::Current()));
}
diff --git a/test/cctest/test-disasm-arm.cc b/test/cctest/test-disasm-arm.cc
index dea0db92..32216147 100644
--- a/test/cctest/test-disasm-arm.cc
+++ b/test/cctest/test-disasm-arm.cc
@@ -270,7 +270,7 @@ TEST(Type0) {
"13a06000 movne r6, #0");
// mov -> movw.
- if (CpuFeatures::IsSupported(ARMv7)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
COMPARE(mov(r5, Operand(0x01234), LeaveCC, ne),
"13015234 movwne r5, #4660");
// We only disassemble one instruction so the eor instruction is not here.
@@ -360,7 +360,7 @@ TEST(Type1) {
TEST(Type3) {
SETUP();
- if (CpuFeatures::IsSupported(ARMv7)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) {
COMPARE(ubfx(r0, r1, 5, 10),
"e7e902d1 ubfx r0, r1, #5, #10");
COMPARE(ubfx(r1, r0, 5, 10),
@@ -415,7 +415,7 @@ TEST(Type3) {
TEST(Vfp) {
SETUP();
- if (CpuFeatures::IsSupported(VFP3)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
COMPARE(vmov(d0, d1),
"eeb00b41 vmov.f64 d0, d1");
@@ -440,6 +440,11 @@ TEST(Vfp) {
COMPARE(vabs(d3, d4, mi),
"4eb03bc4 vabsmi d3, d4");
+ COMPARE(vneg(d0, d1),
+ "eeb10b41 vneg d0, d1");
+ COMPARE(vneg(d3, d4, mi),
+ "4eb13b44 vnegmi d3, d4");
+
COMPARE(vadd(d0, d1, d2),
"ee310b02 vadd.f64 d0, d1, d2");
COMPARE(vadd(d3, d4, d5, mi),
diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc
index c995aa8e..26da5c9c 100644
--- a/test/cctest/test-disasm-ia32.cc
+++ b/test/cctest/test-disasm-ia32.cc
@@ -68,7 +68,7 @@ TEST(DisasmIa320) {
__ sub(Operand(eax), Immediate(12345678));
__ xor_(eax, 12345678);
__ and_(eax, 12345678);
- Handle<FixedArray> foo = Factory::NewFixedArray(10, TENURED);
+ Handle<FixedArray> foo = FACTORY->NewFixedArray(10, TENURED);
__ cmp(eax, foo);
// ---- This one caused crash
@@ -99,7 +99,7 @@ TEST(DisasmIa320) {
__ cmp(edx, 3);
__ cmp(edx, Operand(esp, 4));
__ cmp(Operand(ebp, ecx, times_4, 0), Immediate(1000));
- Handle<FixedArray> foo2 = Factory::NewFixedArray(10, TENURED);
+ Handle<FixedArray> foo2 = FACTORY->NewFixedArray(10, TENURED);
__ cmp(ebx, foo2);
__ cmpb(ebx, Operand(ebp, ecx, times_2, 0));
__ cmpb(Operand(ebp, ecx, times_2, 0), ebx);
@@ -107,12 +107,12 @@ TEST(DisasmIa320) {
__ xor_(edx, 3);
__ nop();
{
- CHECK(CpuFeatures::IsSupported(CPUID));
+ CHECK(Isolate::Current()->cpu_features()->IsSupported(CPUID));
CpuFeatures::Scope fscope(CPUID);
__ cpuid();
}
{
- CHECK(CpuFeatures::IsSupported(RDTSC));
+ CHECK(Isolate::Current()->cpu_features()->IsSupported(RDTSC));
CpuFeatures::Scope fscope(RDTSC);
__ rdtsc();
}
@@ -272,7 +272,8 @@ TEST(DisasmIa320) {
__ bind(&L2);
__ call(Operand(ebx, ecx, times_4, 10000));
__ nop();
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
__ nop();
__ call(FUNCTION_ADDR(DummyStaticFunction), RelocInfo::RUNTIME_ENTRY);
@@ -282,7 +283,8 @@ TEST(DisasmIa320) {
__ jmp(Operand(ebx, ecx, times_4, 10000));
#ifdef ENABLE_DEBUGGER_SUPPORT
ExternalReference after_break_target =
- ExternalReference(Debug_Address::AfterBreakTarget());
+ ExternalReference(Debug_Address::AfterBreakTarget(),
+ assm.isolate());
__ jmp(Operand::StaticVariable(after_break_target));
#endif // ENABLE_DEBUGGER_SUPPORT
__ jmp(ic, RelocInfo::CODE_TARGET);
@@ -332,7 +334,7 @@ TEST(DisasmIa320) {
__ j(zero, &Ljcc, taken);
__ j(zero, &Ljcc, not_taken);
- // __ mov(Operand::StaticVariable(Top::handler_address()), eax);
+ // __ mov(Operand::StaticVariable(Isolate::handler_address()), eax);
// 0xD9 instructions
__ nop();
@@ -373,7 +375,7 @@ TEST(DisasmIa320) {
__ fwait();
__ nop();
{
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope fscope(SSE2);
__ cvttss2si(edx, Operand(ebx, ecx, times_4, 10000));
__ cvtsi2sd(xmm1, Operand(ebx, ecx, times_4, 10000));
@@ -395,7 +397,7 @@ TEST(DisasmIa320) {
// cmov.
{
- if (CpuFeatures::IsSupported(CMOV)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(CMOV)) {
CpuFeatures::Scope use_cmov(CMOV);
__ cmov(overflow, eax, Operand(eax, 0));
__ cmov(no_overflow, eax, Operand(eax, 1));
@@ -418,7 +420,7 @@ TEST(DisasmIa320) {
// andpd, cmpltsd, movaps, psllq, psrlq, por.
{
- if (CpuFeatures::IsSupported(SSE2)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) {
CpuFeatures::Scope fscope(SSE2);
__ andpd(xmm0, xmm1);
__ andpd(xmm1, xmm2);
@@ -447,7 +449,7 @@ TEST(DisasmIa320) {
}
{
- if (CpuFeatures::IsSupported(SSE4_1)) {
+ if (Isolate::Current()->cpu_features()->IsSupported(SSE4_1)) {
CpuFeatures::Scope scope(SSE4_1);
__ pextrd(Operand(eax), xmm0, 1);
__ pinsrd(xmm1, Operand(eax), 0);
@@ -458,10 +460,10 @@ TEST(DisasmIa320) {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef OBJECT_PRINT
Code::cast(code)->Print();
diff --git a/test/cctest/test-func-name-inference.cc b/test/cctest/test-func-name-inference.cc
index 563cc4bf..dea5c477 100644
--- a/test/cctest/test-func-name-inference.cc
+++ b/test/cctest/test-func-name-inference.cc
@@ -36,6 +36,7 @@ using ::v8::internal::CStrVector;
using ::v8::internal::Factory;
using ::v8::internal::Handle;
using ::v8::internal::Heap;
+using ::v8::internal::Isolate;
using ::v8::internal::JSFunction;
using ::v8::internal::Object;
using ::v8::internal::Runtime;
@@ -77,15 +78,20 @@ static void CheckFunctionName(v8::Handle<v8::Script> script,
// Find the position of a given func source substring in the source.
Handle<String> func_pos_str =
- Factory::NewStringFromAscii(CStrVector(func_pos_src));
- int func_pos = Runtime::StringMatch(script_src, func_pos_str, 0);
+ FACTORY->NewStringFromAscii(CStrVector(func_pos_src));
+ int func_pos = Runtime::StringMatch(Isolate::Current(),
+ script_src,
+ func_pos_str,
+ 0);
CHECK_NE(0, func_pos);
#ifdef ENABLE_DEBUGGER_SUPPORT
// Obtain SharedFunctionInfo for the function.
Object* shared_func_info_ptr =
- Runtime::FindSharedFunctionInfoInScript(i_script, func_pos);
- CHECK(shared_func_info_ptr != Heap::undefined_value());
+ Runtime::FindSharedFunctionInfoInScript(Isolate::Current(),
+ i_script,
+ func_pos);
+ CHECK(shared_func_info_ptr != HEAP->undefined_value());
Handle<SharedFunctionInfo> shared_func_info(
SharedFunctionInfo::cast(shared_func_info_ptr));
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index ad242fe7..141b42f7 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -26,7 +26,7 @@ class ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
public:
ConstructorHeapProfileTestHelper()
: i::ConstructorHeapProfile(),
- f_name_(i::Factory::NewStringFromAscii(i::CStrVector("F"))),
+ f_name_(FACTORY->NewStringFromAscii(i::CStrVector("F"))),
f_count_(0) {
}
@@ -143,25 +143,25 @@ TEST(ClustersCoarserSimple) {
i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
JSObjectsRetainerTree tree;
- JSObjectsCluster function(i::Heap::function_class_symbol());
- JSObjectsCluster a(*i::Factory::NewStringFromAscii(i::CStrVector("A")));
- JSObjectsCluster b(*i::Factory::NewStringFromAscii(i::CStrVector("B")));
+ JSObjectsCluster function(HEAP->function_class_symbol());
+ JSObjectsCluster a(*FACTORY->NewStringFromAscii(i::CStrVector("A")));
+ JSObjectsCluster b(*FACTORY->NewStringFromAscii(i::CStrVector("B")));
// o1 <- Function
JSObjectsCluster o1 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
// o2 <- Function
JSObjectsCluster o2 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
// o3 <- A, B
JSObjectsCluster o3 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &a, &b);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &a, &b);
// o4 <- B, A
JSObjectsCluster o4 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x400, &b, &a);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x400, &b, &a);
// o5 <- A, B, Function
JSObjectsCluster o5 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x500,
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x500,
&a, &b, &function);
ClustersCoarser coarser;
@@ -181,20 +181,20 @@ TEST(ClustersCoarserMultipleConstructors) {
i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
JSObjectsRetainerTree tree;
- JSObjectsCluster function(i::Heap::function_class_symbol());
+ JSObjectsCluster function(HEAP->function_class_symbol());
// o1 <- Function
JSObjectsCluster o1 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
// a1 <- Function
JSObjectsCluster a1 =
- AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x1000, &function);
+ AddHeapObjectToTree(&tree, HEAP->Array_symbol(), 0x1000, &function);
// o2 <- Function
JSObjectsCluster o2 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
// a2 <- Function
JSObjectsCluster a2 =
- AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x2000, &function);
+ AddHeapObjectToTree(&tree, HEAP->Array_symbol(), 0x2000, &function);
ClustersCoarser coarser;
coarser.Process(&tree);
@@ -224,21 +224,21 @@ TEST(ClustersCoarserPathsTraversal) {
// o21 ~ o22, and o11 ~ o12.
JSObjectsCluster o =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
JSObjectsCluster o11 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
JSObjectsCluster o12 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
JSObjectsCluster o21 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x210, &o11);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x210, &o11);
JSObjectsCluster o22 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x220, &o12);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x220, &o12);
JSObjectsCluster p =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o21);
JSObjectsCluster q =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o21, &o22);
JSObjectsCluster r =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x320, &o22);
ClustersCoarser coarser;
coarser.Process(&tree);
@@ -275,19 +275,19 @@ TEST(ClustersCoarserSelf) {
// we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2;
JSObjectsCluster o =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
JSObjectsCluster o1 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
JSObjectsCluster o2 =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
JSObjectsCluster p =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o1);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o1);
AddSelfReferenceToTree(&tree, &p);
JSObjectsCluster q =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o1, &o2);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o1, &o2);
AddSelfReferenceToTree(&tree, &q);
JSObjectsCluster r =
- AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o2);
+ AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x320, &o2);
AddSelfReferenceToTree(&tree, &r);
ClustersCoarser coarser;
@@ -433,19 +433,6 @@ static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
}
-static bool IsNodeRetainedAs(const v8::HeapGraphNode* node,
- v8::HeapGraphEdge::Type type,
- const char* name) {
- for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) {
- const v8::HeapGraphEdge* prop = node->GetRetainer(i);
- v8::String::AsciiValue prop_name(prop->GetName());
- if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
- return true;
- }
- return false;
-}
-
-
static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
const v8::HeapGraphEdge* prop = node->GetChild(i);
@@ -496,56 +483,6 @@ TEST(HeapSnapshot) {
CHECK(det.has_A2);
CHECK(det.has_B2);
CHECK(det.has_C2);
-
- /*
- // Currently disabled. Too many retaining paths emerge, need to
- // reduce the amount.
-
- // Verify 'a2' object retainers. They are:
- // - (global object).a2
- // - c2.x1, c2.x2, c2[1]
- // - b2_1 and b2_2 closures: via 'x' variable
- CHECK_EQ(6, a2_node->GetRetainingPathsCount());
- bool has_global_obj_a2_ref = false;
- bool has_c2_x1_ref = false, has_c2_x2_ref = false, has_c2_1_ref = false;
- bool has_b2_1_x_ref = false, has_b2_2_x_ref = false;
- for (int i = 0; i < a2_node->GetRetainingPathsCount(); ++i) {
- const v8::HeapGraphPath* path = a2_node->GetRetainingPath(i);
- const int edges_count = path->GetEdgesCount();
- CHECK_GT(edges_count, 0);
- const v8::HeapGraphEdge* last_edge = path->GetEdge(edges_count - 1);
- v8::String::AsciiValue last_edge_name(last_edge->GetName());
- if (strcmp("a2", *last_edge_name) == 0
- && last_edge->GetType() == v8::HeapGraphEdge::kProperty) {
- has_global_obj_a2_ref = true;
- continue;
- }
- CHECK_GT(edges_count, 1);
- const v8::HeapGraphEdge* prev_edge = path->GetEdge(edges_count - 2);
- v8::String::AsciiValue prev_edge_name(prev_edge->GetName());
- if (strcmp("x1", *last_edge_name) == 0
- && last_edge->GetType() == v8::HeapGraphEdge::kProperty
- && strcmp("c2", *prev_edge_name) == 0) has_c2_x1_ref = true;
- if (strcmp("x2", *last_edge_name) == 0
- && last_edge->GetType() == v8::HeapGraphEdge::kProperty
- && strcmp("c2", *prev_edge_name) == 0) has_c2_x2_ref = true;
- if (strcmp("1", *last_edge_name) == 0
- && last_edge->GetType() == v8::HeapGraphEdge::kElement
- && strcmp("c2", *prev_edge_name) == 0) has_c2_1_ref = true;
- if (strcmp("x", *last_edge_name) == 0
- && last_edge->GetType() == v8::HeapGraphEdge::kContextVariable
- && strcmp("b2_1", *prev_edge_name) == 0) has_b2_1_x_ref = true;
- if (strcmp("x", *last_edge_name) == 0
- && last_edge->GetType() == v8::HeapGraphEdge::kContextVariable
- && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true;
- }
- CHECK(has_global_obj_a2_ref);
- CHECK(has_c2_x1_ref);
- CHECK(has_c2_x2_ref);
- CHECK(has_c2_1_ref);
- CHECK(has_b2_1_x_ref);
- CHECK(has_b2_2_x_ref);
- */
}
@@ -730,7 +667,7 @@ TEST(HeapEntryIdsAndGC) {
const v8::HeapSnapshot* snapshot1 =
v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
- i::Heap::CollectAllGarbage(true); // Enforce compaction.
+ HEAP->CollectAllGarbage(true); // Enforce compaction.
const v8::HeapSnapshot* snapshot2 =
v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
@@ -774,76 +711,6 @@ TEST(HeapEntryIdsAndGC) {
}
-TEST(HeapSnapshotsDiff) {
- v8::HandleScope scope;
- LocalContext env;
-
- CompileRun(
- "function A() {}\n"
- "function B(x) { this.x = x; }\n"
- "function A2(a) { for (var i = 0; i < a; ++i) this[i] = i; }\n"
- "var a = new A();\n"
- "var b = new B(a);");
- const v8::HeapSnapshot* snapshot1 =
- v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
-
- CompileRun(
- "delete a;\n"
- "b.x = null;\n"
- "var a = new A2(20);\n"
- "var b2 = new B(a);");
- const v8::HeapSnapshot* snapshot2 =
- v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
-
- const v8::HeapSnapshotsDiff* diff = snapshot1->CompareWith(snapshot2);
-
- // Verify additions: ensure that addition of A and B was detected.
- const v8::HeapGraphNode* additions_root = diff->GetAdditionsRoot();
- bool found_A = false, found_B = false;
- uint64_t s1_A_id = 0;
- for (int i = 0, count = additions_root->GetChildrenCount(); i < count; ++i) {
- const v8::HeapGraphEdge* prop = additions_root->GetChild(i);
- const v8::HeapGraphNode* node = prop->GetToNode();
- if (node->GetType() == v8::HeapGraphNode::kObject) {
- v8::String::AsciiValue node_name(node->GetName());
- if (strcmp(*node_name, "A2") == 0) {
- CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a"));
- CHECK(!found_A);
- found_A = true;
- s1_A_id = node->GetId();
- } else if (strcmp(*node_name, "B") == 0) {
- CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "b2"));
- CHECK(!found_B);
- found_B = true;
- }
- }
- }
- CHECK(found_A);
- CHECK(found_B);
-
- // Verify deletions: ensure that deletion of A was detected.
- const v8::HeapGraphNode* deletions_root = diff->GetDeletionsRoot();
- bool found_A_del = false;
- uint64_t s2_A_id = 0;
- for (int i = 0, count = deletions_root->GetChildrenCount(); i < count; ++i) {
- const v8::HeapGraphEdge* prop = deletions_root->GetChild(i);
- const v8::HeapGraphNode* node = prop->GetToNode();
- if (node->GetType() == v8::HeapGraphNode::kObject) {
- v8::String::AsciiValue node_name(node->GetName());
- if (strcmp(*node_name, "A") == 0) {
- CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a"));
- CHECK(!found_A_del);
- found_A_del = true;
- s2_A_id = node->GetId();
- }
- }
- }
- CHECK(found_A_del);
- CHECK_NE_UINT64_T(0, s1_A_id);
- CHECK(s1_A_id != s2_A_id);
-}
-
-
TEST(HeapSnapshotRootPreservedAfterSorting) {
v8::HandleScope scope;
LocalContext env;
@@ -1258,4 +1125,199 @@ TEST(TakeHeapSnapshotAborting) {
CHECK_GT(control.total(), 0);
}
+
+namespace {
+
+class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
+ public:
+ TestRetainedObjectInfo(int hash,
+ const char* label,
+ intptr_t element_count = -1,
+ intptr_t size = -1)
+ : disposed_(false),
+ hash_(hash),
+ label_(label),
+ element_count_(element_count),
+ size_(size) {
+ instances.Add(this);
+ }
+ virtual ~TestRetainedObjectInfo() {}
+ virtual void Dispose() {
+ CHECK(!disposed_);
+ disposed_ = true;
+ }
+ virtual bool IsEquivalent(RetainedObjectInfo* other) {
+ return GetHash() == other->GetHash();
+ }
+ virtual intptr_t GetHash() { return hash_; }
+ virtual const char* GetLabel() { return label_; }
+ virtual intptr_t GetElementCount() { return element_count_; }
+ virtual intptr_t GetSizeInBytes() { return size_; }
+ bool disposed() { return disposed_; }
+
+ static v8::RetainedObjectInfo* WrapperInfoCallback(
+ uint16_t class_id, v8::Handle<v8::Value> wrapper) {
+ if (class_id == 1) {
+ if (wrapper->IsString()) {
+ v8::String::AsciiValue ascii(wrapper);
+ if (strcmp(*ascii, "AAA") == 0)
+ return new TestRetainedObjectInfo(1, "aaa", 100);
+ else if (strcmp(*ascii, "BBB") == 0)
+ return new TestRetainedObjectInfo(1, "aaa", 100);
+ }
+ } else if (class_id == 2) {
+ if (wrapper->IsString()) {
+ v8::String::AsciiValue ascii(wrapper);
+ if (strcmp(*ascii, "CCC") == 0)
+ return new TestRetainedObjectInfo(2, "ccc");
+ }
+ }
+ CHECK(false);
+ return NULL;
+ }
+
+ static i::List<TestRetainedObjectInfo*> instances;
+
+ private:
+ bool disposed_;
+ int category_;
+ int hash_;
+ const char* label_;
+ intptr_t element_count_;
+ intptr_t size_;
+};
+
+
+i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
+}
+
+
+static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
+ v8::HeapGraphNode::Type type,
+ const char* name) {
+ for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
+ if (node->GetType() == type && strcmp(name,
+ const_cast<i::HeapEntry*>(
+ reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
+ return node;
+ }
+ }
+ return NULL;
+}
+
+
+TEST(HeapSnapshotRetainedObjectInfo) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ v8::HeapProfiler::DefineWrapperClass(
+ 1, TestRetainedObjectInfo::WrapperInfoCallback);
+ v8::HeapProfiler::DefineWrapperClass(
+ 2, TestRetainedObjectInfo::WrapperInfoCallback);
+ v8::Persistent<v8::String> p_AAA =
+ v8::Persistent<v8::String>::New(v8_str("AAA"));
+ p_AAA.SetWrapperClassId(1);
+ v8::Persistent<v8::String> p_BBB =
+ v8::Persistent<v8::String>::New(v8_str("BBB"));
+ p_BBB.SetWrapperClassId(1);
+ v8::Persistent<v8::String> p_CCC =
+ v8::Persistent<v8::String>::New(v8_str("CCC"));
+ p_CCC.SetWrapperClassId(2);
+ CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("retained"));
+
+ CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
+ for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
+ CHECK(TestRetainedObjectInfo::instances[i]->disposed());
+ delete TestRetainedObjectInfo::instances[i];
+ }
+
+ const v8::HeapGraphNode* natives = GetNode(
+ snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(Native objects)");
+ CHECK_NE(NULL, natives);
+ CHECK_EQ(2, natives->GetChildrenCount());
+ const v8::HeapGraphNode* aaa = GetNode(
+ natives, v8::HeapGraphNode::kNative, "aaa / 100 entries");
+ CHECK_NE(NULL, aaa);
+ const v8::HeapGraphNode* ccc = GetNode(
+ natives, v8::HeapGraphNode::kNative, "ccc");
+ CHECK_NE(NULL, ccc);
+
+ CHECK_EQ(2, aaa->GetChildrenCount());
+ const v8::HeapGraphNode* n_AAA = GetNode(
+ aaa, v8::HeapGraphNode::kString, "AAA");
+ CHECK_NE(NULL, n_AAA);
+ const v8::HeapGraphNode* n_BBB = GetNode(
+ aaa, v8::HeapGraphNode::kString, "BBB");
+ CHECK_NE(NULL, n_BBB);
+ CHECK_EQ(1, ccc->GetChildrenCount());
+ const v8::HeapGraphNode* n_CCC = GetNode(
+ ccc, v8::HeapGraphNode::kString, "CCC");
+ CHECK_NE(NULL, n_CCC);
+
+ CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "Native"));
+ CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "Native"));
+ CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "Native"));
+}
+
+
+TEST(DeleteAllHeapSnapshots) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
+ v8::HeapProfiler::DeleteAllSnapshots();
+ CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
+ CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("1")));
+ CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
+ v8::HeapProfiler::DeleteAllSnapshots();
+ CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
+ CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("1")));
+ CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("2")));
+ CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
+ v8::HeapProfiler::DeleteAllSnapshots();
+ CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
+}
+
+
+TEST(DeleteHeapSnapshot) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
+ const v8::HeapSnapshot* s1 =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("1"));
+ CHECK_NE(NULL, s1);
+ CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
+ unsigned uid1 = s1->GetUid();
+ CHECK_EQ(s1, v8::HeapProfiler::FindSnapshot(uid1));
+ const_cast<v8::HeapSnapshot*>(s1)->Delete();
+ CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
+ CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid1));
+
+ const v8::HeapSnapshot* s2 =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("2"));
+ CHECK_NE(NULL, s2);
+ CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
+ unsigned uid2 = s2->GetUid();
+ CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
+ CHECK_EQ(s2, v8::HeapProfiler::FindSnapshot(uid2));
+ const v8::HeapSnapshot* s3 =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("3"));
+ CHECK_NE(NULL, s3);
+ CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
+ unsigned uid3 = s3->GetUid();
+ CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
+ CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
+ const_cast<v8::HeapSnapshot*>(s2)->Delete();
+ CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
+ CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid2));
+ CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
+ const_cast<v8::HeapSnapshot*>(s3)->Delete();
+ CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
+ CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3));
+}
+
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 4cc7f8ba..86860ce0 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -24,9 +24,9 @@ static void InitializeVM() {
static void CheckMap(Map* map, int type, int instance_size) {
CHECK(map->IsHeapObject());
#ifdef DEBUG
- CHECK(Heap::Contains(map));
+ CHECK(HEAP->Contains(map));
#endif
- CHECK_EQ(Heap::meta_map(), map->map());
+ CHECK_EQ(HEAP->meta_map(), map->map());
CHECK_EQ(type, map->instance_type());
CHECK_EQ(instance_size, map->instance_size());
}
@@ -34,10 +34,10 @@ static void CheckMap(Map* map, int type, int instance_size) {
TEST(HeapMaps) {
InitializeVM();
- CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize);
- CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
- CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
- CheckMap(Heap::string_map(), STRING_TYPE, kVariableSizeSentinel);
+ CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
+ CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
+ CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
+ CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
}
@@ -58,7 +58,7 @@ static void CheckSmi(int value, const char* string) {
static void CheckNumber(double value, const char* string) {
- Object* obj = Heap::NumberFromDouble(value)->ToObjectChecked();
+ Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
CHECK(obj->IsNumber());
bool exc;
Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
@@ -76,27 +76,27 @@ static void CheckFindCodeObject() {
CodeDesc desc;
assm.GetCode(&desc);
- Object* code = Heap::CreateCode(
+ Object* code = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
HeapObject* obj = HeapObject::cast(code);
Address obj_addr = obj->address();
for (int i = 0; i < obj->Size(); i += kPointerSize) {
- Object* found = Heap::FindCodeObject(obj_addr + i);
+ Object* found = HEAP->FindCodeObject(obj_addr + i);
CHECK_EQ(code, found);
}
- Object* copy = Heap::CreateCode(
+ Object* copy = HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
- Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
CHECK(copy->IsCode());
HeapObject* obj_copy = HeapObject::cast(copy);
- Object* not_right = Heap::FindCodeObject(obj_copy->address() +
+ Object* not_right = HEAP->FindCodeObject(obj_copy->address() +
obj_copy->Size() / 2);
CHECK(not_right != code);
}
@@ -106,41 +106,41 @@ TEST(HeapObjects) {
InitializeVM();
v8::HandleScope sc;
- Object* value = Heap::NumberFromDouble(1.000123)->ToObjectChecked();
+ Object* value = HEAP->NumberFromDouble(1.000123)->ToObjectChecked();
CHECK(value->IsHeapNumber());
CHECK(value->IsNumber());
CHECK_EQ(1.000123, value->Number());
- value = Heap::NumberFromDouble(1.0)->ToObjectChecked();
+ value = HEAP->NumberFromDouble(1.0)->ToObjectChecked();
CHECK(value->IsSmi());
CHECK(value->IsNumber());
CHECK_EQ(1.0, value->Number());
- value = Heap::NumberFromInt32(1024)->ToObjectChecked();
+ value = HEAP->NumberFromInt32(1024)->ToObjectChecked();
CHECK(value->IsSmi());
CHECK(value->IsNumber());
CHECK_EQ(1024.0, value->Number());
- value = Heap::NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
+ value = HEAP->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
CHECK(value->IsSmi());
CHECK(value->IsNumber());
CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
- value = Heap::NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
+ value = HEAP->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
CHECK(value->IsSmi());
CHECK(value->IsNumber());
CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
#ifndef V8_TARGET_ARCH_X64
// TODO(lrn): We need a NumberFromIntptr function in order to test this.
- value = Heap::NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
+ value = HEAP->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
CHECK(value->IsHeapNumber());
CHECK(value->IsNumber());
CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
#endif
MaybeObject* maybe_value =
- Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
+ HEAP->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
value = maybe_value->ToObjectChecked();
CHECK(value->IsHeapNumber());
CHECK(value->IsNumber());
@@ -148,21 +148,22 @@ TEST(HeapObjects) {
value->Number());
// nan oddball checks
- CHECK(Heap::nan_value()->IsNumber());
- CHECK(isnan(Heap::nan_value()->Number()));
+ CHECK(HEAP->nan_value()->IsNumber());
+ CHECK(isnan(HEAP->nan_value()->Number()));
- Handle<String> s = Factory::NewStringFromAscii(CStrVector("fisk hest "));
+ Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
CHECK(s->IsString());
CHECK_EQ(10, s->length());
- String* object_symbol = String::cast(Heap::Object_symbol());
- CHECK(Top::context()->global()->HasLocalProperty(object_symbol));
+ String* object_symbol = String::cast(HEAP->Object_symbol());
+ CHECK(
+ Isolate::Current()->context()->global()->HasLocalProperty(object_symbol));
// Check ToString for oddballs
- CheckOddball(Heap::true_value(), "true");
- CheckOddball(Heap::false_value(), "false");
- CheckOddball(Heap::null_value(), "null");
- CheckOddball(Heap::undefined_value(), "undefined");
+ CheckOddball(HEAP->true_value(), "true");
+ CheckOddball(HEAP->false_value(), "false");
+ CheckOddball(HEAP->null_value(), "null");
+ CheckOddball(HEAP->undefined_value(), "undefined");
// Check ToString for Smis
CheckSmi(0, "0");
@@ -197,25 +198,25 @@ TEST(GarbageCollection) {
v8::HandleScope sc;
// Check GC.
- Heap::CollectGarbage(NEW_SPACE);
+ HEAP->CollectGarbage(NEW_SPACE);
- Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
- Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
- Handle<String> prop_namex = Factory::LookupAsciiSymbol("theSlotx");
- Handle<String> obj_name = Factory::LookupAsciiSymbol("theObject");
+ Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
+ Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
+ Handle<String> prop_namex = FACTORY->LookupAsciiSymbol("theSlotx");
+ Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject");
{
v8::HandleScope inner_scope;
// Allocate a function and keep it in global object's property.
Handle<JSFunction> function =
- Factory::NewFunction(name, Factory::undefined_value());
+ FACTORY->NewFunction(name, FACTORY->undefined_value());
Handle<Map> initial_map =
- Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
function->set_initial_map(*initial_map);
- Top::context()->global()->SetProperty(
+ Isolate::Current()->context()->global()->SetProperty(
*name, *function, NONE, kNonStrictMode)->ToObjectChecked();
// Allocate an object. Unrooted after leaving the scope.
- Handle<JSObject> obj = Factory::NewJSObject(function);
+ Handle<JSObject> obj = FACTORY->NewJSObject(function);
obj->SetProperty(
*prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
obj->SetProperty(
@@ -225,34 +226,34 @@ TEST(GarbageCollection) {
CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
}
- Heap::CollectGarbage(NEW_SPACE);
+ HEAP->CollectGarbage(NEW_SPACE);
// Function should be alive.
- CHECK(Top::context()->global()->HasLocalProperty(*name));
+ CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*name));
// Check function is retained.
- Object* func_value =
- Top::context()->global()->GetProperty(*name)->ToObjectChecked();
+ Object* func_value = Isolate::Current()->context()->global()->
+ GetProperty(*name)->ToObjectChecked();
CHECK(func_value->IsJSFunction());
Handle<JSFunction> function(JSFunction::cast(func_value));
{
HandleScope inner_scope;
// Allocate another object, make it reachable from global.
- Handle<JSObject> obj = Factory::NewJSObject(function);
- Top::context()->global()->SetProperty(
+ Handle<JSObject> obj = FACTORY->NewJSObject(function);
+ Isolate::Current()->context()->global()->SetProperty(
*obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
obj->SetProperty(
*prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
}
// After gc, it should survive.
- Heap::CollectGarbage(NEW_SPACE);
+ HEAP->CollectGarbage(NEW_SPACE);
- CHECK(Top::context()->global()->HasLocalProperty(*obj_name));
- CHECK(Top::context()->global()->GetProperty(*obj_name)->ToObjectChecked()->
- IsJSObject());
- Object* obj =
- Top::context()->global()->GetProperty(*obj_name)->ToObjectChecked();
+ CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*obj_name));
+ CHECK(Isolate::Current()->context()->global()->
+ GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
+ Object* obj = Isolate::Current()->context()->global()->
+ GetProperty(*obj_name)->ToObjectChecked();
JSObject* js_obj = JSObject::cast(obj);
CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
}
@@ -260,7 +261,7 @@ TEST(GarbageCollection) {
static void VerifyStringAllocation(const char* string) {
v8::HandleScope scope;
- Handle<String> s = Factory::NewStringFromUtf8(CStrVector(string));
+ Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
CHECK_EQ(StrLength(string), s->length());
for (int index = 0; index < s->length(); index++) {
CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
@@ -284,12 +285,13 @@ TEST(LocalHandles) {
v8::HandleScope scope;
const char* name = "Kasper the spunky";
- Handle<String> string = Factory::NewStringFromAscii(CStrVector(name));
+ Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
CHECK_EQ(StrLength(name), string->length());
}
TEST(GlobalHandles) {
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
InitializeVM();
Handle<Object> h1;
@@ -300,17 +302,17 @@ TEST(GlobalHandles) {
{
HandleScope scope;
- Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
- Handle<Object> u = Factory::NewNumber(1.12344);
+ Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
+ Handle<Object> u = FACTORY->NewNumber(1.12344);
- h1 = GlobalHandles::Create(*i);
- h2 = GlobalHandles::Create(*u);
- h3 = GlobalHandles::Create(*i);
- h4 = GlobalHandles::Create(*u);
+ h1 = global_handles->Create(*i);
+ h2 = global_handles->Create(*u);
+ h3 = global_handles->Create(*i);
+ h4 = global_handles->Create(*u);
}
// after gc, it should survive
- Heap::CollectGarbage(NEW_SPACE);
+ HEAP->CollectGarbage(NEW_SPACE);
CHECK((*h1)->IsString());
CHECK((*h2)->IsHeapNumber());
@@ -318,12 +320,12 @@ TEST(GlobalHandles) {
CHECK((*h4)->IsHeapNumber());
CHECK_EQ(*h3, *h1);
- GlobalHandles::Destroy(h1.location());
- GlobalHandles::Destroy(h3.location());
+ global_handles->Destroy(h1.location());
+ global_handles->Destroy(h3.location());
CHECK_EQ(*h4, *h2);
- GlobalHandles::Destroy(h2.location());
- GlobalHandles::Destroy(h4.location());
+ global_handles->Destroy(h2.location());
+ global_handles->Destroy(h4.location());
}
@@ -337,6 +339,7 @@ static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
TEST(WeakGlobalHandlesScavenge) {
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
InitializeVM();
WeakPointerCleared = false;
@@ -347,33 +350,34 @@ TEST(WeakGlobalHandlesScavenge) {
{
HandleScope scope;
- Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
- Handle<Object> u = Factory::NewNumber(1.12344);
+ Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
+ Handle<Object> u = FACTORY->NewNumber(1.12344);
- h1 = GlobalHandles::Create(*i);
- h2 = GlobalHandles::Create(*u);
+ h1 = global_handles->Create(*i);
+ h2 = global_handles->Create(*u);
}
- GlobalHandles::MakeWeak(h2.location(),
- reinterpret_cast<void*>(1234),
- &TestWeakGlobalHandleCallback);
+ global_handles->MakeWeak(h2.location(),
+ reinterpret_cast<void*>(1234),
+ &TestWeakGlobalHandleCallback);
// Scavenge treats weak pointers as normal roots.
- Heap::PerformScavenge();
+ HEAP->PerformScavenge();
CHECK((*h1)->IsString());
CHECK((*h2)->IsHeapNumber());
CHECK(!WeakPointerCleared);
- CHECK(!GlobalHandles::IsNearDeath(h2.location()));
- CHECK(!GlobalHandles::IsNearDeath(h1.location()));
+ CHECK(!global_handles->IsNearDeath(h2.location()));
+ CHECK(!global_handles->IsNearDeath(h1.location()));
- GlobalHandles::Destroy(h1.location());
- GlobalHandles::Destroy(h2.location());
+ global_handles->Destroy(h1.location());
+ global_handles->Destroy(h2.location());
}
TEST(WeakGlobalHandlesMark) {
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
InitializeVM();
WeakPointerCleared = false;
@@ -384,34 +388,35 @@ TEST(WeakGlobalHandlesMark) {
{
HandleScope scope;
- Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
- Handle<Object> u = Factory::NewNumber(1.12344);
+ Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
+ Handle<Object> u = FACTORY->NewNumber(1.12344);
- h1 = GlobalHandles::Create(*i);
- h2 = GlobalHandles::Create(*u);
+ h1 = global_handles->Create(*i);
+ h2 = global_handles->Create(*u);
}
- Heap::CollectGarbage(OLD_POINTER_SPACE);
- Heap::CollectGarbage(NEW_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(NEW_SPACE);
// Make sure the object is promoted.
- GlobalHandles::MakeWeak(h2.location(),
- reinterpret_cast<void*>(1234),
- &TestWeakGlobalHandleCallback);
+ global_handles->MakeWeak(h2.location(),
+ reinterpret_cast<void*>(1234),
+ &TestWeakGlobalHandleCallback);
CHECK(!GlobalHandles::IsNearDeath(h1.location()));
CHECK(!GlobalHandles::IsNearDeath(h2.location()));
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
CHECK((*h1)->IsString());
CHECK(WeakPointerCleared);
CHECK(!GlobalHandles::IsNearDeath(h1.location()));
- GlobalHandles::Destroy(h1.location());
+ global_handles->Destroy(h1.location());
}
TEST(DeleteWeakGlobalHandle) {
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
InitializeVM();
WeakPointerCleared = false;
@@ -421,21 +426,21 @@ TEST(DeleteWeakGlobalHandle) {
{
HandleScope scope;
- Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
- h = GlobalHandles::Create(*i);
+ Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
+ h = global_handles->Create(*i);
}
- GlobalHandles::MakeWeak(h.location(),
- reinterpret_cast<void*>(1234),
- &TestWeakGlobalHandleCallback);
+ global_handles->MakeWeak(h.location(),
+ reinterpret_cast<void*>(1234),
+ &TestWeakGlobalHandleCallback);
// Scanvenge does not recognize weak reference.
- Heap::PerformScavenge();
+ HEAP->PerformScavenge();
CHECK(!WeakPointerCleared);
// Mark-compact treats weak reference properly.
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
CHECK(WeakPointerCleared);
}
@@ -507,12 +512,12 @@ static const char* not_so_random_string_table[] = {
static void CheckSymbols(const char** strings) {
for (const char* string = *strings; *strings != 0; string = *strings++) {
Object* a;
- MaybeObject* maybe_a = Heap::LookupAsciiSymbol(string);
+ MaybeObject* maybe_a = HEAP->LookupAsciiSymbol(string);
// LookupAsciiSymbol may return a failure if a GC is needed.
if (!maybe_a->ToObject(&a)) continue;
CHECK(a->IsSymbol());
Object* b;
- MaybeObject *maybe_b = Heap::LookupAsciiSymbol(string);
+ MaybeObject* maybe_b = HEAP->LookupAsciiSymbol(string);
if (!maybe_b->ToObject(&b)) continue;
CHECK_EQ(b, a);
CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
@@ -532,15 +537,15 @@ TEST(FunctionAllocation) {
InitializeVM();
v8::HandleScope sc;
- Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
+ Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
Handle<JSFunction> function =
- Factory::NewFunction(name, Factory::undefined_value());
+ FACTORY->NewFunction(name, FACTORY->undefined_value());
Handle<Map> initial_map =
- Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
function->set_initial_map(*initial_map);
- Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
- Handle<JSObject> obj = Factory::NewJSObject(function);
+ Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
+ Handle<JSObject> obj = FACTORY->NewJSObject(function);
obj->SetProperty(
*prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
@@ -555,14 +560,14 @@ TEST(ObjectProperties) {
InitializeVM();
v8::HandleScope sc;
- String* object_symbol = String::cast(Heap::Object_symbol());
- Object* raw_object =
- Top::context()->global()->GetProperty(object_symbol)->ToObjectChecked();
+ String* object_symbol = String::cast(HEAP->Object_symbol());
+ Object* raw_object = Isolate::Current()->context()->global()->
+ GetProperty(object_symbol)->ToObjectChecked();
JSFunction* object_function = JSFunction::cast(raw_object);
Handle<JSFunction> constructor(object_function);
- Handle<JSObject> obj = Factory::NewJSObject(constructor);
- Handle<String> first = Factory::LookupAsciiSymbol("first");
- Handle<String> second = Factory::LookupAsciiSymbol("second");
+ Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
+ Handle<String> first = FACTORY->LookupAsciiSymbol("first");
+ Handle<String> second = FACTORY->LookupAsciiSymbol("second");
// check for empty
CHECK(!obj->HasLocalProperty(*first));
@@ -608,18 +613,18 @@ TEST(ObjectProperties) {
// check string and symbol match
static const char* string1 = "fisk";
- Handle<String> s1 = Factory::NewStringFromAscii(CStrVector(string1));
+ Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
obj->SetProperty(
*s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
- Handle<String> s1_symbol = Factory::LookupAsciiSymbol(string1);
+ Handle<String> s1_symbol = FACTORY->LookupAsciiSymbol(string1);
CHECK(obj->HasLocalProperty(*s1_symbol));
// check symbol and string match
static const char* string2 = "fugl";
- Handle<String> s2_symbol = Factory::LookupAsciiSymbol(string2);
+ Handle<String> s2_symbol = FACTORY->LookupAsciiSymbol(string2);
obj->SetProperty(
*s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
- Handle<String> s2 = Factory::NewStringFromAscii(CStrVector(string2));
+ Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
CHECK(obj->HasLocalProperty(*s2));
}
@@ -628,15 +633,15 @@ TEST(JSObjectMaps) {
InitializeVM();
v8::HandleScope sc;
- Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
+ Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
Handle<JSFunction> function =
- Factory::NewFunction(name, Factory::undefined_value());
+ FACTORY->NewFunction(name, FACTORY->undefined_value());
Handle<Map> initial_map =
- Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
function->set_initial_map(*initial_map);
- Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
- Handle<JSObject> obj = Factory::NewJSObject(function);
+ Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
+ Handle<JSObject> obj = FACTORY->NewJSObject(function);
// Set a propery
obj->SetProperty(
@@ -652,14 +657,14 @@ TEST(JSArray) {
InitializeVM();
v8::HandleScope sc;
- Handle<String> name = Factory::LookupAsciiSymbol("Array");
- Object* raw_object =
- Top::context()->global()->GetProperty(*name)->ToObjectChecked();
+ Handle<String> name = FACTORY->LookupAsciiSymbol("Array");
+ Object* raw_object = Isolate::Current()->context()->global()->
+ GetProperty(*name)->ToObjectChecked();
Handle<JSFunction> function = Handle<JSFunction>(
JSFunction::cast(raw_object));
// Allocate the object.
- Handle<JSObject> object = Factory::NewJSObject(function);
+ Handle<JSObject> object = FACTORY->NewJSObject(function);
Handle<JSArray> array = Handle<JSArray>::cast(object);
// We just initialized the VM, no heap allocation failure yet.
Object* ok = array->Initialize(0)->ToObjectChecked();
@@ -676,7 +681,7 @@ TEST(JSArray) {
// Set array length with larger than smi value.
Handle<Object> length =
- Factory::NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
+ FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
ok = array->SetElementsLength(*length)->ToObjectChecked();
uint32_t int_length = 0;
@@ -698,14 +703,14 @@ TEST(JSObjectCopy) {
InitializeVM();
v8::HandleScope sc;
- String* object_symbol = String::cast(Heap::Object_symbol());
- Object* raw_object =
- Top::context()->global()->GetProperty(object_symbol)->ToObjectChecked();
+ String* object_symbol = String::cast(HEAP->Object_symbol());
+ Object* raw_object = Isolate::Current()->context()->global()->
+ GetProperty(object_symbol)->ToObjectChecked();
JSFunction* object_function = JSFunction::cast(raw_object);
Handle<JSFunction> constructor(object_function);
- Handle<JSObject> obj = Factory::NewJSObject(constructor);
- Handle<String> first = Factory::LookupAsciiSymbol("first");
- Handle<String> second = Factory::LookupAsciiSymbol("second");
+ Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
+ Handle<String> first = FACTORY->LookupAsciiSymbol("first");
+ Handle<String> second = FACTORY->LookupAsciiSymbol("second");
obj->SetProperty(
*first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
@@ -761,17 +766,17 @@ TEST(StringAllocation) {
non_ascii[3 * i + 2] = chars[2];
}
Handle<String> non_ascii_sym =
- Factory::LookupSymbol(Vector<const char>(non_ascii, 3 * length));
+ FACTORY->LookupSymbol(Vector<const char>(non_ascii, 3 * length));
CHECK_EQ(length, non_ascii_sym->length());
Handle<String> ascii_sym =
- Factory::LookupSymbol(Vector<const char>(ascii, length));
+ FACTORY->LookupSymbol(Vector<const char>(ascii, length));
CHECK_EQ(length, ascii_sym->length());
Handle<String> non_ascii_str =
- Factory::NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
+ FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
non_ascii_str->Hash();
CHECK_EQ(length, non_ascii_str->length());
Handle<String> ascii_str =
- Factory::NewStringFromUtf8(Vector<const char>(ascii, length));
+ FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
ascii_str->Hash();
CHECK_EQ(length, ascii_str->length());
DeleteArray(non_ascii);
@@ -805,22 +810,22 @@ TEST(Iteration) {
int next_objs_index = 0;
// Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
- objs[next_objs_index++] = Factory::NewJSArray(10);
- objs[next_objs_index++] = Factory::NewJSArray(10, TENURED);
+ objs[next_objs_index++] = FACTORY->NewJSArray(10);
+ objs[next_objs_index++] = FACTORY->NewJSArray(10, TENURED);
// Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
objs[next_objs_index++] =
- Factory::NewStringFromAscii(CStrVector("abcdefghij"));
+ FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
objs[next_objs_index++] =
- Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
+ FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
// Allocate a large string (for large object space).
- int large_size = Heap::MaxObjectSizeInPagedSpace() + 1;
+ int large_size = HEAP->MaxObjectSizeInPagedSpace() + 1;
char* str = new char[large_size];
for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
str[large_size - 1] = '\0';
objs[next_objs_index++] =
- Factory::NewStringFromAscii(CStrVector(str), TENURED);
+ FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
delete[] str;
// Add a Map object to look for.
@@ -834,9 +839,9 @@ TEST(Iteration) {
TEST(LargeObjectSpaceContains) {
InitializeVM();
- Heap::CollectGarbage(NEW_SPACE);
+ HEAP->CollectGarbage(NEW_SPACE);
- Address current_top = Heap::new_space()->top();
+ Address current_top = HEAP->new_space()->top();
Page* page = Page::FromAddress(current_top);
Address current_page = page->address();
Address next_page = current_page + Page::kPageSize;
@@ -859,7 +864,7 @@ TEST(LargeObjectSpaceContains) {
kPointerSize;
CHECK_EQ(bytes_to_allocate, FixedArray::SizeFor(n_elements));
FixedArray* array = FixedArray::cast(
- Heap::AllocateFixedArray(n_elements)->ToObjectChecked());
+ HEAP->AllocateFixedArray(n_elements)->ToObjectChecked());
int index = n_elements - 1;
CHECK_EQ(flags_ptr,
@@ -869,8 +874,8 @@ TEST(LargeObjectSpaceContains) {
// CHECK(Page::FromAddress(next_page)->IsLargeObjectPage());
HeapObject* addr = HeapObject::FromAddress(next_page + 2 * kPointerSize);
- CHECK(Heap::new_space()->Contains(addr));
- CHECK(!Heap::lo_space()->Contains(addr));
+ CHECK(HEAP->new_space()->Contains(addr));
+ CHECK(!HEAP->lo_space()->Contains(addr));
}
@@ -901,7 +906,7 @@ TEST(Regression39128) {
// Increase the chance of 'bump-the-pointer' allocation in old space.
bool force_compaction = true;
- Heap::CollectAllGarbage(force_compaction);
+ HEAP->CollectAllGarbage(force_compaction);
v8::HandleScope scope;
@@ -910,11 +915,12 @@ TEST(Regression39128) {
// that region dirty marks are updated correctly.
// Step 1: prepare a map for the object. We add 1 inobject property to it.
- Handle<JSFunction> object_ctor(Top::global_context()->object_function());
+ Handle<JSFunction> object_ctor(
+ Isolate::Current()->global_context()->object_function());
CHECK(object_ctor->has_initial_map());
Handle<Map> object_map(object_ctor->initial_map());
// Create a map with single inobject property.
- Handle<Map> my_map = Factory::CopyMap(object_map, 1);
+ Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
int n_properties = my_map->inobject_properties();
CHECK_GT(n_properties, 0);
@@ -924,15 +930,15 @@ TEST(Regression39128) {
// just enough room to allocate JSObject and thus fill the newspace.
int allocation_amount = Min(FixedArray::kMaxSize,
- Heap::MaxObjectSizeInNewSpace());
+ HEAP->MaxObjectSizeInNewSpace());
int allocation_len = LenFromSize(allocation_amount);
- NewSpace* new_space = Heap::new_space();
+ NewSpace* new_space = HEAP->new_space();
Address* top_addr = new_space->allocation_top_address();
Address* limit_addr = new_space->allocation_limit_address();
while ((*limit_addr - *top_addr) > allocation_amount) {
- CHECK(!Heap::always_allocate());
- Object* array =
- Heap::AllocateFixedArray(allocation_len)->ToObjectChecked();
+ CHECK(!HEAP->always_allocate());
+ Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
+ CHECK(!array->IsFailure());
CHECK(new_space->Contains(array));
}
@@ -941,12 +947,12 @@ TEST(Regression39128) {
int fixed_array_len = LenFromSize(to_fill);
CHECK(fixed_array_len < FixedArray::kMaxLength);
- CHECK(!Heap::always_allocate());
- Object* array =
- Heap::AllocateFixedArray(fixed_array_len)->ToObjectChecked();
+ CHECK(!HEAP->always_allocate());
+ Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
+ CHECK(!array->IsFailure());
CHECK(new_space->Contains(array));
- Object* object = Heap::AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
+ Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
CHECK(new_space->Contains(object));
JSObject* jsobject = JSObject::cast(object);
CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
@@ -958,15 +964,15 @@ TEST(Regression39128) {
// Step 4: clone jsobject, but force always allocate first to create a clone
// in old pointer space.
- Address old_pointer_space_top = Heap::old_pointer_space()->top();
+ Address old_pointer_space_top = HEAP->old_pointer_space()->top();
AlwaysAllocateScope aa_scope;
- Object* clone_obj = Heap::CopyJSObject(jsobject)->ToObjectChecked();
+ Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
JSObject* clone = JSObject::cast(clone_obj);
if (clone->address() != old_pointer_space_top) {
// Alas, got allocated from free list, we cannot do checks.
return;
}
- CHECK(Heap::old_pointer_space()->Contains(clone->address()));
+ CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
// Step 5: verify validity of region dirty marks.
Address clone_addr = clone->address();
@@ -988,7 +994,7 @@ TEST(TestCodeFlushing) {
" var z = x + y;"
"};"
"foo()";
- Handle<String> foo_name = Factory::LookupAsciiSymbol("foo");
+ Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
// This compile will add the code to the compilation cache.
{ v8::HandleScope scope;
@@ -996,23 +1002,23 @@ TEST(TestCodeFlushing) {
}
// Check function is compiled.
- Object* func_value =
- Top::context()->global()->GetProperty(*foo_name)->ToObjectChecked();
+ Object* func_value = Isolate::Current()->context()->global()->
+ GetProperty(*foo_name)->ToObjectChecked();
CHECK(func_value->IsJSFunction());
Handle<JSFunction> function(JSFunction::cast(func_value));
CHECK(function->shared()->is_compiled());
- Heap::CollectAllGarbage(true);
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
CHECK(function->shared()->is_compiled());
- Heap::CollectAllGarbage(true);
- Heap::CollectAllGarbage(true);
- Heap::CollectAllGarbage(true);
- Heap::CollectAllGarbage(true);
- Heap::CollectAllGarbage(true);
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
// foo should no longer be in the compilation cache
CHECK(!function->shared()->is_compiled() || function->IsOptimized());
@@ -1027,7 +1033,7 @@ TEST(TestCodeFlushing) {
// Count the number of global contexts in the weak list of global contexts.
static int CountGlobalContexts() {
int count = 0;
- Object* object = Heap::global_contexts_list();
+ Object* object = HEAP->global_contexts_list();
while (!object->IsUndefined()) {
count++;
object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
@@ -1051,6 +1057,8 @@ static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
TEST(TestInternalWeakLists) {
+ v8::V8::Initialize();
+
static const int kNumTestContexts = 10;
v8::HandleScope scope;
@@ -1094,35 +1102,35 @@ TEST(TestInternalWeakLists) {
// Scavenge treats these references as strong.
for (int j = 0; j < 10; j++) {
- Heap::PerformScavenge();
+ HEAP->PerformScavenge();
CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
}
// Mark compact handles the weak references.
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
// Get rid of f3 and f5 in the same way.
CompileRun("f3=null");
for (int j = 0; j < 10; j++) {
- Heap::PerformScavenge();
+ HEAP->PerformScavenge();
CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
}
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
CompileRun("f5=null");
for (int j = 0; j < 10; j++) {
- Heap::PerformScavenge();
+ HEAP->PerformScavenge();
CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
}
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
ctx[i]->Exit();
}
// Force compilation cache cleanup.
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
// Dispose the global contexts one by one.
for (int i = 0; i < kNumTestContexts; i++) {
@@ -1131,12 +1139,12 @@ TEST(TestInternalWeakLists) {
// Scavenge treats these references as strong.
for (int j = 0; j < 10; j++) {
- Heap::PerformScavenge();
+ HEAP->PerformScavenge();
CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
}
// Mark compact handles the weak references.
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
}
@@ -1148,10 +1156,10 @@ TEST(TestInternalWeakLists) {
// causing a GC after the specified number of elements.
static int CountGlobalContextsWithGC(int n) {
int count = 0;
- Handle<Object> object(Heap::global_contexts_list());
+ Handle<Object> object(HEAP->global_contexts_list());
while (!object->IsUndefined()) {
count++;
- if (count == n) Heap::CollectAllGarbage(true);
+ if (count == n) HEAP->CollectAllGarbage(true);
object =
Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
}
@@ -1170,7 +1178,7 @@ static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
while (object->IsJSFunction() &&
!Handle<JSFunction>::cast(object)->IsBuiltin()) {
count++;
- if (count == n) Heap::CollectAllGarbage(true);
+ if (count == n) HEAP->CollectAllGarbage(true);
object = Handle<Object>(
Object::cast(JSFunction::cast(*object)->next_function_link()));
}
@@ -1179,6 +1187,8 @@ static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
TEST(TestInternalWeakListsTraverseWithGC) {
+ v8::V8::Initialize();
+
static const int kNumTestContexts = 10;
v8::HandleScope scope;
@@ -1228,7 +1238,7 @@ TEST(TestInternalWeakListsTraverseWithGC) {
TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
InitializeVM();
- intptr_t size_of_objects_1 = Heap::SizeOfObjects();
+ intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
intptr_t size_of_objects_2 = 0;
for (HeapObject* obj = iterator.next();
@@ -1283,10 +1293,10 @@ TEST(HeapIteratorFilterUnreachable) {
InitializeVM();
v8::HandleScope scope;
CompileRun("a = {}; b = {};");
- v8::Handle<Object> a(Top::context()->global()->GetProperty(
- *Factory::LookupAsciiSymbol("a"))->ToObjectChecked());
- v8::Handle<Object> b(Top::context()->global()->GetProperty(
- *Factory::LookupAsciiSymbol("b"))->ToObjectChecked());
+ v8::Handle<Object> a(ISOLATE->context()->global()->GetProperty(
+ *FACTORY->LookupAsciiSymbol("a"))->ToObjectChecked());
+ v8::Handle<Object> b(ISOLATE->context()->global()->GetProperty(
+ *FACTORY->LookupAsciiSymbol("b"))->ToObjectChecked());
CHECK_NE(*a, *b);
{
HeapIteratorTestHelper helper(*a, *b);
@@ -1294,8 +1304,8 @@ TEST(HeapIteratorFilterUnreachable) {
CHECK(helper.a_found());
CHECK(helper.b_found());
}
- CHECK(Top::context()->global()->DeleteProperty(
- *Factory::LookupAsciiSymbol("a"), JSObject::FORCE_DELETION));
+ CHECK(ISOLATE->context()->global()->DeleteProperty(
+ *FACTORY->LookupAsciiSymbol("a"), JSObject::FORCE_DELETION));
// We ensure that GC will not happen, so our raw pointer stays valid.
AssertNoAllocation no_alloc;
Object* a_saved = *a;
diff --git a/test/cctest/test-liveedit.cc b/test/cctest/test-liveedit.cc
index 244980a1..92323544 100644
--- a/test/cctest/test-liveedit.cc
+++ b/test/cctest/test-liveedit.cc
@@ -158,6 +158,7 @@ void CompareStrings(const char* s1, const char* s2,
// --- T h e A c t u a l T e s t s
TEST(LiveEditDiffer) {
+ v8::internal::V8::Initialize(NULL);
CompareStrings("zz1zzz12zz123zzz", "zzzzzzzzzz", 6);
CompareStrings("zz1zzz12zz123zzz", "zz0zzz0zz0zzz", 9);
CompareStrings("123456789", "987654321", 16);
diff --git a/test/cctest/test-log-stack-tracer.cc b/test/cctest/test-log-stack-tracer.cc
index bf72184f..df0806f8 100644
--- a/test/cctest/test-log-stack-tracer.cc
+++ b/test/cctest/test-log-stack-tracer.cc
@@ -36,7 +36,7 @@
#include "api.h"
#include "codegen.h"
#include "log.h"
-#include "top.h"
+#include "isolate.h"
#include "cctest.h"
#include "disassembler.h"
#include "register-allocator-inl.h"
@@ -52,10 +52,10 @@ using v8::Value;
using v8::internal::byte;
using v8::internal::Address;
using v8::internal::Handle;
+using v8::internal::Isolate;
using v8::internal::JSFunction;
using v8::internal::StackTracer;
using v8::internal::TickSample;
-using v8::internal::Top;
namespace i = v8::internal;
@@ -78,18 +78,19 @@ static void DoTrace(Address fp) {
// sp is only used to define stack high bound
trace_env.sample->sp =
reinterpret_cast<Address>(trace_env.sample) - 10240;
- StackTracer::Trace(trace_env.sample);
+ StackTracer::Trace(Isolate::Current(), trace_env.sample);
}
// Hide c_entry_fp to emulate situation when sampling is done while
// pure JS code is being executed
static void DoTraceHideCEntryFPAddress(Address fp) {
- v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address());
+ v8::internal::Address saved_c_frame_fp =
+ *(Isolate::Current()->c_entry_fp_address());
CHECK(saved_c_frame_fp);
- *(Top::c_entry_fp_address()) = 0;
+ *(Isolate::Current()->c_entry_fp_address()) = 0;
DoTrace(fp);
- *(Top::c_entry_fp_address()) = saved_c_frame_fp;
+ *(Isolate::Current()->c_entry_fp_address()) = saved_c_frame_fp;
}
@@ -163,8 +164,8 @@ v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
static Address GetJsEntrySp() {
- CHECK_NE(NULL, Top::GetCurrentThread());
- return Top::js_entry_sp(Top::GetCurrentThread());
+ CHECK_NE(NULL, i::Isolate::Current()->thread_local_top());
+ return Isolate::js_entry_sp(i::Isolate::Current()->thread_local_top());
}
@@ -276,7 +277,7 @@ static void CreateTraceCallerFunction(const char* func_name,
// This test verifies that stack tracing works when called during
// execution of a native function called from JS code. In this case,
-// StackTracer uses Top::c_entry_fp as a starting point for stack
+// StackTracer uses Isolate::c_entry_fp as a starting point for stack
// walking.
TEST(CFromJSStackTrace) {
TickSample sample;
@@ -302,13 +303,11 @@ TEST(CFromJSStackTrace) {
// DoTrace(EBP) [native]
// StackTracer::Trace
- // The VM state tracking keeps track of external callbacks and puts
- // them at the top of the sample stack.
- int base = 0;
- CHECK(sample.stack[0] == FUNCTION_ADDR(TraceExtension::Trace));
- base++;
+ CHECK(sample.has_external_callback);
+ CHECK_EQ(FUNCTION_ADDR(TraceExtension::Trace), sample.external_callback);
// Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
+ int base = 0;
CHECK_GT(sample.frames_count, base + 1);
CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0]));
CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1]));
@@ -318,7 +317,7 @@ TEST(CFromJSStackTrace) {
// This test verifies that stack tracing works when called during
// execution of JS code. However, as calling StackTracer requires
// entering native code, we can only emulate pure JS by erasing
-// Top::c_entry_fp value. In this case, StackTracer uses passed frame
+// Isolate::c_entry_fp value. In this case, StackTracer uses passed frame
// pointer value as a starting point for stack walking.
TEST(PureJSStackTrace) {
// This test does not pass with inlining enabled since inlined functions
@@ -353,13 +352,11 @@ TEST(PureJSStackTrace) {
// StackTracer::Trace
//
- // The VM state tracking keeps track of external callbacks and puts
- // them at the top of the sample stack.
- int base = 0;
- CHECK(sample.stack[0] == FUNCTION_ADDR(TraceExtension::JSTrace));
- base++;
+ CHECK(sample.has_external_callback);
+ CHECK_EQ(FUNCTION_ADDR(TraceExtension::JSTrace), sample.external_callback);
// Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
+ int base = 0;
CHECK_GT(sample.frames_count, base + 1);
CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 0]));
CHECK(IsAddressWithinFuncCode("OuterJSTrace", sample.stack[base + 1]));
@@ -397,6 +394,7 @@ static int CFunc(int depth) {
TEST(PureCStackTrace) {
TickSample sample;
InitTraceEnv(&sample);
+ InitializeVM();
// Check that sampler doesn't crash
CHECK_EQ(10, CFunc(10));
}
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 30b8a48d..17c73874 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -29,61 +29,61 @@ static void SetUp() {
// Log to memory buffer.
i::FLAG_logfile = "*";
i::FLAG_log = true;
- Logger::Setup();
+ LOGGER->Setup();
}
static void TearDown() {
- Logger::TearDown();
+ LOGGER->TearDown();
}
TEST(EmptyLog) {
SetUp();
- CHECK_EQ(0, Logger::GetLogLines(0, NULL, 0));
- CHECK_EQ(0, Logger::GetLogLines(100, NULL, 0));
- CHECK_EQ(0, Logger::GetLogLines(0, NULL, 100));
- CHECK_EQ(0, Logger::GetLogLines(100, NULL, 100));
+ CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 0));
+ CHECK_EQ(0, LOGGER->GetLogLines(100, NULL, 0));
+ CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 100));
+ CHECK_EQ(0, LOGGER->GetLogLines(100, NULL, 100));
TearDown();
}
TEST(GetMessages) {
SetUp();
- Logger::StringEvent("aaa", "bbb");
- Logger::StringEvent("cccc", "dddd");
- CHECK_EQ(0, Logger::GetLogLines(0, NULL, 0));
+ LOGGER->StringEvent("aaa", "bbb");
+ LOGGER->StringEvent("cccc", "dddd");
+ CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 0));
char log_lines[100];
memset(log_lines, 0, sizeof(log_lines));
// See Logger::StringEvent.
const char* line_1 = "aaa,\"bbb\"\n";
const int line_1_len = StrLength(line_1);
// The exact size.
- CHECK_EQ(line_1_len, Logger::GetLogLines(0, log_lines, line_1_len));
+ CHECK_EQ(line_1_len, LOGGER->GetLogLines(0, log_lines, line_1_len));
CHECK_EQ(line_1, log_lines);
memset(log_lines, 0, sizeof(log_lines));
// A bit more than the first line length.
- CHECK_EQ(line_1_len, Logger::GetLogLines(0, log_lines, line_1_len + 3));
+ CHECK_EQ(line_1_len, LOGGER->GetLogLines(0, log_lines, line_1_len + 3));
log_lines[line_1_len] = '\0';
CHECK_EQ(line_1, log_lines);
memset(log_lines, 0, sizeof(log_lines));
const char* line_2 = "cccc,\"dddd\"\n";
const int line_2_len = StrLength(line_2);
// Now start with line_2 beginning.
- CHECK_EQ(0, Logger::GetLogLines(line_1_len, log_lines, 0));
- CHECK_EQ(line_2_len, Logger::GetLogLines(line_1_len, log_lines, line_2_len));
+ CHECK_EQ(0, LOGGER->GetLogLines(line_1_len, log_lines, 0));
+ CHECK_EQ(line_2_len, LOGGER->GetLogLines(line_1_len, log_lines, line_2_len));
CHECK_EQ(line_2, log_lines);
memset(log_lines, 0, sizeof(log_lines));
CHECK_EQ(line_2_len,
- Logger::GetLogLines(line_1_len, log_lines, line_2_len + 3));
+ LOGGER->GetLogLines(line_1_len, log_lines, line_2_len + 3));
CHECK_EQ(line_2, log_lines);
memset(log_lines, 0, sizeof(log_lines));
// Now get entire buffer contents.
const char* all_lines = "aaa,\"bbb\"\ncccc,\"dddd\"\n";
const int all_lines_len = StrLength(all_lines);
- CHECK_EQ(all_lines_len, Logger::GetLogLines(0, log_lines, all_lines_len));
+ CHECK_EQ(all_lines_len, LOGGER->GetLogLines(0, log_lines, all_lines_len));
CHECK_EQ(all_lines, log_lines);
memset(log_lines, 0, sizeof(log_lines));
- CHECK_EQ(all_lines_len, Logger::GetLogLines(0, log_lines, all_lines_len + 3));
+ CHECK_EQ(all_lines_len, LOGGER->GetLogLines(0, log_lines, all_lines_len + 3));
CHECK_EQ(all_lines, log_lines);
memset(log_lines, 0, sizeof(log_lines));
TearDown();
@@ -91,26 +91,26 @@ TEST(GetMessages) {
static int GetLogLines(int start_pos, i::Vector<char>* buffer) {
- return Logger::GetLogLines(start_pos, buffer->start(), buffer->length());
+ return LOGGER->GetLogLines(start_pos, buffer->start(), buffer->length());
}
TEST(BeyondWritePosition) {
SetUp();
- Logger::StringEvent("aaa", "bbb");
- Logger::StringEvent("cccc", "dddd");
+ LOGGER->StringEvent("aaa", "bbb");
+ LOGGER->StringEvent("cccc", "dddd");
// See Logger::StringEvent.
const char* all_lines = "aaa,\"bbb\"\ncccc,\"dddd\"\n";
const int all_lines_len = StrLength(all_lines);
EmbeddedVector<char, 100> buffer;
const int beyond_write_pos = all_lines_len;
- CHECK_EQ(0, Logger::GetLogLines(beyond_write_pos, buffer.start(), 1));
+ CHECK_EQ(0, LOGGER->GetLogLines(beyond_write_pos, buffer.start(), 1));
CHECK_EQ(0, GetLogLines(beyond_write_pos, &buffer));
- CHECK_EQ(0, Logger::GetLogLines(beyond_write_pos + 1, buffer.start(), 1));
+ CHECK_EQ(0, LOGGER->GetLogLines(beyond_write_pos + 1, buffer.start(), 1));
CHECK_EQ(0, GetLogLines(beyond_write_pos + 1, &buffer));
- CHECK_EQ(0, Logger::GetLogLines(beyond_write_pos + 100, buffer.start(), 1));
+ CHECK_EQ(0, LOGGER->GetLogLines(beyond_write_pos + 100, buffer.start(), 1));
CHECK_EQ(0, GetLogLines(beyond_write_pos + 100, &buffer));
- CHECK_EQ(0, Logger::GetLogLines(10 * 1024 * 1024, buffer.start(), 1));
+ CHECK_EQ(0, LOGGER->GetLogLines(10 * 1024 * 1024, buffer.start(), 1));
CHECK_EQ(0, GetLogLines(10 * 1024 * 1024, &buffer));
TearDown();
}
@@ -120,12 +120,12 @@ TEST(MemoryLoggingTurnedOff) {
// Log to stdout
i::FLAG_logfile = "-";
i::FLAG_log = true;
- Logger::Setup();
- CHECK_EQ(0, Logger::GetLogLines(0, NULL, 0));
- CHECK_EQ(0, Logger::GetLogLines(100, NULL, 0));
- CHECK_EQ(0, Logger::GetLogLines(0, NULL, 100));
- CHECK_EQ(0, Logger::GetLogLines(100, NULL, 100));
- Logger::TearDown();
+ LOGGER->Setup();
+ CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 0));
+ CHECK_EQ(0, LOGGER->GetLogLines(100, NULL, 0));
+ CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 100));
+ CHECK_EQ(0, LOGGER->GetLogLines(100, NULL, 100));
+ LOGGER->TearDown();
}
@@ -139,12 +139,12 @@ namespace internal {
class LoggerTestHelper : public AllStatic {
public:
- static bool IsSamplerActive() { return Logger::IsProfilerSamplerActive(); }
+ static bool IsSamplerActive() { return LOGGER->IsProfilerSamplerActive(); }
static void ResetSamplesTaken() {
- reinterpret_cast<Sampler*>(Logger::ticker_)->ResetSamplesTaken();
+ reinterpret_cast<Sampler*>(LOGGER->ticker_)->ResetSamplesTaken();
}
static bool has_samples_taken() {
- return reinterpret_cast<Sampler*>(Logger::ticker_)->samples_taken() > 0;
+ return reinterpret_cast<Sampler*>(LOGGER->ticker_)->samples_taken() > 0;
}
};
@@ -166,13 +166,13 @@ class ScopedLoggerInitializer {
need_to_set_up_logger_(i::V8::IsRunning()),
scope_(),
env_(v8::Context::New()) {
- if (need_to_set_up_logger_) Logger::Setup();
+ if (need_to_set_up_logger_) LOGGER->Setup();
env_->Enter();
}
~ScopedLoggerInitializer() {
env_->Exit();
- Logger::TearDown();
+ LOGGER->TearDown();
i::FLAG_prof_lazy = saved_prof_lazy_;
i::FLAG_prof = saved_prof_;
i::FLAG_prof_auto = saved_prof_auto_;
@@ -251,7 +251,7 @@ static void CheckThatProfilerWorks(LogBufferMatcher* matcher) {
!LoggerTestHelper::IsSamplerActive());
LoggerTestHelper::ResetSamplesTaken();
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 0);
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 0);
CHECK(LoggerTestHelper::IsSamplerActive());
// Verify that the current map of compiled functions has been logged.
@@ -273,7 +273,7 @@ static void CheckThatProfilerWorks(LogBufferMatcher* matcher) {
i::OS::Sleep(1);
}
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 0);
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 0);
CHECK(i::RuntimeProfiler::IsEnabled() ||
!LoggerTestHelper::IsSamplerActive());
@@ -329,8 +329,8 @@ namespace {
class LoopingThread : public v8::internal::Thread {
public:
- LoopingThread()
- : v8::internal::Thread(),
+ explicit LoopingThread(v8::internal::Isolate* isolate)
+ : v8::internal::Thread(isolate),
semaphore_(v8::internal::OS::CreateSemaphore(0)),
run_(true) {
}
@@ -369,9 +369,12 @@ class LoopingThread : public v8::internal::Thread {
class LoopingJsThread : public LoopingThread {
public:
+ explicit LoopingJsThread(v8::internal::Isolate* isolate)
+ : LoopingThread(isolate) { }
void RunLoop() {
v8::Locker locker;
- CHECK(v8::internal::ThreadManager::HasId());
+ CHECK(i::Isolate::Current() != NULL);
+ CHECK_GT(i::Isolate::Current()->thread_manager()->CurrentId(), 0);
SetV8ThreadId();
while (IsRunning()) {
v8::HandleScope scope;
@@ -392,11 +395,14 @@ class LoopingJsThread : public LoopingThread {
class LoopingNonJsThread : public LoopingThread {
public:
+ explicit LoopingNonJsThread(v8::internal::Isolate* isolate)
+ : LoopingThread(isolate) { }
void RunLoop() {
v8::Locker locker;
v8::Unlocker unlocker;
// Now thread has V8's id, but will not run VM code.
- CHECK(v8::internal::ThreadManager::HasId());
+ CHECK(i::Isolate::Current() != NULL);
+ CHECK_GT(i::Isolate::Current()->thread_manager()->CurrentId(), 0);
double i = 10;
SignalRunning();
while (IsRunning()) {
@@ -409,8 +415,8 @@ class LoopingNonJsThread : public LoopingThread {
class TestSampler : public v8::internal::Sampler {
public:
- TestSampler()
- : Sampler(0, true, true),
+ explicit TestSampler(v8::internal::Isolate* isolate)
+ : Sampler(isolate, 0, true, true),
semaphore_(v8::internal::OS::CreateSemaphore(0)),
was_sample_stack_called_(false) {
}
@@ -441,14 +447,14 @@ TEST(ProfMultipleThreads) {
TestSampler* sampler = NULL;
{
v8::Locker locker;
- sampler = new TestSampler();
+ sampler = new TestSampler(v8::internal::Isolate::Current());
sampler->Start();
CHECK(sampler->IsActive());
}
- LoopingJsThread jsThread;
+ LoopingJsThread jsThread(v8::internal::Isolate::Current());
jsThread.Start();
- LoopingNonJsThread nonJsThread;
+ LoopingNonJsThread nonJsThread(v8::internal::Isolate::Current());
nonJsThread.Start();
CHECK(!sampler->WasSampleStackCalled());
@@ -515,7 +521,7 @@ TEST(Issue23768) {
i_source->set_resource(NULL);
// Must not crash.
- i::Logger::LogCompiledFunctions();
+ LOGGER->LogCompiledFunctions();
}
@@ -541,7 +547,7 @@ TEST(LogCallbacks) {
initialize_logger.env()->Global()->Set(v8_str("Obj"), obj->GetFunction());
CompileAndRunScript("Obj.prototype.method1.toString();");
- i::Logger::LogCompiledFunctions();
+ LOGGER->LogCompiledFunctions();
CHECK_GT(matcher.GetNextChunk(), 0);
const char* callback_rec = "code-creation,Callback,";
@@ -584,7 +590,7 @@ TEST(LogAccessorCallbacks) {
inst->SetAccessor(v8::String::New("prop1"), Prop1Getter, Prop1Setter);
inst->SetAccessor(v8::String::New("prop2"), Prop2Getter);
- i::Logger::LogAccessorCallbacks();
+ LOGGER->LogAccessorCallbacks();
CHECK_GT(matcher.GetNextChunk(), 0);
matcher.PrintBuffer();
@@ -616,11 +622,11 @@ TEST(LogTags) {
const char* close_tag = "close-tag,";
// Check compatibility with the old style behavior.
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 0);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 0);
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 0);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 0);
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
CHECK_EQ(NULL, matcher.Find(open_tag));
CHECK_EQ(NULL, matcher.Find(close_tag));
@@ -628,11 +634,11 @@ TEST(LogTags) {
const char* close_tag1 = "close-tag,1\n";
// Check non-nested tag case.
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
CHECK_GT(matcher.GetNextChunk(), 0);
CHECK(matcher.IsInSequence(open_tag1, close_tag1));
@@ -640,15 +646,15 @@ TEST(LogTags) {
const char* close_tag2 = "close-tag,2\n";
// Check nested tags case.
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 2);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 2);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 2);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 2);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
CHECK_GT(matcher.GetNextChunk(), 0);
// open_tag1 < open_tag2 < close_tag2 < close_tag1
CHECK(matcher.IsInSequence(open_tag1, open_tag2));
@@ -656,15 +662,15 @@ TEST(LogTags) {
CHECK(matcher.IsInSequence(close_tag2, close_tag1));
// Check overlapped tags case.
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 2);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 2);
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 2);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 2);
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
CHECK_GT(matcher.GetNextChunk(), 0);
// open_tag1 < open_tag2 < close_tag1 < close_tag2
CHECK(matcher.IsInSequence(open_tag1, open_tag2));
@@ -675,19 +681,19 @@ TEST(LogTags) {
const char* close_tag3 = "close-tag,3\n";
// Check pausing overflow case.
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 2);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 2);
- CHECK_EQ(v8::PROFILER_MODULE_CPU, Logger::GetActiveProfilerModules());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 3);
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 3);
- CHECK_EQ(v8::PROFILER_MODULE_NONE, Logger::GetActiveProfilerModules());
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 2);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 2);
+ CHECK_EQ(v8::PROFILER_MODULE_CPU, LOGGER->GetActiveProfilerModules());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 3);
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 3);
+ CHECK_EQ(v8::PROFILER_MODULE_NONE, LOGGER->GetActiveProfilerModules());
// Must be no tags, because logging must be disabled.
CHECK_EQ(NULL, matcher.Find(open_tag3));
CHECK_EQ(NULL, matcher.Find(close_tag3));
@@ -697,29 +703,29 @@ TEST(LogTags) {
TEST(IsLoggingPreserved) {
ScopedLoggerInitializer initialize_logger(false);
- CHECK(Logger::is_logging());
- Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK(Logger::is_logging());
- Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
- CHECK(Logger::is_logging());
+ CHECK(LOGGER->is_logging());
+ LOGGER->ResumeProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK(LOGGER->is_logging());
+ LOGGER->PauseProfiler(v8::PROFILER_MODULE_CPU, 1);
+ CHECK(LOGGER->is_logging());
- CHECK(Logger::is_logging());
- Logger::ResumeProfiler(
+ CHECK(LOGGER->is_logging());
+ LOGGER->ResumeProfiler(
v8::PROFILER_MODULE_HEAP_STATS | v8::PROFILER_MODULE_JS_CONSTRUCTORS, 1);
- CHECK(Logger::is_logging());
- Logger::PauseProfiler(
+ CHECK(LOGGER->is_logging());
+ LOGGER->PauseProfiler(
v8::PROFILER_MODULE_HEAP_STATS | v8::PROFILER_MODULE_JS_CONSTRUCTORS, 1);
- CHECK(Logger::is_logging());
+ CHECK(LOGGER->is_logging());
- CHECK(Logger::is_logging());
- Logger::ResumeProfiler(
+ CHECK(LOGGER->is_logging());
+ LOGGER->ResumeProfiler(
v8::PROFILER_MODULE_CPU |
v8::PROFILER_MODULE_HEAP_STATS | v8::PROFILER_MODULE_JS_CONSTRUCTORS, 1);
- CHECK(Logger::is_logging());
- Logger::PauseProfiler(
+ CHECK(LOGGER->is_logging());
+ LOGGER->PauseProfiler(
v8::PROFILER_MODULE_CPU |
v8::PROFILER_MODULE_HEAP_STATS | v8::PROFILER_MODULE_JS_CONSTRUCTORS, 1);
- CHECK(Logger::is_logging());
+ CHECK(LOGGER->is_logging());
}
@@ -1128,7 +1134,7 @@ TEST(EquivalenceOfLoggingAndTraversal) {
" obj.test =\n"
" (function a(j) { return function b() { return j; } })(100);\n"
"})(this);");
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
EmbeddedVector<char, 204800> buffer;
int log_size;
@@ -1148,9 +1154,9 @@ TEST(EquivalenceOfLoggingAndTraversal) {
}
// Iterate heap to find compiled functions, will write to log.
- i::Logger::LogCompiledFunctions();
+ LOGGER->LogCompiledFunctions();
char* new_log_start = buffer.start() + log_size;
- const int new_log_size = Logger::GetLogLines(
+ const int new_log_size = LOGGER->GetLogLines(
log_size, new_log_start, buffer.length() - log_size);
CHECK_GT(new_log_size, 0);
CHECK_GT(buffer.length(), log_size + new_log_size);
@@ -1184,7 +1190,7 @@ TEST(EquivalenceOfLoggingAndTraversal) {
CHECK(results_equal);
env->Exit();
- Logger::TearDown();
+ LOGGER->TearDown();
i::FLAG_always_compact = saved_always_compact;
}
diff --git a/test/cctest/test-macro-assembler-x64.cc b/test/cctest/test-macro-assembler-x64.cc
index 9b1fc46e..c7c67b05 100755
--- a/test/cctest/test-macro-assembler-x64.cc
+++ b/test/cctest/test-macro-assembler-x64.cc
@@ -57,9 +57,9 @@ using v8::internal::rsp;
using v8::internal::r8;
using v8::internal::r9;
using v8::internal::r11;
-using v8::internal::r12;
using v8::internal::r13;
using v8::internal::r14;
+using v8::internal::r15;
using v8::internal::times_pointer_size;
using v8::internal::FUNCTION_CAST;
using v8::internal::CodeDesc;
@@ -95,7 +95,9 @@ typedef int (*F0)();
static void EntryCode(MacroAssembler* masm) {
// Smi constant register is callee save.
__ push(v8::internal::kSmiConstantRegister);
+ __ push(v8::internal::kRootRegister);
__ InitializeSmiConstantRegister();
+ __ InitializeRootRegister();
}
@@ -105,6 +107,7 @@ static void ExitCode(MacroAssembler* masm) {
__ cmpq(rdx, v8::internal::kSmiConstantRegister);
__ movq(rdx, Immediate(-1));
__ cmovq(not_equal, rax, rdx);
+ __ pop(v8::internal::kRootRegister);
__ pop(v8::internal::kSmiConstantRegister);
}
@@ -146,6 +149,7 @@ static void TestMoveSmi(MacroAssembler* masm, Label* exit, int id, Smi* value) {
// Test that we can move a Smi value literally into a register.
TEST(SmiMove) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -220,7 +224,7 @@ void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ j(less_equal, exit);
}
} else {
- __ SmiCompare(rcx, rcx);
+ __ cmpq(rcx, rcx);
__ movl(rax, Immediate(id + 11));
__ j(not_equal, exit);
__ incq(rax);
@@ -232,10 +236,11 @@ void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) {
// Test that we can compare smis for equality (and more).
TEST(SmiCompare) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
- static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+ static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
&actual_size,
true));
CHECK(buffer);
@@ -282,6 +287,7 @@ TEST(SmiCompare) {
TEST(Integer32ToSmi) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -300,35 +306,35 @@ TEST(Integer32ToSmi) {
__ movl(rcx, Immediate(0));
__ Integer32ToSmi(rcx, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
- __ SmiCompare(rcx, rdx);
+ __ cmpq(rcx, rdx);
__ j(not_equal, &exit);
__ movq(rax, Immediate(2)); // Test number.
__ movl(rcx, Immediate(1024));
__ Integer32ToSmi(rcx, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
- __ SmiCompare(rcx, rdx);
+ __ cmpq(rcx, rdx);
__ j(not_equal, &exit);
__ movq(rax, Immediate(3)); // Test number.
__ movl(rcx, Immediate(-1));
__ Integer32ToSmi(rcx, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
- __ SmiCompare(rcx, rdx);
+ __ cmpq(rcx, rdx);
__ j(not_equal, &exit);
__ movq(rax, Immediate(4)); // Test number.
__ movl(rcx, Immediate(Smi::kMaxValue));
__ Integer32ToSmi(rcx, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
- __ SmiCompare(rcx, rdx);
+ __ cmpq(rcx, rdx);
__ j(not_equal, &exit);
__ movq(rax, Immediate(5)); // Test number.
__ movl(rcx, Immediate(Smi::kMinValue));
__ Integer32ToSmi(rcx, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
- __ SmiCompare(rcx, rdx);
+ __ cmpq(rcx, rdx);
__ j(not_equal, &exit);
// Different target register.
@@ -337,35 +343,35 @@ TEST(Integer32ToSmi) {
__ movl(rcx, Immediate(0));
__ Integer32ToSmi(r8, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
- __ SmiCompare(r8, rdx);
+ __ cmpq(r8, rdx);
__ j(not_equal, &exit);
__ movq(rax, Immediate(7)); // Test number.
__ movl(rcx, Immediate(1024));
__ Integer32ToSmi(r8, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
- __ SmiCompare(r8, rdx);
+ __ cmpq(r8, rdx);
__ j(not_equal, &exit);
__ movq(rax, Immediate(8)); // Test number.
__ movl(rcx, Immediate(-1));
__ Integer32ToSmi(r8, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
- __ SmiCompare(r8, rdx);
+ __ cmpq(r8, rdx);
__ j(not_equal, &exit);
__ movq(rax, Immediate(9)); // Test number.
__ movl(rcx, Immediate(Smi::kMaxValue));
__ Integer32ToSmi(r8, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
- __ SmiCompare(r8, rdx);
+ __ cmpq(r8, rdx);
__ j(not_equal, &exit);
__ movq(rax, Immediate(10)); // Test number.
__ movl(rcx, Immediate(Smi::kMinValue));
__ Integer32ToSmi(r8, rcx);
__ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
- __ SmiCompare(r8, rdx);
+ __ cmpq(r8, rdx);
__ j(not_equal, &exit);
@@ -394,21 +400,22 @@ void TestI64PlusConstantToSmi(MacroAssembler* masm,
__ movq(rcx, x, RelocInfo::NONE);
__ movq(r11, rcx);
__ Integer64PlusConstantToSmi(rdx, rcx, y);
- __ SmiCompare(rdx, r8);
+ __ cmpq(rdx, r8);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ Integer64PlusConstantToSmi(rcx, rcx, y);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
}
TEST(Integer64PlusConstantToSmi) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -452,6 +459,7 @@ TEST(Integer64PlusConstantToSmi) {
TEST(SmiCheck) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -660,14 +668,14 @@ void TestSmiNeg(MacroAssembler* masm, Label* exit, int id, int x) {
__ SmiNeg(r9, rcx, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ SmiNeg(rcx, rcx, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
} else {
Label smi_ok, smi_ok2;
@@ -679,11 +687,11 @@ void TestSmiNeg(MacroAssembler* masm, Label* exit, int id, int x) {
__ jmp(exit);
__ bind(&smi_ok);
__ incq(rax);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
@@ -691,13 +699,14 @@ void TestSmiNeg(MacroAssembler* masm, Label* exit, int id, int x) {
__ jmp(exit);
__ bind(&smi_ok2);
__ incq(rax);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
}
}
TEST(SmiNeg) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -751,12 +760,12 @@ static void SmiAddTest(MacroAssembler* masm,
__ movl(rax, Immediate(id)); // Test number.
__ SmiAdd(r9, rcx, rdx, exit);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
__ SmiAdd(rcx, rcx, rdx, exit); \
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
__ movl(rcx, Immediate(first));
@@ -764,11 +773,11 @@ static void SmiAddTest(MacroAssembler* masm,
__ incq(rax);
__ SmiAddConstant(r9, rcx, Smi::FromInt(second));
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ SmiAddConstant(rcx, rcx, Smi::FromInt(second));
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
__ movl(rcx, Immediate(first));
@@ -776,16 +785,17 @@ static void SmiAddTest(MacroAssembler* masm,
__ incq(rax);
__ SmiAddConstant(r9, rcx, Smi::FromInt(second), exit);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
__ SmiAddConstant(rcx, rcx, Smi::FromInt(second), exit);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
}
TEST(SmiAdd) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -834,36 +844,36 @@ static void SmiSubTest(MacroAssembler* masm,
__ movl(rax, Immediate(id)); // Test 0.
__ SmiSub(r9, rcx, rdx, exit);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax); // Test 1.
__ SmiSub(rcx, rcx, rdx, exit);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
__ Move(rcx, Smi::FromInt(first));
__ incq(rax); // Test 2.
__ SmiSubConstant(r9, rcx, Smi::FromInt(second));
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax); // Test 3.
__ SmiSubConstant(rcx, rcx, Smi::FromInt(second));
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
__ Move(rcx, Smi::FromInt(first));
__ incq(rax); // Test 4.
__ SmiSubConstant(r9, rcx, Smi::FromInt(second), exit);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax); // Test 5.
__ SmiSubConstant(rcx, rcx, Smi::FromInt(second), exit);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
}
@@ -886,7 +896,7 @@ static void SmiSubOverflowTest(MacroAssembler* masm,
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
@@ -897,7 +907,7 @@ static void SmiSubOverflowTest(MacroAssembler* masm,
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
@@ -909,7 +919,7 @@ static void SmiSubOverflowTest(MacroAssembler* masm,
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
@@ -920,7 +930,7 @@ static void SmiSubOverflowTest(MacroAssembler* masm,
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
@@ -933,7 +943,7 @@ static void SmiSubOverflowTest(MacroAssembler* masm,
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
@@ -944,7 +954,7 @@ static void SmiSubOverflowTest(MacroAssembler* masm,
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
@@ -956,7 +966,7 @@ static void SmiSubOverflowTest(MacroAssembler* masm,
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
@@ -967,13 +977,14 @@ static void SmiSubOverflowTest(MacroAssembler* masm,
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
}
TEST(SmiSub) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1032,15 +1043,15 @@ void TestSmiMul(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ Move(r8, Smi::FromIntptr(result));
__ SmiMul(r9, rcx, rdx, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
__ SmiMul(rcx, rcx, rdx, exit);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
} else {
__ movl(rax, Immediate(id + 8));
@@ -1049,7 +1060,7 @@ void TestSmiMul(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ jmp(exit);
__ bind(&overflow_ok);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ SmiMul(rcx, rcx, rdx, &overflow_ok2);
@@ -1057,13 +1068,14 @@ void TestSmiMul(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ bind(&overflow_ok2);
// 31-bit version doesn't preserve rcx on failure.
// __ incq(rax);
- // __ SmiCompare(r11, rcx);
+ // __ cmpq(r11, rcx);
// __ j(not_equal, exit);
}
}
TEST(SmiMul) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -1120,30 +1132,30 @@ void TestSmiDiv(MacroAssembler* masm, Label* exit, int id, int x, int y) {
if (!fraction && !overflow && !negative_zero && !division_by_zero) {
// Division succeeds
__ movq(rcx, r11);
- __ movq(r12, Immediate(id));
+ __ movq(r15, Immediate(id));
int result = x / y;
__ Move(r8, Smi::FromInt(result));
__ SmiDiv(r9, rcx, r14, exit);
// Might have destroyed rcx and r14.
- __ incq(r12);
- __ SmiCompare(r9, r8);
+ __ incq(r15);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
- __ incq(r12);
+ __ incq(r15);
__ movq(rcx, r11);
__ Move(r14, Smi::FromInt(y));
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
- __ incq(r12);
+ __ incq(r15);
__ SmiDiv(rcx, rcx, r14, exit);
- __ incq(r12);
- __ SmiCompare(rcx, r8);
+ __ incq(r15);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
} else {
// Division fails.
- __ movq(r12, Immediate(id + 8));
+ __ movq(r15, Immediate(id + 8));
Label fail_ok, fail_ok2;
__ movq(rcx, r11);
@@ -1151,23 +1163,24 @@ void TestSmiDiv(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ jmp(exit);
__ bind(&fail_ok);
- __ incq(r12);
- __ SmiCompare(rcx, r11);
+ __ incq(r15);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
- __ incq(r12);
+ __ incq(r15);
__ SmiDiv(rcx, rcx, r14, &fail_ok2);
__ jmp(exit);
__ bind(&fail_ok2);
- __ incq(r12);
- __ SmiCompare(rcx, r11);
+ __ incq(r15);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
}
TEST(SmiDiv) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1184,7 +1197,7 @@ TEST(SmiDiv) {
Label exit;
__ push(r14);
- __ push(r12);
+ __ push(r15);
TestSmiDiv(masm, &exit, 0x10, 1, 1);
TestSmiDiv(masm, &exit, 0x20, 1, 0);
TestSmiDiv(masm, &exit, 0x30, -1, 0);
@@ -1206,10 +1219,10 @@ TEST(SmiDiv) {
TestSmiDiv(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
TestSmiDiv(masm, &exit, 0x140, Smi::kMinValue, -1);
- __ xor_(r12, r12); // Success.
+ __ xor_(r15, r15); // Success.
__ bind(&exit);
- __ movq(rax, r12);
- __ pop(r12);
+ __ movq(rax, r15);
+ __ pop(r15);
__ pop(r14);
ExitCode(masm);
__ ret(0);
@@ -1232,51 +1245,52 @@ void TestSmiMod(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ Move(r14, Smi::FromInt(y));
if (!division_overflow && !negative_zero && !division_by_zero) {
// Modulo succeeds
- __ movq(r12, Immediate(id));
+ __ movq(r15, Immediate(id));
int result = x % y;
__ Move(r8, Smi::FromInt(result));
__ SmiMod(r9, rcx, r14, exit);
- __ incq(r12);
- __ SmiCompare(r9, r8);
+ __ incq(r15);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
- __ incq(r12);
- __ SmiCompare(rcx, r11);
+ __ incq(r15);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
- __ incq(r12);
+ __ incq(r15);
__ SmiMod(rcx, rcx, r14, exit);
- __ incq(r12);
- __ SmiCompare(rcx, r8);
+ __ incq(r15);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
} else {
// Modulo fails.
- __ movq(r12, Immediate(id + 8));
+ __ movq(r15, Immediate(id + 8));
Label fail_ok, fail_ok2;
__ SmiMod(r9, rcx, r14, &fail_ok);
__ jmp(exit);
__ bind(&fail_ok);
- __ incq(r12);
- __ SmiCompare(rcx, r11);
+ __ incq(r15);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
- __ incq(r12);
+ __ incq(r15);
__ SmiMod(rcx, rcx, r14, &fail_ok2);
__ jmp(exit);
__ bind(&fail_ok2);
- __ incq(r12);
- __ SmiCompare(rcx, r11);
+ __ incq(r15);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
}
}
TEST(SmiMod) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1293,7 +1307,7 @@ TEST(SmiMod) {
Label exit;
__ push(r14);
- __ push(r12);
+ __ push(r15);
TestSmiMod(masm, &exit, 0x10, 1, 1);
TestSmiMod(masm, &exit, 0x20, 1, 0);
TestSmiMod(masm, &exit, 0x30, -1, 0);
@@ -1315,10 +1329,10 @@ TEST(SmiMod) {
TestSmiMod(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
TestSmiMod(masm, &exit, 0x140, Smi::kMinValue, -1);
- __ xor_(r12, r12); // Success.
+ __ xor_(r15, r15); // Success.
__ bind(&exit);
- __ movq(rax, r12);
- __ pop(r12);
+ __ movq(rax, r15);
+ __ pop(r15);
__ pop(r14);
ExitCode(masm);
__ ret(0);
@@ -1340,7 +1354,7 @@ void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
ASSERT(index.reg.is(rcx) || index.reg.is(rdx));
__ shl(index.reg, Immediate(index.scale));
__ Set(r8, static_cast<intptr_t>(x) << i);
- __ SmiCompare(index.reg, r8);
+ __ cmpq(index.reg, r8);
__ j(not_equal, exit);
__ incq(rax);
__ Move(rcx, Smi::FromInt(x));
@@ -1348,7 +1362,7 @@ void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
ASSERT(index.reg.is(rcx));
__ shl(rcx, Immediate(index.scale));
__ Set(r8, static_cast<intptr_t>(x) << i);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -1357,7 +1371,7 @@ void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
ASSERT(index.reg.is(rcx) || index.reg.is(rdx));
__ shl(index.reg, Immediate(index.scale));
__ Set(r8, static_cast<intptr_t>(-x) << i);
- __ SmiCompare(index.reg, r8);
+ __ cmpq(index.reg, r8);
__ j(not_equal, exit);
__ incq(rax);
__ Move(rcx, Smi::FromInt(x));
@@ -1365,13 +1379,14 @@ void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
ASSERT(index.reg.is(rcx));
__ shl(rcx, Immediate(index.scale));
__ Set(r8, static_cast<intptr_t>(-x) << i);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
__ incq(rax);
}
}
TEST(SmiIndex) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1414,7 +1429,7 @@ void TestSelectNonSmi(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ SelectNonSmi(r9, rcx, rdx, exit);
__ incq(rax);
- __ SmiCompare(r9, rdx);
+ __ cmpq(r9, rdx);
__ j(not_equal, exit);
__ incq(rax);
@@ -1424,7 +1439,7 @@ void TestSelectNonSmi(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ SelectNonSmi(r9, rcx, rdx, exit);
__ incq(rax);
- __ SmiCompare(r9, rcx);
+ __ cmpq(r9, rcx);
__ j(not_equal, exit);
__ incq(rax);
@@ -1440,6 +1455,7 @@ void TestSelectNonSmi(MacroAssembler* masm, Label* exit, int id, int x, int y) {
TEST(SmiSelectNonSmi) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1488,36 +1504,37 @@ void TestSmiAnd(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ Move(rdx, Smi::FromInt(y));
__ Move(r8, Smi::FromInt(result));
__ SmiAnd(r9, rcx, rdx);
- __ SmiCompare(r8, r9);
+ __ cmpq(r8, r9);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ SmiAnd(rcx, rcx, rdx);
- __ SmiCompare(r8, rcx);
+ __ cmpq(r8, rcx);
__ j(not_equal, exit);
__ movq(rcx, r11);
__ incq(rax);
__ SmiAndConstant(r9, rcx, Smi::FromInt(y));
- __ SmiCompare(r8, r9);
+ __ cmpq(r8, r9);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ SmiAndConstant(rcx, rcx, Smi::FromInt(y));
- __ SmiCompare(r8, rcx);
+ __ cmpq(r8, rcx);
__ j(not_equal, exit);
}
TEST(SmiAnd) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1568,36 +1585,37 @@ void TestSmiOr(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ Move(rdx, Smi::FromInt(y));
__ Move(r8, Smi::FromInt(result));
__ SmiOr(r9, rcx, rdx);
- __ SmiCompare(r8, r9);
+ __ cmpq(r8, r9);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ SmiOr(rcx, rcx, rdx);
- __ SmiCompare(r8, rcx);
+ __ cmpq(r8, rcx);
__ j(not_equal, exit);
__ movq(rcx, r11);
__ incq(rax);
__ SmiOrConstant(r9, rcx, Smi::FromInt(y));
- __ SmiCompare(r8, r9);
+ __ cmpq(r8, r9);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ SmiOrConstant(rcx, rcx, Smi::FromInt(y));
- __ SmiCompare(r8, rcx);
+ __ cmpq(r8, rcx);
__ j(not_equal, exit);
}
TEST(SmiOr) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1650,36 +1668,37 @@ void TestSmiXor(MacroAssembler* masm, Label* exit, int id, int x, int y) {
__ Move(rdx, Smi::FromInt(y));
__ Move(r8, Smi::FromInt(result));
__ SmiXor(r9, rcx, rdx);
- __ SmiCompare(r8, r9);
+ __ cmpq(r8, r9);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ SmiXor(rcx, rcx, rdx);
- __ SmiCompare(r8, rcx);
+ __ cmpq(r8, rcx);
__ j(not_equal, exit);
__ movq(rcx, r11);
__ incq(rax);
__ SmiXorConstant(r9, rcx, Smi::FromInt(y));
- __ SmiCompare(r8, r9);
+ __ cmpq(r8, r9);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ SmiXorConstant(rcx, rcx, Smi::FromInt(y));
- __ SmiCompare(r8, rcx);
+ __ cmpq(r8, rcx);
__ j(not_equal, exit);
}
TEST(SmiXor) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1731,21 +1750,22 @@ void TestSmiNot(MacroAssembler* masm, Label* exit, int id, int x) {
__ movq(r11, rcx);
__ SmiNot(r9, rcx);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx);
+ __ cmpq(r11, rcx);
__ j(not_equal, exit);
__ incq(rax);
__ SmiNot(rcx, rcx);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
}
TEST(SmiNot) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1797,7 +1817,7 @@ void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
__ SmiShiftLeftConstant(r9, rcx, shift);
__ incq(rax);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -1805,7 +1825,7 @@ void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
__ SmiShiftLeftConstant(rcx, rcx, shift);
__ incq(rax);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -1814,7 +1834,7 @@ void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
__ SmiShiftLeft(r9, rdx, rcx);
__ incq(rax);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -1823,7 +1843,7 @@ void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
__ SmiShiftLeft(r9, rdx, r11);
__ incq(rax);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -1832,7 +1852,7 @@ void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
__ SmiShiftLeft(rdx, rdx, r11);
__ incq(rax);
- __ SmiCompare(rdx, r8);
+ __ cmpq(rdx, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -1841,6 +1861,7 @@ void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
TEST(SmiShiftLeft) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1893,7 +1914,7 @@ void TestSmiShiftLogicalRight(MacroAssembler* masm,
__ SmiShiftLogicalRightConstant(r9, rcx, shift, exit);
__ incq(rax);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -1902,7 +1923,7 @@ void TestSmiShiftLogicalRight(MacroAssembler* masm,
__ SmiShiftLogicalRight(r9, rdx, rcx, exit);
__ incq(rax);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -1911,7 +1932,7 @@ void TestSmiShiftLogicalRight(MacroAssembler* masm,
__ SmiShiftLogicalRight(r9, rdx, r11, exit);
__ incq(rax);
- __ SmiCompare(r9, r8);
+ __ cmpq(r9, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -1925,7 +1946,7 @@ void TestSmiShiftLogicalRight(MacroAssembler* masm,
__ bind(&fail_ok);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
__ incq(rax);
@@ -1936,7 +1957,7 @@ void TestSmiShiftLogicalRight(MacroAssembler* masm,
__ bind(&fail_ok3);
__ incq(rax);
- __ SmiCompare(rcx, r11);
+ __ cmpq(rcx, r11);
__ j(not_equal, exit);
__ addq(rax, Immediate(3));
@@ -1946,6 +1967,7 @@ void TestSmiShiftLogicalRight(MacroAssembler* masm,
TEST(SmiShiftLogicalRight) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -1997,7 +2019,7 @@ void TestSmiShiftArithmeticRight(MacroAssembler* masm,
__ Move(rcx, Smi::FromInt(x));
__ SmiShiftArithmeticRightConstant(rcx, rcx, shift);
- __ SmiCompare(rcx, r8);
+ __ cmpq(rcx, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -2005,7 +2027,7 @@ void TestSmiShiftArithmeticRight(MacroAssembler* masm,
__ Move(r11, Smi::FromInt(shift));
__ SmiShiftArithmeticRight(rdx, rdx, r11);
- __ SmiCompare(rdx, r8);
+ __ cmpq(rdx, r8);
__ j(not_equal, exit);
__ incq(rax);
@@ -2014,6 +2036,7 @@ void TestSmiShiftArithmeticRight(MacroAssembler* masm,
TEST(SmiShiftArithmeticRight) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
@@ -2062,14 +2085,14 @@ void TestPositiveSmiPowerUp(MacroAssembler* masm, Label* exit, int id, int x) {
__ Move(rcx, Smi::FromInt(x));
__ movq(r11, rcx);
__ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rcx, power);
- __ SmiCompare(rdx, r8);
+ __ cmpq(rdx, r8);
__ j(not_equal, exit);
__ incq(rax);
- __ SmiCompare(r11, rcx); // rcx unchanged.
+ __ cmpq(r11, rcx); // rcx unchanged.
__ j(not_equal, exit);
__ incq(rax);
__ PositiveSmiTimesPowerOfTwoToInteger64(rcx, rcx, power);
- __ SmiCompare(rdx, r8);
+ __ cmpq(rdx, r8);
__ j(not_equal, exit);
__ incq(rax);
}
@@ -2077,10 +2100,11 @@ void TestPositiveSmiPowerUp(MacroAssembler* masm, Label* exit, int id, int x) {
TEST(PositiveSmiTimesPowerOfTwoToInteger64) {
+ v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer =
- static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
+ static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4,
&actual_size,
true));
CHECK(buffer);
@@ -2116,6 +2140,7 @@ TEST(PositiveSmiTimesPowerOfTwoToInteger64) {
TEST(OperandOffset) {
+ v8::internal::V8::Initialize(NULL);
int data[256];
for (int i = 0; i < 256; i++) { data[i] = i * 0x01010101; }
@@ -2150,7 +2175,7 @@ TEST(OperandOffset) {
__ push(Immediate(0x108));
__ push(Immediate(0x109)); // <-- rsp
// rbp = rsp[9]
- // r12 = rsp[3]
+ // r15 = rsp[3]
// rbx = rsp[5]
// r13 = rsp[7]
__ lea(r14, Operand(rsp, 3 * kPointerSize));
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 3e3175e7..6d1b5ce6 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -31,7 +31,6 @@
#include "global-handles.h"
#include "snapshot.h"
-#include "top.h"
#include "cctest.h"
using namespace v8::internal;
@@ -79,7 +78,7 @@ TEST(Promotion) {
// from new space.
FLAG_gc_global = true;
FLAG_always_compact = true;
- Heap::ConfigureHeap(2*256*KB, 4*MB, 4*MB);
+ HEAP->ConfigureHeap(2*256*KB, 4*MB, 4*MB);
InitializeVM();
@@ -87,25 +86,25 @@ TEST(Promotion) {
// Allocate a fixed array in the new space.
int array_size =
- (Heap::MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
+ (HEAP->MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
(kPointerSize * 4);
- Object* obj = Heap::AllocateFixedArray(array_size)->ToObjectChecked();
+ Object* obj = HEAP->AllocateFixedArray(array_size)->ToObjectChecked();
Handle<FixedArray> array(FixedArray::cast(obj));
// Array should be in the new space.
- CHECK(Heap::InSpace(*array, NEW_SPACE));
+ CHECK(HEAP->InSpace(*array, NEW_SPACE));
// Call the m-c collector, so array becomes an old object.
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
// Array now sits in the old space
- CHECK(Heap::InSpace(*array, OLD_POINTER_SPACE));
+ CHECK(HEAP->InSpace(*array, OLD_POINTER_SPACE));
}
TEST(NoPromotion) {
- Heap::ConfigureHeap(2*256*KB, 4*MB, 4*MB);
+ HEAP->ConfigureHeap(2*256*KB, 4*MB, 4*MB);
// Test the situation that some objects in new space are promoted to
// the old space
@@ -114,23 +113,23 @@ TEST(NoPromotion) {
v8::HandleScope sc;
// Do a mark compact GC to shrink the heap.
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
// Allocate a big Fixed array in the new space.
- int size = (Heap::MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
+ int size = (HEAP->MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
kPointerSize;
- Object* obj = Heap::AllocateFixedArray(size)->ToObjectChecked();
+ Object* obj = HEAP->AllocateFixedArray(size)->ToObjectChecked();
Handle<FixedArray> array(FixedArray::cast(obj));
// Array still stays in the new space.
- CHECK(Heap::InSpace(*array, NEW_SPACE));
+ CHECK(HEAP->InSpace(*array, NEW_SPACE));
// Allocate objects in the old space until out of memory.
FixedArray* host = *array;
while (true) {
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArray(100, TENURED);
+ { MaybeObject* maybe_obj = HEAP->AllocateFixedArray(100, TENURED);
if (!maybe_obj->ToObject(&obj)) break;
}
@@ -139,10 +138,10 @@ TEST(NoPromotion) {
}
// Call mark compact GC, and it should pass.
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
// array should not be promoted because the old space is full.
- CHECK(Heap::InSpace(*array, NEW_SPACE));
+ CHECK(HEAP->InSpace(*array, NEW_SPACE));
}
@@ -151,90 +150,86 @@ TEST(MarkCompactCollector) {
v8::HandleScope sc;
// call mark-compact when heap is empty
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
// keep allocating garbage in new space until it fails
const int ARRAY_SIZE = 100;
Object* array;
MaybeObject* maybe_array;
do {
- maybe_array = Heap::AllocateFixedArray(ARRAY_SIZE);
+ maybe_array = HEAP->AllocateFixedArray(ARRAY_SIZE);
} while (maybe_array->ToObject(&array));
- Heap::CollectGarbage(NEW_SPACE);
+ HEAP->CollectGarbage(NEW_SPACE);
- array = Heap::AllocateFixedArray(ARRAY_SIZE)->ToObjectChecked();
+ array = HEAP->AllocateFixedArray(ARRAY_SIZE)->ToObjectChecked();
// keep allocating maps until it fails
Object* mapp;
MaybeObject* maybe_mapp;
do {
- maybe_mapp = Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ maybe_mapp = HEAP->AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
} while (maybe_mapp->ToObject(&mapp));
- Heap::CollectGarbage(MAP_SPACE);
- mapp = Heap::AllocateMap(JS_OBJECT_TYPE,
+ HEAP->CollectGarbage(MAP_SPACE);
+ mapp = HEAP->AllocateMap(JS_OBJECT_TYPE,
JSObject::kHeaderSize)->ToObjectChecked();
// allocate a garbage
String* func_name =
- String::cast(Heap::LookupAsciiSymbol("theFunction")->ToObjectChecked());
+ String::cast(HEAP->LookupAsciiSymbol("theFunction")->ToObjectChecked());
SharedFunctionInfo* function_share = SharedFunctionInfo::cast(
- Heap::AllocateSharedFunctionInfo(func_name)->ToObjectChecked());
+ HEAP->AllocateSharedFunctionInfo(func_name)->ToObjectChecked());
JSFunction* function = JSFunction::cast(
- Heap::AllocateFunction(*Top::function_map(),
+ HEAP->AllocateFunction(*Isolate::Current()->function_map(),
function_share,
- Heap::undefined_value())->ToObjectChecked());
+ HEAP->undefined_value())->ToObjectChecked());
Map* initial_map =
- Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE,
+ Map::cast(HEAP->AllocateMap(JS_OBJECT_TYPE,
JSObject::kHeaderSize)->ToObjectChecked());
function->set_initial_map(initial_map);
- Top::context()->global()->SetProperty(func_name,
- function,
- NONE,
- kNonStrictMode)->ToObjectChecked();
+ Isolate::Current()->context()->global()->SetProperty(
+ func_name, function, NONE, kNonStrictMode)->ToObjectChecked();
- JSObject* obj =
- JSObject::cast(Heap::AllocateJSObject(function)->ToObjectChecked());
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ JSObject* obj = JSObject::cast(
+ HEAP->AllocateJSObject(function)->ToObjectChecked());
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
func_name =
- String::cast(Heap::LookupAsciiSymbol("theFunction")->ToObjectChecked());
- CHECK(Top::context()->global()->HasLocalProperty(func_name));
- Object* func_value =
- Top::context()->global()->GetProperty(func_name)->ToObjectChecked();
+ String::cast(HEAP->LookupAsciiSymbol("theFunction")->ToObjectChecked());
+ CHECK(Isolate::Current()->context()->global()->HasLocalProperty(func_name));
+ Object* func_value = Isolate::Current()->context()->global()->
+ GetProperty(func_name)->ToObjectChecked();
CHECK(func_value->IsJSFunction());
function = JSFunction::cast(func_value);
- obj = JSObject::cast(Heap::AllocateJSObject(function)->ToObjectChecked());
+ obj = JSObject::cast(HEAP->AllocateJSObject(function)->ToObjectChecked());
String* obj_name =
- String::cast(Heap::LookupAsciiSymbol("theObject")->ToObjectChecked());
- Top::context()->global()->SetProperty(obj_name,
- obj,
- NONE,
- kNonStrictMode)->ToObjectChecked();
+ String::cast(HEAP->LookupAsciiSymbol("theObject")->ToObjectChecked());
+ Isolate::Current()->context()->global()->SetProperty(
+ obj_name, obj, NONE, kNonStrictMode)->ToObjectChecked();
String* prop_name =
- String::cast(Heap::LookupAsciiSymbol("theSlot")->ToObjectChecked());
+ String::cast(HEAP->LookupAsciiSymbol("theSlot")->ToObjectChecked());
obj->SetProperty(prop_name,
Smi::FromInt(23),
NONE,
kNonStrictMode)->ToObjectChecked();
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
obj_name =
- String::cast(Heap::LookupAsciiSymbol("theObject")->ToObjectChecked());
- CHECK(Top::context()->global()->HasLocalProperty(obj_name));
- CHECK(Top::context()->global()->
- GetProperty(obj_name)->ToObjectChecked()->IsJSObject());
- obj = JSObject::cast(
- Top::context()->global()->GetProperty(obj_name)->ToObjectChecked());
+ String::cast(HEAP->LookupAsciiSymbol("theObject")->ToObjectChecked());
+ CHECK(Isolate::Current()->context()->global()->HasLocalProperty(obj_name));
+ CHECK(Isolate::Current()->context()->global()->
+ GetProperty(obj_name)->ToObjectChecked()->IsJSObject());
+ obj = JSObject::cast(Isolate::Current()->context()->global()->
+ GetProperty(obj_name)->ToObjectChecked());
prop_name =
- String::cast(Heap::LookupAsciiSymbol("theSlot")->ToObjectChecked());
- CHECK(obj->GetProperty(prop_name)->ToObjectChecked() == Smi::FromInt(23));
+ String::cast(HEAP->LookupAsciiSymbol("theSlot")->ToObjectChecked());
+ CHECK(obj->GetProperty(prop_name) == Smi::FromInt(23));
}
static Handle<Map> CreateMap() {
- return Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ return FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
}
@@ -246,20 +241,20 @@ TEST(MapCompact) {
v8::HandleScope sc;
// keep allocating maps while pointers are still encodable and thus
// mark compact is permitted.
- Handle<JSObject> root = Factory::NewJSObjectFromMap(CreateMap());
+ Handle<JSObject> root = FACTORY->NewJSObjectFromMap(CreateMap());
do {
Handle<Map> map = CreateMap();
map->set_prototype(*root);
- root = Factory::NewJSObjectFromMap(map);
- } while (Heap::map_space()->MapPointersEncodable());
+ root = FACTORY->NewJSObjectFromMap(map);
+ } while (HEAP->map_space()->MapPointersEncodable());
}
// Now, as we don't have any handles to just allocated maps, we should
// be able to trigger map compaction.
// To give an additional chance to fail, try to force compaction which
// should be impossible right now.
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
// And now map pointers should be encodable again.
- CHECK(Heap::map_space()->MapPointersEncodable());
+ CHECK(HEAP->map_space()->MapPointersEncodable());
}
@@ -281,16 +276,16 @@ static void GCEpilogueCallbackFunc() {
TEST(GCCallback) {
InitializeVM();
- Heap::SetGlobalGCPrologueCallback(&GCPrologueCallbackFunc);
- Heap::SetGlobalGCEpilogueCallback(&GCEpilogueCallbackFunc);
+ HEAP->SetGlobalGCPrologueCallback(&GCPrologueCallbackFunc);
+ HEAP->SetGlobalGCEpilogueCallback(&GCEpilogueCallbackFunc);
// Scavenge does not call GC callback functions.
- Heap::PerformScavenge();
+ HEAP->PerformScavenge();
CHECK_EQ(0, gc_starts);
CHECK_EQ(gc_ends, gc_starts);
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
CHECK_EQ(1, gc_starts);
CHECK_EQ(gc_ends, gc_starts);
}
@@ -298,39 +293,51 @@ TEST(GCCallback) {
static int NumberOfWeakCalls = 0;
static void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) {
+ ASSERT(id == reinterpret_cast<void*>(1234));
NumberOfWeakCalls++;
handle.Dispose();
}
TEST(ObjectGroups) {
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
InitializeVM();
NumberOfWeakCalls = 0;
v8::HandleScope handle_scope;
Handle<Object> g1s1 =
- GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
+ global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
Handle<Object> g1s2 =
- GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
- GlobalHandles::MakeWeak(g1s1.location(),
- reinterpret_cast<void*>(1234),
- &WeakPointerCallback);
- GlobalHandles::MakeWeak(g1s2.location(),
- reinterpret_cast<void*>(1234),
- &WeakPointerCallback);
+ global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+ Handle<Object> g1c1 =
+ global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+ global_handles->MakeWeak(g1s1.location(),
+ reinterpret_cast<void*>(1234),
+ &WeakPointerCallback);
+ global_handles->MakeWeak(g1s2.location(),
+ reinterpret_cast<void*>(1234),
+ &WeakPointerCallback);
+ global_handles->MakeWeak(g1c1.location(),
+ reinterpret_cast<void*>(1234),
+ &WeakPointerCallback);
Handle<Object> g2s1 =
- GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
+ global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
Handle<Object> g2s2 =
- GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
- GlobalHandles::MakeWeak(g2s1.location(),
- reinterpret_cast<void*>(1234),
- &WeakPointerCallback);
- GlobalHandles::MakeWeak(g2s2.location(),
- reinterpret_cast<void*>(1234),
- &WeakPointerCallback);
-
- Handle<Object> root = GlobalHandles::Create(*g1s1); // make a root.
+ global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+ Handle<Object> g2c1 =
+ global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+ global_handles->MakeWeak(g2s1.location(),
+ reinterpret_cast<void*>(1234),
+ &WeakPointerCallback);
+ global_handles->MakeWeak(g2s2.location(),
+ reinterpret_cast<void*>(1234),
+ &WeakPointerCallback);
+ global_handles->MakeWeak(g2c1.location(),
+ reinterpret_cast<void*>(1234),
+ &WeakPointerCallback);
+
+ Handle<Object> root = global_handles->Create(*g1s1); // make a root.
// Connect group 1 and 2, make a cycle.
Handle<FixedArray>::cast(g1s2)->set(0, *g2s2);
@@ -338,31 +345,58 @@ TEST(ObjectGroups) {
{
Object** g1_objects[] = { g1s1.location(), g1s2.location() };
+ Object** g1_children[] = { g1c1.location() };
Object** g2_objects[] = { g2s1.location(), g2s2.location() };
- GlobalHandles::AddGroup(g1_objects, 2);
- GlobalHandles::AddGroup(g2_objects, 2);
+ Object** g2_children[] = { g2c1.location() };
+ global_handles->AddObjectGroup(g1_objects, 2, NULL);
+ global_handles->AddImplicitReferences(HeapObject::cast(*g1s1),
+ g1_children, 1);
+ global_handles->AddObjectGroup(g2_objects, 2, NULL);
+ global_handles->AddImplicitReferences(HeapObject::cast(*g2s2),
+ g2_children, 1);
}
// Do a full GC
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
// All object should be alive.
CHECK_EQ(0, NumberOfWeakCalls);
// Weaken the root.
- GlobalHandles::MakeWeak(root.location(),
- reinterpret_cast<void*>(1234),
- &WeakPointerCallback);
+ global_handles->MakeWeak(root.location(),
+ reinterpret_cast<void*>(1234),
+ &WeakPointerCallback);
+ // But make children strong roots---all the objects (except for children)
+ // should be collectable now.
+ global_handles->ClearWeakness(g1c1.location());
+ global_handles->ClearWeakness(g2c1.location());
// Groups are deleted, rebuild groups.
{
Object** g1_objects[] = { g1s1.location(), g1s2.location() };
+ Object** g1_children[] = { g1c1.location() };
Object** g2_objects[] = { g2s1.location(), g2s2.location() };
- GlobalHandles::AddGroup(g1_objects, 2);
- GlobalHandles::AddGroup(g2_objects, 2);
+ Object** g2_children[] = { g2c1.location() };
+ global_handles->AddObjectGroup(g1_objects, 2, NULL);
+ global_handles->AddImplicitReferences(HeapObject::cast(*g1s1),
+ g1_children, 1);
+ global_handles->AddObjectGroup(g2_objects, 2, NULL);
+ global_handles->AddImplicitReferences(HeapObject::cast(*g2s2),
+ g2_children, 1);
}
- Heap::CollectGarbage(OLD_POINTER_SPACE);
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
// All objects should be gone. 5 global handles in total.
CHECK_EQ(5, NumberOfWeakCalls);
+
+ // And now make children weak again and collect them.
+ global_handles->MakeWeak(g1c1.location(),
+ reinterpret_cast<void*>(1234),
+ &WeakPointerCallback);
+ global_handles->MakeWeak(g2c1.location(),
+ reinterpret_cast<void*>(1234),
+ &WeakPointerCallback);
+
+ HEAP->CollectGarbage(OLD_POINTER_SPACE);
+ CHECK_EQ(7, NumberOfWeakCalls);
}
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 8ee40385..98a5870a 100755
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -31,6 +31,7 @@
#include "v8.h"
+#include "isolate.h"
#include "token.h"
#include "scanner.h"
#include "parser.h"
@@ -153,7 +154,7 @@ TEST(ScanHTMLEndComments) {
// Parser/Scanner needs a stack limit.
int marker;
- i::StackGuard::SetStackLimit(
+ i::Isolate::Current()->stack_guard()->SetStackLimit(
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
for (int i = 0; tests[i]; i++) {
@@ -184,7 +185,7 @@ TEST(Preparsing) {
v8::Persistent<v8::Context> context = v8::Context::New();
v8::Context::Scope context_scope(context);
int marker;
- i::StackGuard::SetStackLimit(
+ i::Isolate::Current()->stack_guard()->SetStackLimit(
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
// Source containing functions that might be lazily compiled and all types
@@ -245,7 +246,7 @@ TEST(Preparsing) {
TEST(StandAlonePreParser) {
int marker;
- i::StackGuard::SetStackLimit(
+ i::Isolate::Current()->stack_guard()->SetStackLimit(
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
const char* programs[] = {
@@ -257,14 +258,14 @@ TEST(StandAlonePreParser) {
NULL
};
- uintptr_t stack_limit = i::StackGuard::real_climit();
+ uintptr_t stack_limit = ISOLATE->stack_guard()->real_climit();
for (int i = 0; programs[i]; i++) {
const char* program = programs[i];
i::Utf8ToUC16CharacterStream stream(
reinterpret_cast<const i::byte*>(program),
static_cast<unsigned>(strlen(program)));
i::CompleteParserRecorder log;
- i::V8JavaScriptScanner scanner;
+ i::V8JavaScriptScanner scanner(ISOLATE->scanner_constants());
scanner.Initialize(&stream);
v8::preparser::PreParser::PreParseResult result =
@@ -281,7 +282,7 @@ TEST(StandAlonePreParser) {
TEST(RegressChromium62639) {
int marker;
- i::StackGuard::SetStackLimit(
+ ISOLATE->stack_guard()->SetStackLimit(
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
const char* program = "var x = 'something';\n"
@@ -306,7 +307,7 @@ TEST(Regress928) {
// the block could be lazily compiled, and an extra, unexpected,
// entry was added to the data.
int marker;
- i::StackGuard::SetStackLimit(
+ ISOLATE->stack_guard()->SetStackLimit(
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
const char* program =
@@ -342,7 +343,7 @@ TEST(Regress928) {
TEST(PreParseOverflow) {
int marker;
- i::StackGuard::SetStackLimit(
+ ISOLATE->stack_guard()->SetStackLimit(
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
size_t kProgramSize = 1024 * 1024;
@@ -351,13 +352,13 @@ TEST(PreParseOverflow) {
memset(*program, '(', kProgramSize);
program[kProgramSize] = '\0';
- uintptr_t stack_limit = i::StackGuard::real_climit();
+ uintptr_t stack_limit = ISOLATE->stack_guard()->real_climit();
i::Utf8ToUC16CharacterStream stream(
reinterpret_cast<const i::byte*>(*program),
static_cast<unsigned>(kProgramSize));
i::CompleteParserRecorder log;
- i::V8JavaScriptScanner scanner;
+ i::V8JavaScriptScanner scanner(ISOLATE->scanner_constants());
scanner.Initialize(&stream);
@@ -405,10 +406,10 @@ void TestCharacterStream(const char* ascii_source,
}
i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
i::Handle<i::String> ascii_string(
- i::Factory::NewStringFromAscii(ascii_vector));
+ FACTORY->NewStringFromAscii(ascii_vector));
TestExternalResource resource(*uc16_buffer, length);
i::Handle<i::String> uc16_string(
- i::Factory::NewExternalStringFromTwoByte(&resource));
+ FACTORY->NewExternalStringFromTwoByte(&resource));
i::ExternalTwoByteStringUC16CharacterStream uc16_stream(
i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
@@ -575,7 +576,7 @@ void TestStreamScanner(i::UC16CharacterStream* stream,
i::Token::Value* expected_tokens,
int skip_pos = 0, // Zero means not skipping.
int skip_to = 0) {
- i::V8JavaScriptScanner scanner;
+ i::V8JavaScriptScanner scanner(ISOLATE->scanner_constants());
scanner.Initialize(stream);
int i = 0;
@@ -654,7 +655,7 @@ void TestScanRegExp(const char* re_source, const char* expected) {
i::Utf8ToUC16CharacterStream stream(
reinterpret_cast<const i::byte*>(re_source),
static_cast<unsigned>(strlen(re_source)));
- i::V8JavaScriptScanner scanner;
+ i::V8JavaScriptScanner scanner(ISOLATE->scanner_constants());
scanner.Initialize(&stream);
i::Token::Value start = scanner.peek();
diff --git a/test/cctest/test-platform-linux.cc b/test/cctest/test-platform-linux.cc
index e1a00e10..756b9473 100644
--- a/test/cctest/test-platform-linux.cc
+++ b/test/cctest/test-platform-linux.cc
@@ -67,6 +67,7 @@ TEST(BusyLock) {
TEST(VirtualMemory) {
+ OS::Setup();
VirtualMemory* vm = new VirtualMemory(1 * MB);
CHECK(vm->IsReserved());
void* block_addr = vm->address();
diff --git a/test/cctest/test-platform-tls.cc b/test/cctest/test-platform-tls.cc
new file mode 100644
index 00000000..b2cb101f
--- /dev/null
+++ b/test/cctest/test-platform-tls.cc
@@ -0,0 +1,66 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+//
+// Tests of fast TLS support.
+
+#include "v8.h"
+
+#include "cctest.h"
+#include "checks.h"
+#include "platform.h"
+
+using v8::internal::Thread;
+
+static const int kValueCount = 128;
+
+static Thread::LocalStorageKey keys[kValueCount];
+
+static void* GetValue(int num) {
+ return reinterpret_cast<void*>(static_cast<intptr_t>(num + 1));
+}
+
+static void DoTest() {
+ for (int i = 0; i < kValueCount; i++) {
+ CHECK(!Thread::HasThreadLocal(keys[i]));
+ }
+ for (int i = 0; i < kValueCount; i++) {
+ Thread::SetThreadLocal(keys[i], GetValue(i));
+ }
+ for (int i = 0; i < kValueCount; i++) {
+ CHECK(Thread::HasThreadLocal(keys[i]));
+ }
+ for (int i = 0; i < kValueCount; i++) {
+ CHECK_EQ(GetValue(i), Thread::GetThreadLocal(keys[i]));
+ CHECK_EQ(GetValue(i), Thread::GetExistingThreadLocal(keys[i]));
+ }
+ for (int i = 0; i < kValueCount; i++) {
+ Thread::SetThreadLocal(keys[i], GetValue(kValueCount - i - 1));
+ }
+ for (int i = 0; i < kValueCount; i++) {
+ CHECK(Thread::HasThreadLocal(keys[i]));
+ }
+ for (int i = 0; i < kValueCount; i++) {
+ CHECK_EQ(GetValue(kValueCount - i - 1),
+ Thread::GetThreadLocal(keys[i]));
+ CHECK_EQ(GetValue(kValueCount - i - 1),
+ Thread::GetExistingThreadLocal(keys[i]));
+ }
+}
+
+class TestThread : public Thread {
+ public:
+ TestThread() : Thread(NULL, "TestThread") {}
+
+ virtual void Run() {
+ DoTest();
+ }
+};
+
+TEST(FastTLS) {
+ for (int i = 0; i < kValueCount; i++) {
+ keys[i] = Thread::CreateThreadLocalKey();
+ }
+ DoTest();
+ TestThread thread;
+ thread.Start();
+ thread.Join();
+}
diff --git a/test/cctest/test-platform-win32.cc b/test/cctest/test-platform-win32.cc
index a5a6dd58..9bd0014c 100644
--- a/test/cctest/test-platform-win32.cc
+++ b/test/cctest/test-platform-win32.cc
@@ -13,6 +13,7 @@ using namespace ::v8::internal;
TEST(VirtualMemory) {
+ OS::Setup();
VirtualMemory* vm = new VirtualMemory(1 * MB);
CHECK(vm->IsReserved());
void* block_addr = vm->address();
diff --git a/test/cctest/test-profile-generator.cc b/test/cctest/test-profile-generator.cc
index c60d0720..fbe5834e 100644
--- a/test/cctest/test-profile-generator.cc
+++ b/test/cctest/test-profile-generator.cc
@@ -56,7 +56,7 @@ TEST(TokenEnumerator) {
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
}
CHECK(!i::TokenEnumeratorTester::token_removed(&te)->at(2));
- i::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
CHECK(i::TokenEnumeratorTester::token_removed(&te)->at(2));
CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index 51fef714..e7026d42 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -45,6 +45,10 @@
#include "arm/macro-assembler-arm.h"
#include "arm/regexp-macro-assembler-arm.h"
#endif
+#ifdef V8_TARGET_ARCH_MIPS
+#include "mips/macro-assembler-mips.h"
+#include "mips/regexp-macro-assembler-mips.h"
+#endif
#ifdef V8_TARGET_ARCH_X64
#include "x64/macro-assembler-x64.h"
#include "x64/regexp-macro-assembler-x64.h"
@@ -62,7 +66,7 @@ static bool CheckParse(const char* input) {
V8::Initialize(NULL);
v8::HandleScope scope;
ZoneScope zone_scope(DELETE_ON_EXIT);
- FlatStringReader reader(CStrVector(input));
+ FlatStringReader reader(Isolate::Current(), CStrVector(input));
RegExpCompileData result;
return v8::internal::RegExpParser::ParseRegExp(&reader, false, &result);
}
@@ -72,7 +76,7 @@ static SmartPointer<const char> Parse(const char* input) {
V8::Initialize(NULL);
v8::HandleScope scope;
ZoneScope zone_scope(DELETE_ON_EXIT);
- FlatStringReader reader(CStrVector(input));
+ FlatStringReader reader(Isolate::Current(), CStrVector(input));
RegExpCompileData result;
CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
CHECK(result.tree != NULL);
@@ -86,7 +90,7 @@ static bool CheckSimple(const char* input) {
v8::HandleScope scope;
unibrow::Utf8InputBuffer<> buffer(input, StrLength(input));
ZoneScope zone_scope(DELETE_ON_EXIT);
- FlatStringReader reader(CStrVector(input));
+ FlatStringReader reader(Isolate::Current(), CStrVector(input));
RegExpCompileData result;
CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
CHECK(result.tree != NULL);
@@ -104,7 +108,7 @@ static MinMaxPair CheckMinMaxMatch(const char* input) {
v8::HandleScope scope;
unibrow::Utf8InputBuffer<> buffer(input, StrLength(input));
ZoneScope zone_scope(DELETE_ON_EXIT);
- FlatStringReader reader(CStrVector(input));
+ FlatStringReader reader(Isolate::Current(), CStrVector(input));
RegExpCompileData result;
CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
CHECK(result.tree != NULL);
@@ -375,7 +379,7 @@ static void ExpectError(const char* input,
V8::Initialize(NULL);
v8::HandleScope scope;
ZoneScope zone_scope(DELETE_ON_EXIT);
- FlatStringReader reader(CStrVector(input));
+ FlatStringReader reader(Isolate::Current(), CStrVector(input));
RegExpCompileData result;
CHECK(!v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
CHECK(result.tree == NULL);
@@ -471,6 +475,7 @@ static void TestCharacterClassEscapes(uc16 c, bool (pred)(uc16 c)) {
TEST(CharacterClassEscapes) {
+ v8::internal::V8::Initialize(NULL);
TestCharacterClassEscapes('.', IsRegExpNewline);
TestCharacterClassEscapes('d', IsDigit);
TestCharacterClassEscapes('D', NotDigit);
@@ -483,12 +488,12 @@ TEST(CharacterClassEscapes) {
static RegExpNode* Compile(const char* input, bool multiline, bool is_ascii) {
V8::Initialize(NULL);
- FlatStringReader reader(CStrVector(input));
+ FlatStringReader reader(Isolate::Current(), CStrVector(input));
RegExpCompileData compile_data;
if (!v8::internal::RegExpParser::ParseRegExp(&reader, multiline,
&compile_data))
return NULL;
- Handle<String> pattern = Factory::NewStringFromUtf8(CStrVector(input));
+ Handle<String> pattern = FACTORY->NewStringFromUtf8(CStrVector(input));
RegExpEngine::Compile(&compile_data, false, multiline, pattern, is_ascii);
return compile_data.node;
}
@@ -538,6 +543,7 @@ static unsigned PseudoRandom(int i, int j) {
TEST(SplayTreeSimple) {
+ v8::internal::V8::Initialize(NULL);
static const unsigned kLimit = 1000;
ZoneScope zone_scope(DELETE_ON_EXIT);
ZoneSplayTree<TestConfig> tree;
@@ -590,6 +596,7 @@ TEST(SplayTreeSimple) {
TEST(DispatchTableConstruction) {
+ v8::internal::V8::Initialize(NULL);
// Initialize test data.
static const int kLimit = 1000;
static const int kRangeCount = 8;
@@ -667,13 +674,13 @@ typedef RegExpMacroAssemblerX64 ArchRegExpMacroAssembler;
#elif V8_TARGET_ARCH_ARM
typedef RegExpMacroAssemblerARM ArchRegExpMacroAssembler;
#elif V8_TARGET_ARCH_MIPS
-typedef RegExpMacroAssembler ArchRegExpMacroAssembler;
+typedef RegExpMacroAssemblerMIPS ArchRegExpMacroAssembler;
#endif
class ContextInitializer {
public:
ContextInitializer()
- : env_(), scope_(), zone_(DELETE_ON_EXIT), stack_guard_() {
+ : env_(), scope_(), zone_(DELETE_ON_EXIT) {
env_ = v8::Context::New();
env_->Enter();
}
@@ -685,7 +692,6 @@ class ContextInitializer {
v8::Persistent<v8::Context> env_;
v8::HandleScope scope_;
v8::internal::ZoneScope zone_;
- v8::internal::StackGuard stack_guard_;
};
@@ -701,7 +707,8 @@ static ArchRegExpMacroAssembler::Result Execute(Code* code,
start_offset,
input_start,
input_end,
- captures);
+ captures,
+ Isolate::Current());
}
@@ -713,12 +720,12 @@ TEST(MacroAssemblerNativeSuccess) {
m.Succeed();
- Handle<String> source = Factory::NewStringFromAscii(CStrVector(""));
+ Handle<String> source = FACTORY->NewStringFromAscii(CStrVector(""));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
int captures[4] = {42, 37, 87, 117};
- Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
+ Handle<String> input = FACTORY->NewStringFromAscii(CStrVector("foofoo"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
const byte* start_adr =
reinterpret_cast<const byte*>(seq_input->GetCharsAddress());
@@ -757,12 +764,12 @@ TEST(MacroAssemblerNativeSimple) {
m.Bind(&fail);
m.Fail();
- Handle<String> source = Factory::NewStringFromAscii(CStrVector("^foo"));
+ Handle<String> source = FACTORY->NewStringFromAscii(CStrVector("^foo"));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
int captures[4] = {42, 37, 87, 117};
- Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
+ Handle<String> input = FACTORY->NewStringFromAscii(CStrVector("foofoo"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -780,7 +787,7 @@ TEST(MacroAssemblerNativeSimple) {
CHECK_EQ(-1, captures[2]);
CHECK_EQ(-1, captures[3]);
- input = Factory::NewStringFromAscii(CStrVector("barbarbar"));
+ input = FACTORY->NewStringFromAscii(CStrVector("barbarbar"));
seq_input = Handle<SeqAsciiString>::cast(input);
start_adr = seq_input->GetCharsAddress();
@@ -813,14 +820,14 @@ TEST(MacroAssemblerNativeSimpleUC16) {
m.Bind(&fail);
m.Fail();
- Handle<String> source = Factory::NewStringFromAscii(CStrVector("^foo"));
+ Handle<String> source = FACTORY->NewStringFromAscii(CStrVector("^foo"));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
int captures[4] = {42, 37, 87, 117};
const uc16 input_data[6] = {'f', 'o', 'o', 'f', 'o', '\xa0'};
Handle<String> input =
- Factory::NewStringFromTwoByte(Vector<const uc16>(input_data, 6));
+ FACTORY->NewStringFromTwoByte(Vector<const uc16>(input_data, 6));
Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -839,7 +846,7 @@ TEST(MacroAssemblerNativeSimpleUC16) {
CHECK_EQ(-1, captures[3]);
const uc16 input_data2[9] = {'b', 'a', 'r', 'b', 'a', 'r', 'b', 'a', '\xa0'};
- input = Factory::NewStringFromTwoByte(Vector<const uc16>(input_data2, 9));
+ input = FACTORY->NewStringFromTwoByte(Vector<const uc16>(input_data2, 9));
seq_input = Handle<SeqTwoByteString>::cast(input);
start_adr = seq_input->GetCharsAddress();
@@ -871,11 +878,11 @@ TEST(MacroAssemblerNativeBacktrack) {
m.Bind(&backtrack);
m.Fail();
- Handle<String> source = Factory::NewStringFromAscii(CStrVector(".........."));
+ Handle<String> source = FACTORY->NewStringFromAscii(CStrVector(".........."));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
- Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
+ Handle<String> input = FACTORY->NewStringFromAscii(CStrVector("foofoo"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -912,11 +919,11 @@ TEST(MacroAssemblerNativeBackReferenceASCII) {
m.Bind(&missing_match);
m.Fail();
- Handle<String> source = Factory::NewStringFromAscii(CStrVector("^(..)..\1"));
+ Handle<String> source = FACTORY->NewStringFromAscii(CStrVector("^(..)..\1"));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
- Handle<String> input = Factory::NewStringFromAscii(CStrVector("fooofo"));
+ Handle<String> input = FACTORY->NewStringFromAscii(CStrVector("fooofo"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -958,13 +965,13 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
m.Bind(&missing_match);
m.Fail();
- Handle<String> source = Factory::NewStringFromAscii(CStrVector("^(..)..\1"));
+ Handle<String> source = FACTORY->NewStringFromAscii(CStrVector("^(..)..\1"));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
const uc16 input_data[6] = {'f', 0x2028, 'o', 'o', 'f', 0x2028};
Handle<String> input =
- Factory::NewStringFromTwoByte(Vector<const uc16>(input_data, 6));
+ FACTORY->NewStringFromTwoByte(Vector<const uc16>(input_data, 6));
Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -1013,11 +1020,11 @@ TEST(MacroAssemblernativeAtStart) {
m.CheckNotCharacter('b', &fail);
m.Succeed();
- Handle<String> source = Factory::NewStringFromAscii(CStrVector("(^f|ob)"));
+ Handle<String> source = FACTORY->NewStringFromAscii(CStrVector("(^f|ob)"));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
- Handle<String> input = Factory::NewStringFromAscii(CStrVector("foobar"));
+ Handle<String> input = FACTORY->NewStringFromAscii(CStrVector("foobar"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -1071,12 +1078,12 @@ TEST(MacroAssemblerNativeBackRefNoCase) {
m.Succeed();
Handle<String> source =
- Factory::NewStringFromAscii(CStrVector("^(abc)\1\1(?!\1)...(?!\1)"));
+ FACTORY->NewStringFromAscii(CStrVector("^(abc)\1\1(?!\1)...(?!\1)"));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
Handle<String> input =
- Factory::NewStringFromAscii(CStrVector("aBcAbCABCxYzab"));
+ FACTORY->NewStringFromAscii(CStrVector("aBcAbCABCxYzab"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -1169,13 +1176,13 @@ TEST(MacroAssemblerNativeRegisters) {
m.Fail();
Handle<String> source =
- Factory::NewStringFromAscii(CStrVector("<loop test>"));
+ FACTORY->NewStringFromAscii(CStrVector("<loop test>"));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
// String long enough for test (content doesn't matter).
Handle<String> input =
- Factory::NewStringFromAscii(CStrVector("foofoofoofoofoo"));
+ FACTORY->NewStringFromAscii(CStrVector("foofoofoofoofoo"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -1210,13 +1217,13 @@ TEST(MacroAssemblerStackOverflow) {
m.GoTo(&loop);
Handle<String> source =
- Factory::NewStringFromAscii(CStrVector("<stack overflow test>"));
+ FACTORY->NewStringFromAscii(CStrVector("<stack overflow test>"));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
// String long enough for test (content doesn't matter).
Handle<String> input =
- Factory::NewStringFromAscii(CStrVector("dummy"));
+ FACTORY->NewStringFromAscii(CStrVector("dummy"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -1229,8 +1236,8 @@ TEST(MacroAssemblerStackOverflow) {
NULL);
CHECK_EQ(NativeRegExpMacroAssembler::EXCEPTION, result);
- CHECK(Top::has_pending_exception());
- Top::clear_pending_exception();
+ CHECK(Isolate::Current()->has_pending_exception());
+ Isolate::Current()->clear_pending_exception();
}
@@ -1254,13 +1261,13 @@ TEST(MacroAssemblerNativeLotsOfRegisters) {
m.Succeed();
Handle<String> source =
- Factory::NewStringFromAscii(CStrVector("<huge register space test>"));
+ FACTORY->NewStringFromAscii(CStrVector("<huge register space test>"));
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
// String long enough for test (content doesn't matter).
Handle<String> input =
- Factory::NewStringFromAscii(CStrVector("sample text"));
+ FACTORY->NewStringFromAscii(CStrVector("sample text"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
@@ -1277,7 +1284,7 @@ TEST(MacroAssemblerNativeLotsOfRegisters) {
CHECK_EQ(0, captures[0]);
CHECK_EQ(42, captures[1]);
- Top::clear_pending_exception();
+ Isolate::Current()->clear_pending_exception();
}
#else // V8_INTERPRETED_REGEXP
@@ -1322,13 +1329,13 @@ TEST(MacroAssembler) {
v8::HandleScope scope;
- Handle<String> source = Factory::NewStringFromAscii(CStrVector("^f(o)o"));
+ Handle<String> source = FACTORY->NewStringFromAscii(CStrVector("^f(o)o"));
Handle<ByteArray> array = Handle<ByteArray>::cast(m.GetCode(source));
int captures[5];
const uc16 str1[] = {'f', 'o', 'o', 'b', 'a', 'r'};
Handle<String> f1_16 =
- Factory::NewStringFromTwoByte(Vector<const uc16>(str1, 6));
+ FACTORY->NewStringFromTwoByte(Vector<const uc16>(str1, 6));
CHECK(IrregexpInterpreter::Match(array, f1_16, captures, 0));
CHECK_EQ(0, captures[0]);
@@ -1339,7 +1346,7 @@ TEST(MacroAssembler) {
const uc16 str2[] = {'b', 'a', 'r', 'f', 'o', 'o'};
Handle<String> f2_16 =
- Factory::NewStringFromTwoByte(Vector<const uc16>(str2, 6));
+ FACTORY->NewStringFromTwoByte(Vector<const uc16>(str2, 6));
CHECK(!IrregexpInterpreter::Match(array, f2_16, captures, 0));
CHECK_EQ(42, captures[0]);
@@ -1349,6 +1356,7 @@ TEST(MacroAssembler) {
TEST(AddInverseToTable) {
+ v8::internal::V8::Initialize(NULL);
static const int kLimit = 1000;
static const int kRangeCount = 16;
for (int t = 0; t < 10; t++) {
@@ -1507,6 +1515,7 @@ static void TestSimpleRangeCaseIndependence(CharacterRange input,
TEST(CharacterRangeCaseIndependence) {
+ v8::internal::V8::Initialize(NULL);
TestSimpleRangeCaseIndependence(CharacterRange::Singleton('a'),
CharacterRange::Singleton('A'));
TestSimpleRangeCaseIndependence(CharacterRange::Singleton('z'),
@@ -1548,6 +1557,7 @@ static bool InClass(uc16 c, ZoneList<CharacterRange>* ranges) {
TEST(CharClassDifference) {
+ v8::internal::V8::Initialize(NULL);
ZoneScope zone_scope(DELETE_ON_EXIT);
ZoneList<CharacterRange>* base = new ZoneList<CharacterRange>(1);
base->Add(CharacterRange::Everything());
@@ -1574,6 +1584,7 @@ TEST(CharClassDifference) {
TEST(CanonicalizeCharacterSets) {
+ v8::internal::V8::Initialize(NULL);
ZoneScope scope(DELETE_ON_EXIT);
ZoneList<CharacterRange>* list = new ZoneList<CharacterRange>(4);
CharacterSet set(list);
@@ -1644,6 +1655,7 @@ static bool CharacterInSet(ZoneList<CharacterRange>* set, uc16 value) {
}
TEST(CharacterRangeMerge) {
+ v8::internal::V8::Initialize(NULL);
ZoneScope zone_scope(DELETE_ON_EXIT);
ZoneList<CharacterRange> l1(4);
ZoneList<CharacterRange> l2(4);
diff --git a/test/cctest/test-reloc-info.cc b/test/cctest/test-reloc-info.cc
index 2b9beac1..0378fb34 100644
--- a/test/cctest/test-reloc-info.cc
+++ b/test/cctest/test-reloc-info.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -42,24 +42,31 @@ static void WriteRinfo(RelocInfoWriter* writer,
// Tests that writing both types of positions and then reading either
// or both works as expected.
TEST(Positions) {
- const int instr_size = 10 << 10;
- const int reloc_size = 10 << 10;
- const int buf_size = instr_size + reloc_size;
- SmartPointer<byte> buf(new byte[buf_size]);
- byte* pc = *buf;
- CodeDesc desc = { *buf, buf_size, instr_size, reloc_size, NULL };
+ const int code_size = 10 * KB;
+ int relocation_info_size = 10 * KB;
+ const int buffer_size = code_size + relocation_info_size;
+ SmartPointer<byte> buffer(new byte[buffer_size]);
- RelocInfoWriter writer(*buf + buf_size, pc);
+ byte* pc = *buffer;
+ byte* buffer_end = *buffer + buffer_size;
+
+ RelocInfoWriter writer(buffer_end, pc);
+ byte* relocation_info_end = buffer_end - relocation_info_size;
for (int i = 0, pos = 0; i < 100; i++, pc += i, pos += i) {
RelocInfo::Mode mode = (i % 2 == 0) ?
RelocInfo::STATEMENT_POSITION : RelocInfo::POSITION;
WriteRinfo(&writer, pc, mode, pos);
+ CHECK(writer.pos() - RelocInfoWriter::kMaxSize >= relocation_info_end);
}
+ relocation_info_size = static_cast<int>(buffer_end - writer.pos());
+ CodeDesc desc = { *buffer, buffer_size, code_size,
+ relocation_info_size, NULL };
+
// Read only (non-statement) positions.
{
RelocIterator it(desc, RelocInfo::ModeMask(RelocInfo::POSITION));
- pc = *buf;
+ pc = *buffer;
for (int i = 0, pos = 0; i < 100; i++, pc += i, pos += i) {
RelocInfo::Mode mode = (i % 2 == 0) ?
RelocInfo::STATEMENT_POSITION : RelocInfo::POSITION;
@@ -76,7 +83,7 @@ TEST(Positions) {
// Read only statement positions.
{
RelocIterator it(desc, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
- pc = *buf;
+ pc = *buffer;
for (int i = 0, pos = 0; i < 100; i++, pc += i, pos += i) {
RelocInfo::Mode mode = (i % 2 == 0) ?
RelocInfo::STATEMENT_POSITION : RelocInfo::POSITION;
@@ -93,7 +100,7 @@ TEST(Positions) {
// Read both types of positions.
{
RelocIterator it(desc, RelocInfo::kPositionMask);
- pc = *buf;
+ pc = *buffer;
for (int i = 0, pos = 0; i < 100; i++, pc += i, pos += i) {
RelocInfo::Mode mode = (i % 2 == 0) ?
RelocInfo::STATEMENT_POSITION : RelocInfo::POSITION;
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index 80910c25..730d72a9 100644
--- a/test/cctest/test-serialize.cc
+++ b/test/cctest/test-serialize.cc
@@ -83,7 +83,7 @@ static int* counter_function(const char* name) {
template <class T>
static Address AddressOf(T id) {
- return ExternalReference(id).address();
+ return ExternalReference(id, i::Isolate::Current()).address();
}
@@ -99,70 +99,75 @@ static int make_code(TypeCode type, int id) {
TEST(ExternalReferenceEncoder) {
- StatsTable::SetCounterFunction(counter_function);
- Heap::Setup(false);
+ OS::Setup();
+ Isolate* isolate = i::Isolate::Current();
+ isolate->stats_table()->SetCounterFunction(counter_function);
+ HEAP->Setup(false);
ExternalReferenceEncoder encoder;
- CHECK_EQ(make_code(BUILTIN, Builtins::ArrayCode),
- Encode(encoder, Builtins::ArrayCode));
+ CHECK_EQ(make_code(BUILTIN, Builtins::kArrayCode),
+ Encode(encoder, Builtins::kArrayCode));
CHECK_EQ(make_code(v8::internal::RUNTIME_FUNCTION, Runtime::kAbort),
Encode(encoder, Runtime::kAbort));
CHECK_EQ(make_code(IC_UTILITY, IC::kLoadCallbackProperty),
Encode(encoder, IC_Utility(IC::kLoadCallbackProperty)));
ExternalReference keyed_load_function_prototype =
- ExternalReference(&Counters::keyed_load_function_prototype);
+ ExternalReference(isolate->counters()->keyed_load_function_prototype());
CHECK_EQ(make_code(STATS_COUNTER, Counters::k_keyed_load_function_prototype),
encoder.Encode(keyed_load_function_prototype.address()));
ExternalReference the_hole_value_location =
- ExternalReference::the_hole_value_location();
+ ExternalReference::the_hole_value_location(isolate);
CHECK_EQ(make_code(UNCLASSIFIED, 2),
encoder.Encode(the_hole_value_location.address()));
ExternalReference stack_limit_address =
- ExternalReference::address_of_stack_limit();
+ ExternalReference::address_of_stack_limit(isolate);
CHECK_EQ(make_code(UNCLASSIFIED, 4),
encoder.Encode(stack_limit_address.address()));
ExternalReference real_stack_limit_address =
- ExternalReference::address_of_real_stack_limit();
+ ExternalReference::address_of_real_stack_limit(isolate);
CHECK_EQ(make_code(UNCLASSIFIED, 5),
encoder.Encode(real_stack_limit_address.address()));
#ifdef ENABLE_DEBUGGER_SUPPORT
CHECK_EQ(make_code(UNCLASSIFIED, 15),
- encoder.Encode(ExternalReference::debug_break().address()));
+ encoder.Encode(ExternalReference::debug_break(isolate).address()));
#endif // ENABLE_DEBUGGER_SUPPORT
CHECK_EQ(make_code(UNCLASSIFIED, 10),
- encoder.Encode(ExternalReference::new_space_start().address()));
+ encoder.Encode(
+ ExternalReference::new_space_start(isolate).address()));
CHECK_EQ(make_code(UNCLASSIFIED, 3),
- encoder.Encode(ExternalReference::roots_address().address()));
+ encoder.Encode(ExternalReference::roots_address(isolate).address()));
}
TEST(ExternalReferenceDecoder) {
- StatsTable::SetCounterFunction(counter_function);
- Heap::Setup(false);
+ OS::Setup();
+ Isolate* isolate = i::Isolate::Current();
+ isolate->stats_table()->SetCounterFunction(counter_function);
+ HEAP->Setup(false);
ExternalReferenceDecoder decoder;
- CHECK_EQ(AddressOf(Builtins::ArrayCode),
- decoder.Decode(make_code(BUILTIN, Builtins::ArrayCode)));
+ CHECK_EQ(AddressOf(Builtins::kArrayCode),
+ decoder.Decode(make_code(BUILTIN, Builtins::kArrayCode)));
CHECK_EQ(AddressOf(Runtime::kAbort),
decoder.Decode(make_code(v8::internal::RUNTIME_FUNCTION,
Runtime::kAbort)));
CHECK_EQ(AddressOf(IC_Utility(IC::kLoadCallbackProperty)),
decoder.Decode(make_code(IC_UTILITY, IC::kLoadCallbackProperty)));
ExternalReference keyed_load_function =
- ExternalReference(&Counters::keyed_load_function_prototype);
+ ExternalReference(isolate->counters()->keyed_load_function_prototype());
CHECK_EQ(keyed_load_function.address(),
decoder.Decode(
make_code(STATS_COUNTER,
Counters::k_keyed_load_function_prototype)));
- CHECK_EQ(ExternalReference::the_hole_value_location().address(),
+ CHECK_EQ(ExternalReference::the_hole_value_location(isolate).address(),
decoder.Decode(make_code(UNCLASSIFIED, 2)));
- CHECK_EQ(ExternalReference::address_of_stack_limit().address(),
+ CHECK_EQ(ExternalReference::address_of_stack_limit(isolate).address(),
decoder.Decode(make_code(UNCLASSIFIED, 4)));
- CHECK_EQ(ExternalReference::address_of_real_stack_limit().address(),
+ CHECK_EQ(ExternalReference::address_of_real_stack_limit(isolate).address(),
decoder.Decode(make_code(UNCLASSIFIED, 5)));
#ifdef ENABLE_DEBUGGER_SUPPORT
- CHECK_EQ(ExternalReference::debug_break().address(),
+ CHECK_EQ(ExternalReference::debug_break(isolate).address(),
decoder.Decode(make_code(UNCLASSIFIED, 15)));
#endif // ENABLE_DEBUGGER_SUPPORT
- CHECK_EQ(ExternalReference::new_space_start().address(),
+ CHECK_EQ(ExternalReference::new_space_start(isolate).address(),
decoder.Decode(make_code(UNCLASSIFIED, 10)));
}
@@ -276,12 +281,12 @@ static void Deserialize() {
static void SanityCheck() {
v8::HandleScope scope;
#ifdef DEBUG
- Heap::Verify();
+ HEAP->Verify();
#endif
- CHECK(Top::global()->IsJSObject());
- CHECK(Top::global_context()->IsContext());
- CHECK(Heap::symbol_table()->IsSymbolTable());
- CHECK(!Factory::LookupAsciiSymbol("Empty")->IsFailure());
+ CHECK(Isolate::Current()->global()->IsJSObject());
+ CHECK(Isolate::Current()->global_context()->IsContext());
+ CHECK(HEAP->symbol_table()->IsSymbolTable());
+ CHECK(!FACTORY->LookupAsciiSymbol("Empty")->IsFailure());
}
@@ -291,7 +296,6 @@ DEPENDENT_TEST(Deserialize, Serialize) {
// serialize a snapshot in a VM that is booted from a snapshot.
if (!Snapshot::IsEnabled()) {
v8::HandleScope scope;
-
Deserialize();
v8::Persistent<v8::Context> env = v8::Context::New();
@@ -305,7 +309,6 @@ DEPENDENT_TEST(Deserialize, Serialize) {
DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
if (!Snapshot::IsEnabled()) {
v8::HandleScope scope;
-
Deserialize();
v8::Persistent<v8::Context> env = v8::Context::New();
@@ -319,7 +322,6 @@ DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
if (!Snapshot::IsEnabled()) {
v8::HandleScope scope;
-
Deserialize();
v8::Persistent<v8::Context> env = v8::Context::New();
@@ -337,7 +339,6 @@ DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
SerializeTwice) {
if (!Snapshot::IsEnabled()) {
v8::HandleScope scope;
-
Deserialize();
v8::Persistent<v8::Context> env = v8::Context::New();
@@ -361,11 +362,11 @@ TEST(PartialSerialization) {
// Make sure all builtin scripts are cached.
{ HandleScope scope;
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
- Bootstrapper::NativesSourceLookup(i);
+ Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
}
}
- Heap::CollectAllGarbage(true);
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
Object* raw_foo;
{
@@ -425,7 +426,7 @@ static void ReserveSpaceForPartialSnapshot(const char* file_name) {
#undef fscanf
#endif
fclose(fp);
- Heap::ReserveSpace(new_size,
+ HEAP->ReserveSpace(new_size,
pointer_size,
data_size,
code_size,
@@ -482,12 +483,12 @@ TEST(ContextSerialization) {
// Make sure all builtin scripts are cached.
{ HandleScope scope;
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
- Bootstrapper::NativesSourceLookup(i);
+ Isolate::Current()->bootstrapper()->NativesSourceLookup(i);
}
}
// If we don't do this then we end up with a stray root pointing at the
// context even after we have disposed of env.
- Heap::CollectAllGarbage(true);
+ HEAP->CollectAllGarbage(true);
int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
@@ -561,7 +562,7 @@ TEST(LinearAllocation) {
for (int size = 1000; size < 5 * MB; size += size >> 1) {
int new_space_size = (size < new_space_max) ? size : new_space_max;
- Heap::ReserveSpace(
+ HEAP->ReserveSpace(
new_space_size,
size, // Old pointer space.
size, // Old data space.
@@ -584,7 +585,7 @@ TEST(LinearAllocation) {
i + kSmallFixedArraySize <= new_space_size;
i += kSmallFixedArraySize) {
Object* obj =
- Heap::AllocateFixedArray(kSmallFixedArrayLength)->ToObjectChecked();
+ HEAP->AllocateFixedArray(kSmallFixedArrayLength)->ToObjectChecked();
if (new_last != NULL) {
CHECK(reinterpret_cast<char*>(obj) ==
reinterpret_cast<char*>(new_last) + kSmallFixedArraySize);
@@ -596,7 +597,7 @@ TEST(LinearAllocation) {
for (int i = 0;
i + kSmallFixedArraySize <= size;
i += kSmallFixedArraySize) {
- Object* obj = Heap::AllocateFixedArray(kSmallFixedArrayLength,
+ Object* obj = HEAP->AllocateFixedArray(kSmallFixedArrayLength,
TENURED)->ToObjectChecked();
int old_page_fullness = i % Page::kPageSize;
int page_fullness = (i + kSmallFixedArraySize) % Page::kPageSize;
@@ -614,7 +615,7 @@ TEST(LinearAllocation) {
Object* data_last = NULL;
for (int i = 0; i + kSmallStringSize <= size; i += kSmallStringSize) {
- Object* obj = Heap::AllocateRawAsciiString(kSmallStringLength,
+ Object* obj = HEAP->AllocateRawAsciiString(kSmallStringLength,
TENURED)->ToObjectChecked();
int old_page_fullness = i % Page::kPageSize;
int page_fullness = (i + kSmallStringSize) % Page::kPageSize;
@@ -632,7 +633,7 @@ TEST(LinearAllocation) {
Object* map_last = NULL;
for (int i = 0; i + kMapSize <= size; i += kMapSize) {
- Object* obj = Heap::AllocateMap(JS_OBJECT_TYPE,
+ Object* obj = HEAP->AllocateMap(JS_OBJECT_TYPE,
42 * kPointerSize)->ToObjectChecked();
int old_page_fullness = i % Page::kPageSize;
int page_fullness = (i + kMapSize) % Page::kPageSize;
@@ -654,7 +655,7 @@ TEST(LinearAllocation) {
AlwaysAllocateScope always;
int large_object_array_length =
(size - FixedArray::kHeaderSize) / kPointerSize;
- Object* obj = Heap::AllocateFixedArray(large_object_array_length,
+ Object* obj = HEAP->AllocateFixedArray(large_object_array_length,
TENURED)->ToObjectChecked();
CHECK(!obj->IsFailure());
}
diff --git a/test/cctest/test-sockets.cc b/test/cctest/test-sockets.cc
index 822a23fa..5246d097 100644
--- a/test/cctest/test-sockets.cc
+++ b/test/cctest/test-sockets.cc
@@ -10,8 +10,12 @@ using namespace ::v8::internal;
class SocketListenerThread : public Thread {
public:
- explicit SocketListenerThread(int port, int data_size)
- : port_(port), data_size_(data_size), server_(NULL), client_(NULL),
+ explicit SocketListenerThread(Isolate* isolate, int port, int data_size)
+ : Thread(isolate, "SocketListenerThread"),
+ port_(port),
+ data_size_(data_size),
+ server_(NULL),
+ client_(NULL),
listening_(OS::CreateSemaphore(0)) {
data_ = new char[data_size_];
}
@@ -88,7 +92,8 @@ static void SendAndReceive(int port, char *data, int len) {
OS::SNPrintF(Vector<char>(port_str, kPortBuferLen), "%d", port);
// Create a socket listener.
- SocketListenerThread* listener = new SocketListenerThread(port, len);
+ SocketListenerThread* listener = new SocketListenerThread(Isolate::Current(),
+ port, len);
listener->Start();
listener->WaitForListening();
diff --git a/test/cctest/test-spaces.cc b/test/cctest/test-spaces.cc
index 706c6bf9..de0c41e2 100644
--- a/test/cctest/test-spaces.cc
+++ b/test/cctest/test-spaces.cc
@@ -65,6 +65,8 @@ TEST(Page) {
Address page_start = RoundUp(start, Page::kPageSize);
Page* p = Page::FromAddress(page_start);
+ // Initialized Page has heap pointer, normally set by memory_allocator.
+ p->heap_ = HEAP;
CHECK(p->address() == page_start);
CHECK(p->is_valid());
@@ -90,37 +92,45 @@ TEST(Page) {
TEST(MemoryAllocator) {
- CHECK(Heap::ConfigureHeapDefault());
- CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
-
- OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
+ OS::Setup();
+ Isolate* isolate = Isolate::Current();
+ CHECK(HEAP->ConfigureHeapDefault());
+ CHECK(isolate->memory_allocator()->Setup(HEAP->MaxReserved(),
+ HEAP->MaxExecutableSize()));
+
+ OldSpace faked_space(HEAP,
+ HEAP->MaxReserved(),
+ OLD_POINTER_SPACE,
+ NOT_EXECUTABLE);
int total_pages = 0;
int requested = MemoryAllocator::kPagesPerChunk;
int allocated;
// If we request n pages, we should get n or n - 1.
Page* first_page =
- MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
+ isolate->memory_allocator()->AllocatePages(
+ requested, &allocated, &faked_space);
CHECK(first_page->is_valid());
CHECK(allocated == requested || allocated == requested - 1);
total_pages += allocated;
Page* last_page = first_page;
for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
- CHECK(MemoryAllocator::IsPageInSpace(p, &faked_space));
+ CHECK(isolate->memory_allocator()->IsPageInSpace(p, &faked_space));
last_page = p;
}
// Again, we should get n or n - 1 pages.
Page* others =
- MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
+ isolate->memory_allocator()->AllocatePages(
+ requested, &allocated, &faked_space);
CHECK(others->is_valid());
CHECK(allocated == requested || allocated == requested - 1);
total_pages += allocated;
- MemoryAllocator::SetNextPage(last_page, others);
+ isolate->memory_allocator()->SetNextPage(last_page, others);
int page_count = 0;
for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
- CHECK(MemoryAllocator::IsPageInSpace(p, &faked_space));
+ CHECK(isolate->memory_allocator()->IsPageInSpace(p, &faked_space));
page_count++;
}
CHECK(total_pages == page_count);
@@ -131,31 +141,34 @@ TEST(MemoryAllocator) {
// Freeing pages at the first chunk starting at or after the second page
// should free the entire second chunk. It will return the page it was passed
// (since the second page was in the first chunk).
- Page* free_return = MemoryAllocator::FreePages(second_page);
+ Page* free_return = isolate->memory_allocator()->FreePages(second_page);
CHECK(free_return == second_page);
- MemoryAllocator::SetNextPage(first_page, free_return);
+ isolate->memory_allocator()->SetNextPage(first_page, free_return);
// Freeing pages in the first chunk starting at the first page should free
// the first chunk and return an invalid page.
- Page* invalid_page = MemoryAllocator::FreePages(first_page);
+ Page* invalid_page = isolate->memory_allocator()->FreePages(first_page);
CHECK(!invalid_page->is_valid());
- MemoryAllocator::TearDown();
+ isolate->memory_allocator()->TearDown();
}
TEST(NewSpace) {
- CHECK(Heap::ConfigureHeapDefault());
- CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
+ OS::Setup();
+ CHECK(HEAP->ConfigureHeapDefault());
+ CHECK(Isolate::Current()->memory_allocator()->Setup(
+ HEAP->MaxReserved(), HEAP->MaxExecutableSize()));
- NewSpace new_space;
+ NewSpace new_space(HEAP);
void* chunk =
- MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
+ Isolate::Current()->memory_allocator()->ReserveInitialChunk(
+ 4 * HEAP->ReservedSemiSpaceSize());
CHECK(chunk != NULL);
Address start = RoundUp(static_cast<Address>(chunk),
- 2 * Heap::ReservedSemiSpaceSize());
- CHECK(new_space.Setup(start, 2 * Heap::ReservedSemiSpaceSize()));
+ 2 * HEAP->ReservedSemiSpaceSize());
+ CHECK(new_space.Setup(start, 2 * HEAP->ReservedSemiSpaceSize()));
CHECK(new_space.HasBeenSetup());
while (new_space.Available() >= Page::kMaxHeapObjectSize) {
@@ -165,24 +178,28 @@ TEST(NewSpace) {
}
new_space.TearDown();
- MemoryAllocator::TearDown();
+ Isolate::Current()->memory_allocator()->TearDown();
}
TEST(OldSpace) {
- CHECK(Heap::ConfigureHeapDefault());
- CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
+ OS::Setup();
+ CHECK(HEAP->ConfigureHeapDefault());
+ CHECK(Isolate::Current()->memory_allocator()->Setup(
+ HEAP->MaxReserved(), HEAP->MaxExecutableSize()));
- OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(),
+ OldSpace* s = new OldSpace(HEAP,
+ HEAP->MaxOldGenerationSize(),
OLD_POINTER_SPACE,
NOT_EXECUTABLE);
CHECK(s != NULL);
void* chunk =
- MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
+ Isolate::Current()->memory_allocator()->ReserveInitialChunk(
+ 4 * HEAP->ReservedSemiSpaceSize());
CHECK(chunk != NULL);
Address start = static_cast<Address>(chunk);
- size_t size = RoundUp(start, 2 * Heap::ReservedSemiSpaceSize()) - start;
+ size_t size = RoundUp(start, 2 * HEAP->ReservedSemiSpaceSize()) - start;
CHECK(s->Setup(start, size));
@@ -192,14 +209,15 @@ TEST(OldSpace) {
s->TearDown();
delete s;
- MemoryAllocator::TearDown();
+ Isolate::Current()->memory_allocator()->TearDown();
}
TEST(LargeObjectSpace) {
- CHECK(Heap::Setup(false));
+ OS::Setup();
+ CHECK(HEAP->Setup(false));
- LargeObjectSpace* lo = Heap::lo_space();
+ LargeObjectSpace* lo = HEAP->lo_space();
CHECK(lo != NULL);
Map* faked_map = reinterpret_cast<Map*>(HeapObject::FromAddress(0));
@@ -233,5 +251,5 @@ TEST(LargeObjectSpace) {
lo->TearDown();
delete lo;
- MemoryAllocator::TearDown();
+ Isolate::Current()->memory_allocator()->TearDown();
}
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index 3f02b32b..9c76d2c9 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -94,7 +94,7 @@ static void InitializeBuildingBlocks(
buf[j] = gen() % 65536;
}
building_blocks[i] =
- Factory::NewStringFromTwoByte(Vector<const uc16>(buf, len));
+ FACTORY->NewStringFromTwoByte(Vector<const uc16>(buf, len));
for (int j = 0; j < len; j++) {
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
}
@@ -106,19 +106,19 @@ static void InitializeBuildingBlocks(
buf[j] = gen() % 128;
}
building_blocks[i] =
- Factory::NewStringFromAscii(Vector<const char>(buf, len));
+ FACTORY->NewStringFromAscii(Vector<const char>(buf, len));
for (int j = 0; j < len; j++) {
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
}
break;
}
case 2: {
- uc16* buf = Zone::NewArray<uc16>(len);
+ uc16* buf = ZONE->NewArray<uc16>(len);
for (int j = 0; j < len; j++) {
buf[j] = gen() % 65536;
}
Resource* resource = new Resource(Vector<const uc16>(buf, len));
- building_blocks[i] = Factory::NewExternalStringFromTwoByte(resource);
+ building_blocks[i] = FACTORY->NewExternalStringFromTwoByte(resource);
for (int j = 0; j < len; j++) {
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
}
@@ -130,7 +130,7 @@ static void InitializeBuildingBlocks(
buf[j] = gen() % 128;
}
building_blocks[i] =
- Factory::NewStringFromAscii(Vector<const char>(buf, len));
+ FACTORY->NewStringFromAscii(Vector<const char>(buf, len));
for (int j = 0; j < len; j++) {
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
}
@@ -145,9 +145,9 @@ static void InitializeBuildingBlocks(
static Handle<String> ConstructLeft(
Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
int depth) {
- Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
+ Handle<String> answer = FACTORY->NewStringFromAscii(CStrVector(""));
for (int i = 0; i < depth; i++) {
- answer = Factory::NewConsString(
+ answer = FACTORY->NewConsString(
answer,
building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]);
}
@@ -158,9 +158,9 @@ static Handle<String> ConstructLeft(
static Handle<String> ConstructRight(
Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
int depth) {
- Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
+ Handle<String> answer = FACTORY->NewStringFromAscii(CStrVector(""));
for (int i = depth - 1; i >= 0; i--) {
- answer = Factory::NewConsString(
+ answer = FACTORY->NewConsString(
building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
answer);
}
@@ -177,7 +177,7 @@ static Handle<String> ConstructBalancedHelper(
return building_blocks[from % NUMBER_OF_BUILDING_BLOCKS];
}
if (to - from == 2) {
- return Factory::NewConsString(
+ return FACTORY->NewConsString(
building_blocks[from % NUMBER_OF_BUILDING_BLOCKS],
building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]);
}
@@ -185,7 +185,7 @@ static Handle<String> ConstructBalancedHelper(
ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
Handle<String> part2 =
ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
- return Factory::NewConsString(part1, part2);
+ return FACTORY->NewConsString(part1, part2);
}
@@ -286,12 +286,12 @@ TEST(DeepAscii) {
foo[i] = "foo "[i % 4];
}
Handle<String> string =
- Factory::NewStringFromAscii(Vector<const char>(foo, DEEP_ASCII_DEPTH));
- Handle<String> foo_string = Factory::NewStringFromAscii(CStrVector("foo"));
+ FACTORY->NewStringFromAscii(Vector<const char>(foo, DEEP_ASCII_DEPTH));
+ Handle<String> foo_string = FACTORY->NewStringFromAscii(CStrVector("foo"));
for (int i = 0; i < DEEP_ASCII_DEPTH; i += 10) {
- string = Factory::NewConsString(string, foo_string);
+ string = FACTORY->NewConsString(string, foo_string);
}
- Handle<String> flat_string = Factory::NewConsString(string, foo_string);
+ Handle<String> flat_string = FACTORY->NewConsString(string, foo_string);
FlattenString(flat_string);
for (int i = 0; i < 500; i++) {
@@ -365,7 +365,7 @@ TEST(ExternalShortStringAdd) {
// Generate short ascii and non-ascii external strings.
for (int i = 0; i <= kMaxLength; i++) {
- char* ascii = Zone::NewArray<char>(i + 1);
+ char* ascii = ZONE->NewArray<char>(i + 1);
for (int j = 0; j < i; j++) {
ascii[j] = 'a';
}
@@ -377,7 +377,7 @@ TEST(ExternalShortStringAdd) {
v8::String::NewExternal(ascii_resource);
ascii_external_strings->Set(v8::Integer::New(i), ascii_external_string);
- uc16* non_ascii = Zone::NewArray<uc16>(i + 1);
+ uc16* non_ascii = ZONE->NewArray<uc16>(i + 1);
for (int j = 0; j < i; j++) {
non_ascii[j] = 0x1234;
}
@@ -459,10 +459,10 @@ TEST(CachedHashOverflow) {
Handle<Smi> fortytwo(Smi::FromInt(42));
Handle<Smi> thirtyseven(Smi::FromInt(37));
Handle<Object> results[] = {
- Factory::undefined_value(),
+ FACTORY->undefined_value(),
fortytwo,
- Factory::undefined_value(),
- Factory::undefined_value(),
+ FACTORY->undefined_value(),
+ FACTORY->undefined_value(),
thirtyseven,
fortytwo,
thirtyseven // Bug yielded 42 here.
diff --git a/test/cctest/test-thread-termination.cc b/test/cctest/test-thread-termination.cc
index aed7466a..5635b176 100644
--- a/test/cctest/test-thread-termination.cc
+++ b/test/cctest/test-thread-termination.cc
@@ -159,6 +159,9 @@ TEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) {
class TerminatorThread : public v8::internal::Thread {
+ public:
+ explicit TerminatorThread(i::Isolate* isolate)
+ : Thread(isolate, "TerminatorThread") { }
void Run() {
semaphore->Wait();
CHECK(!v8::V8::IsExecutionTerminating());
@@ -171,7 +174,7 @@ class TerminatorThread : public v8::internal::Thread {
// from the side by another thread.
TEST(TerminateOnlyV8ThreadFromOtherThread) {
semaphore = v8::internal::OS::CreateSemaphore(0);
- TerminatorThread thread;
+ TerminatorThread thread(i::Isolate::Current());
thread.Start();
v8::HandleScope scope;
@@ -193,6 +196,8 @@ TEST(TerminateOnlyV8ThreadFromOtherThread) {
class LoopingThread : public v8::internal::Thread {
public:
+ explicit LoopingThread(i::Isolate* isolate)
+ : Thread(isolate, "LoopingThread") { }
void Run() {
v8::Locker locker;
v8::HandleScope scope;
@@ -225,9 +230,9 @@ TEST(TerminateMultipleV8Threads) {
v8::Locker::StartPreemption(1);
semaphore = v8::internal::OS::CreateSemaphore(0);
}
- LoopingThread thread1;
+ LoopingThread thread1(i::Isolate::Current());
thread1.Start();
- LoopingThread thread2;
+ LoopingThread thread2(i::Isolate::Current());
thread2.Start();
// Wait until both threads have signaled the semaphore.
semaphore->Wait();
diff --git a/test/cctest/test-threads.cc b/test/cctest/test-threads.cc
index 0f48e248..37f02050 100644
--- a/test/cctest/test-threads.cc
+++ b/test/cctest/test-threads.cc
@@ -64,6 +64,7 @@ static Turn turn = FILL_CACHE;
class ThreadA: public v8::internal::Thread {
public:
+ explicit ThreadA(i::Isolate* isolate) : Thread(isolate, "ThreadA") { }
void Run() {
v8::Locker locker;
v8::HandleScope scope;
@@ -99,6 +100,7 @@ class ThreadA: public v8::internal::Thread {
class ThreadB: public v8::internal::Thread {
public:
+ explicit ThreadB(i::Isolate* isolate) : Thread(isolate, "ThreadB") { }
void Run() {
do {
{
@@ -108,7 +110,7 @@ class ThreadB: public v8::internal::Thread {
v8::Context::Scope context_scope(v8::Context::New());
// Clear the caches by forcing major GC.
- v8::internal::Heap::CollectAllGarbage(false);
+ HEAP->CollectAllGarbage(false);
turn = SECOND_TIME_FILL_CACHE;
break;
}
@@ -123,8 +125,8 @@ class ThreadB: public v8::internal::Thread {
TEST(JSFunctionResultCachesInTwoThreads) {
v8::V8::Initialize();
- ThreadA threadA;
- ThreadB threadB;
+ ThreadA threadA(i::Isolate::Current());
+ ThreadB threadB(i::Isolate::Current());
threadA.Start();
threadB.Start();
diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc
index b48dcb8b..018018a1 100644
--- a/test/cctest/test-utils.cc
+++ b/test/cctest/test-utils.cc
@@ -103,7 +103,7 @@ void TestMemCopy(Vector<byte> src,
TEST(MemCopy) {
- V8::Initialize(NULL);
+ OS::Setup();
const int N = kMinComplexMemCopy + 128;
Vector<byte> buffer1 = Vector<byte>::New(N);
Vector<byte> buffer2 = Vector<byte>::New(N);
diff --git a/test/cctest/testcfg.py b/test/cctest/testcfg.py
index b15342ed..a137275f 100644
--- a/test/cctest/testcfg.py
+++ b/test/cctest/testcfg.py
@@ -34,11 +34,12 @@ import utils
class CcTestCase(test.TestCase):
- def __init__(self, path, executable, mode, raw_name, dependency, context):
+ def __init__(self, path, executable, mode, raw_name, dependency, context, variant_flags):
super(CcTestCase, self).__init__(context, path, mode)
self.executable = executable
self.raw_name = raw_name
self.dependency = dependency
+ self.variant_flags = variant_flags
def GetLabel(self):
return "%s %s %s" % (self.mode, self.path[-2], self.path[-1])
@@ -49,6 +50,8 @@ class CcTestCase(test.TestCase):
def BuildCommand(self, name):
serialization_file = join('obj', 'test', self.mode, 'serdes')
serialization_file += '_' + self.GetName()
+ serialization_file = join(self.context.buildspace, serialization_file)
+ serialization_file += ''.join(self.variant_flags).replace('-', '_')
serialization_option = '--testing_serialization_file=' + serialization_file
result = [ self.executable, name, serialization_option ]
result += self.context.GetVmFlags(self, self.mode)
@@ -74,10 +77,11 @@ class CcTestConfiguration(test.TestConfiguration):
def GetBuildRequirements(self):
return ['cctests']
- def ListTests(self, current_path, path, mode):
+ def ListTests(self, current_path, path, mode, variant_flags):
executable = join('obj', 'test', mode, 'cctest')
if utils.IsWindows():
executable += '.exe'
+ executable = join(self.context.buildspace, executable)
output = test.Execute([executable, '--list'], self.context)
if output.exit_code != 0:
print output.stdout
@@ -91,7 +95,7 @@ class CcTestConfiguration(test.TestConfiguration):
if dependency != '':
dependency = relative_path[0] + '/' + dependency
if self.Contains(path, full_path):
- result.append(CcTestCase(full_path, executable, mode, raw_test, dependency, self.context))
+ result.append(CcTestCase(full_path, executable, mode, raw_test, dependency, self.context, variant_flags))
result.sort()
return result
diff --git a/test/es5conform/es5conform.status b/test/es5conform/es5conform.status
index d6f7caf5..1dc90d32 100644
--- a/test/es5conform/es5conform.status
+++ b/test/es5conform/es5conform.status
@@ -239,20 +239,11 @@ chapter15/15.10/15.10.7/15.10.7.5/15.10.7.5-2: FAIL_OK
# Incorrect test - need double escape in eval.
chapter07/7.8/7.8.4/7.8.4-1-s: FAIL
-# arguments[i] remains same after changing actual parameters in strict mode
-chapter10/10.6/10.6-10-c-ii-1-s: FAIL
-# arguments[i] doesn't map to actual parameters in strict mode
-chapter10/10.6/10.6-10-c-ii-2-s: FAIL
-
-# Accessing caller property of Arguments object throws TypeError in strict mode
-chapter10/10.6/10.6-13-b-1-s: FAIL
-# arguments.caller exists in strict mode
-chapter10/10.6/10.6-13-b-2-s: FAIL
# arguments.caller is non-configurable in strict mode
+# Invalid test case. Checks for "writable == true" and presence of "put"..
chapter10/10.6/10.6-13-b-3-s: FAIL
-# Accessing callee property of Arguments object throws TypeError in strict mode
-chapter10/10.6/10.6-13-c-1-s: FAIL
# arguments.callee is non-configurable in strict mode
+# Invalid test case. Checks for "put" property accessor.
chapter10/10.6/10.6-13-c-3-s: FAIL
# simple assignment throws TypeError if LeftHandSide is a property reference
diff --git a/test/es5conform/testcfg.py b/test/es5conform/testcfg.py
index e3a60cc4..af74b8c5 100644
--- a/test/es5conform/testcfg.py
+++ b/test/es5conform/testcfg.py
@@ -73,7 +73,7 @@ class ES5ConformTestConfiguration(test.TestConfiguration):
def __init__(self, context, root):
super(ES5ConformTestConfiguration, self).__init__(context, root)
- def ListTests(self, current_path, path, mode):
+ def ListTests(self, current_path, path, mode, variant_flags):
tests = []
current_root = join(self.root, 'data', 'TestCases')
harness = []
diff --git a/test/message/testcfg.py b/test/message/testcfg.py
index 21a0428f..aabbfef9 100644
--- a/test/message/testcfg.py
+++ b/test/message/testcfg.py
@@ -103,7 +103,7 @@ class MessageTestConfiguration(test.TestConfiguration):
else:
return []
- def ListTests(self, current_path, path, mode):
+ def ListTests(self, current_path, path, mode, variant_flags):
mjsunit = [current_path + [t] for t in self.Ls(self.root)]
regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
diff --git a/test/mjsunit/accessors-on-global-object.js b/test/mjsunit/accessors-on-global-object.js
index 8d95692c..dc910b7e 100644
--- a/test/mjsunit/accessors-on-global-object.js
+++ b/test/mjsunit/accessors-on-global-object.js
@@ -28,7 +28,7 @@
// Test that installing a getter on the global object instead of a
// normal property works.
-var x = 0;
+x = 0;
function getX() { return x; }
@@ -41,7 +41,7 @@ for (var i = 0; i < 10; i++) {
// Test that installing a setter on the global object instead of a
// normal property works.
-var y = 0;
+y = 0;
var setter_y;
function setY(value) { y = value; }
@@ -67,6 +67,6 @@ for (var i = 0; i < 10; i++) {
assertEquals(i < 5 ? 42 : 0, getZ());
if (i == 4) {
delete z;
- var z = 0;
+ z = 0;
}
}
diff --git a/test/mjsunit/bitops-info.js b/test/mjsunit/bitops-info.js
index 4660fdf9..4b114c54 100644
--- a/test/mjsunit/bitops-info.js
+++ b/test/mjsunit/bitops-info.js
@@ -37,7 +37,6 @@ function hidden_int32() {
return 1600822924; // It's a signed Int32.
}
-
function f() {
var x = non_int32(); // Not a constant.
var y = hidden_smi(); // Not a constant.
@@ -66,6 +65,13 @@ function f() {
assertEquals(46512102 & 2600822924, x & y, "10rev");
assertEquals(1600822924 & 2600822924, x & z, "11rev");
+ assertEquals((46512102 & -0x20123456) | 1, (y & -0x20123456) | 1, "12");
+ assertEquals((1600822924 & -0x20123456) | 1, (z & -0x20123456) | 1, "13");
+ assertEquals((2600822924 & -0x20123456) | 1, (x & -0x20123456) | 1, "14");
+ assertEquals((46512102 & -0x20123456) | 1, (-0x20123456 & y) | 1, "12rev");
+ assertEquals((1600822924 & -0x20123456) | 1, (-0x20123456 & z) | 1, "13rev");
+ assertEquals((2600822924 & -0x20123456) | 1, (-0x20123456 & x) | 1, "14rev");
+
assertEquals(2600822924 & 2600822924, x & x, "xx");
assertEquals(y, y & y, "yy");
assertEquals(z, z & z, "zz");
diff --git a/test/mjsunit/compiler/array-length.js b/test/mjsunit/compiler/array-length.js
index 7adb9abb..126c7a02 100644
--- a/test/mjsunit/compiler/array-length.js
+++ b/test/mjsunit/compiler/array-length.js
@@ -36,7 +36,7 @@ function Test(a0, a2, a5) {
var a0 = [];
var a2 = [1,2];
var a5 = [1,2,3,4,5];
-for (var i = 0; i < 10000000; i++) Test(a0, a2, a5);
+for (var i = 0; i < 100000; i++) Test(a0, a2, a5);
assertEquals("undefined", typeof(ArrayLength(0)));
-for (var i = 0; i < 10000000; i++) Test(a0, a2, a5);
+for (var i = 0; i < 100000; i++) Test(a0, a2, a5);
assertEquals(4, ArrayLength("hest"));
diff --git a/test/mjsunit/compiler/pic.js b/test/mjsunit/compiler/pic.js
index a0b5d8f9..06f2b3eb 100644
--- a/test/mjsunit/compiler/pic.js
+++ b/test/mjsunit/compiler/pic.js
@@ -53,7 +53,7 @@ o1.f = o2.f = o3.f = function() { return 99; }
// Run the test until we're fairly sure we've optimized the
// polymorphic property access.
-for (var i = 0; i < 1000000; i++) {
+for (var i = 0; i < 100000; i++) {
Test(o1);
Test(o2);
Test(o3);
diff --git a/test/mjsunit/compiler/regress-loadfield.js b/test/mjsunit/compiler/regress-loadfield.js
new file mode 100644
index 00000000..a2028919
--- /dev/null
+++ b/test/mjsunit/compiler/regress-loadfield.js
@@ -0,0 +1,65 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Regression test for GVN on field loads.
+
+function bar() {}
+
+// Make sure there is a transition on adding "bar" inobject property.
+var b = new bar();
+b.bar = "bar";
+
+function test(a) {
+ var b = new Array(10);
+ for (var i = 0; i < 10; i++) {
+ b[i] = new bar();
+ }
+
+ for (var i = 0; i < 10; i++) {
+ b[i].bar = a.foo;
+ }
+}
+
+// Create an object with fast backing store properties.
+var a = {};
+a.p1 = "";
+a.p2 = "";
+a.p3 = "";
+a.p4 = "";
+a.p5 = "";
+a.p6 = "";
+a.p7 = "";
+a.p8 = "";
+a.p9 = "";
+a.p10 = "";
+a.p11 = "";
+a.foo = "foo";
+for (var i = 0; i < 100000; i++) {
+ test(a);
+}
+
+test("");
diff --git a/test/mjsunit/math-sqrt.js b/test/mjsunit/math-sqrt.js
index fb00d5ba..43fbf6b2 100644
--- a/test/mjsunit/math-sqrt.js
+++ b/test/mjsunit/math-sqrt.js
@@ -29,7 +29,11 @@
function test(expected_sqrt, value) {
assertEquals(expected_sqrt, Math.sqrt(value));
- if (isFinite(value)) {
+ if (isFinite(value)) {
+ if (value === 0 && (1 / value) == -Infinity) {
+ // Math.pow(-0, 0.5) must be zero, but Math.sqrt(-0) is -0.
+ expected_sqrt = 0;
+ }
assertEquals(expected_sqrt, Math.pow(value, 0.5));
}
}
diff --git a/test/mjsunit/mjsunit.js b/test/mjsunit/mjsunit.js
index fe580f35..436bdc81 100644
--- a/test/mjsunit/mjsunit.js
+++ b/test/mjsunit/mjsunit.js
@@ -41,15 +41,62 @@ MjsUnitAssertionError.prototype.toString = function () {
* the f-word and ignore all other lines.
*/
+function MjsUnitToString(value) {
+ switch (typeof value) {
+ case "string":
+ return JSON.stringify(value);
+ case "number":
+ if (value === 0 && (1 / value) < 0) return "-0";
+ case "boolean":
+ case "null":
+ case "undefined":
+ case "function":
+ return String(value);
+ case "object":
+ if (value === null) return "null";
+ var clazz = Object.prototype.toString.call(value);
+ clazz = clazz.substring(8, clazz.length - 1);
+ switch (clazz) {
+ case "Number":
+ case "String":
+ case "Boolean":
+ case "Date":
+ return clazz + "(" + MjsUnitToString(value.valueOf()) + ")";
+ case "RegExp":
+ return value.toString();
+ case "Array":
+ return "[" + value.map(MjsUnitArrayElementToString).join(",") + "]";
+ case "Object":
+ break;
+ default:
+ return clazz + "()";
+ }
+ // [[Class]] is "Object".
+ var constructor = value.constructor.name;
+ if (name) return name + "()";
+ return "Object()";
+ default:
+ return "-- unknown value --";
+ }
+}
+
+
+function MjsUnitArrayElementToString(value, index, array) {
+ if (value === undefined && !(index in array)) return "";
+ return MjsUnitToString(value);
+}
+
+
function fail(expected, found, name_opt) {
- var start;
+ var message = "Fail" + "ure";
if (name_opt) {
// Fix this when we ditch the old test runner.
- start = "Fail" + "ure (" + name_opt + "): ";
- } else {
- start = "Fail" + "ure:";
+ message += " (" + name_opt + ")";
}
- throw new MjsUnitAssertionError(start + " expected <" + expected + "> found <" + found + ">");
+
+ message += ": expected <" + MjsUnitToString(expected) +
+ "> found <" + MjsUnitToString(found) + ">";
+ throw new MjsUnitAssertionError(message);
}
@@ -73,13 +120,17 @@ function deepObjectEquals(a, b) {
function deepEquals(a, b) {
- if (a == b) return true;
+ if (a == b) {
+ // Check for -0.
+ if (a === 0 && b === 0) return (1 / a) === (1 / b);
+ return true;
+ }
if (typeof a == "number" && typeof b == "number" && isNaN(a) && isNaN(b)) {
return true;
}
if (a == null || b == null) return false;
if (a.constructor === RegExp || b.constructor === RegExp) {
- return (a.constructor === b.constructor) && (a.toString === b.toString);
+ return (a.constructor === b.constructor) && (a.toString() === b.toString());
}
if ((typeof a) !== 'object' || (typeof b) !== 'object' ||
(a === null) || (b === null))
@@ -205,7 +256,7 @@ function assertDoesNotThrow(code) {
function assertUnreachable(name_opt) {
// Fix this when we ditch the old test runner.
- var message = "Fail" + "ure: unreachable"
+ var message = "Fail" + "ure: unreachable";
if (name_opt) {
message += " - " + name_opt;
}
diff --git a/test/mjsunit/mul-exhaustive.js b/test/mjsunit/mul-exhaustive.js
index 452f9332..12689db3 100644
--- a/test/mjsunit/mul-exhaustive.js
+++ b/test/mjsunit/mul-exhaustive.js
@@ -26,41 +26,64 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
var x;
-var y;
-var a;
-function f(a, y) {
- assertEquals(a, x * y);
- assertEquals(a, -x * -y);
- assertEquals(-a, -x * y);
- assertEquals(-a, x * -y);
- assertEquals(a, y * x);
- assertEquals(a, -y * -x);
- assertEquals(-a, y * -x);
- assertEquals(-a, -y * x);
+// Converts a number to string respecting -0.
+function stringify(n) {
+ if ((1 / n) === -Infinity) return "-0";
+ return String(n);
}
+function f(expected, y) {
+ function testEval(string, x, y) {
+ var mulFunction = Function("x, y", "return " + string);
+ return mulFunction(x, y);
+ }
+ function mulTest(expected, x, y) {
+ assertEquals(expected, x * y);
+ assertEquals(expected, testEval(stringify(x) + " * y", x, y));
+ assertEquals(expected, testEval("x * " + stringify(y), x, y));
+ assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y));
+ }
+ mulTest(expected, x, y);
+ mulTest(-expected, -x, y);
+ mulTest(-expected, x, -y);
+ mulTest(expected, -x, -y);
+ if (x === y) return; // Symmetric cases not necessary.
+ mulTest(expected, y, x);
+ mulTest(-expected, -y, x);
+ mulTest(-expected, y, -x);
+ mulTest(expected, -y, -x);
+}
+
+x = 0;
+f(0, 0);
x = 1;
+f(0, 0);
f(1, 1);
x = 2;
+f(0, 0);
f(2, 1);
f(4, 2);
x = 3;
+f(0, 0);
f(3, 1);
f(6, 2);
f(9, 3);
x = 4;
+f(0, 0);
f(4, 1);
f(8, 2);
f(12, 3);
f(16, 4);
x = 5;
+f(0, 0);
f(5, 1);
f(10, 2);
f(15, 3);
f(20, 4);
f(25, 5);
x = 7;
+f(0, 0);
f(7, 1);
f(14, 2);
f(21, 3);
@@ -68,6 +91,7 @@ f(28, 4);
f(35, 5);
f(49, 7);
x = 8;
+f(0, 0);
f(8, 1);
f(16, 2);
f(24, 3);
@@ -76,6 +100,7 @@ f(40, 5);
f(56, 7);
f(64, 8);
x = 9;
+f(0, 0);
f(9, 1);
f(18, 2);
f(27, 3);
@@ -85,6 +110,7 @@ f(63, 7);
f(72, 8);
f(81, 9);
x = 15;
+f(0, 0);
f(15, 1);
f(30, 2);
f(45, 3);
@@ -95,6 +121,7 @@ f(120, 8);
f(135, 9);
f(225, 15);
x = 16;
+f(0, 0);
f(16, 1);
f(32, 2);
f(48, 3);
@@ -106,6 +133,7 @@ f(144, 9);
f(240, 15);
f(256, 16);
x = 17;
+f(0, 0);
f(17, 1);
f(34, 2);
f(51, 3);
@@ -118,6 +146,7 @@ f(255, 15);
f(272, 16);
f(289, 17);
x = 31;
+f(0, 0);
f(31, 1);
f(62, 2);
f(93, 3);
@@ -131,6 +160,7 @@ f(496, 16);
f(527, 17);
f(961, 31);
x = 32;
+f(0, 0);
f(32, 1);
f(64, 2);
f(96, 3);
@@ -145,6 +175,7 @@ f(544, 17);
f(992, 31);
f(1024, 32);
x = 33;
+f(0, 0);
f(33, 1);
f(66, 2);
f(99, 3);
@@ -160,6 +191,7 @@ f(1023, 31);
f(1056, 32);
f(1089, 33);
x = 63;
+f(0, 0);
f(63, 1);
f(126, 2);
f(189, 3);
@@ -176,6 +208,7 @@ f(2016, 32);
f(2079, 33);
f(3969, 63);
x = 64;
+f(0, 0);
f(64, 1);
f(128, 2);
f(192, 3);
@@ -193,6 +226,7 @@ f(2112, 33);
f(4032, 63);
f(4096, 64);
x = 65;
+f(0, 0);
f(65, 1);
f(130, 2);
f(195, 3);
@@ -211,6 +245,7 @@ f(4095, 63);
f(4160, 64);
f(4225, 65);
x = 127;
+f(0, 0);
f(127, 1);
f(254, 2);
f(381, 3);
@@ -230,6 +265,7 @@ f(8128, 64);
f(8255, 65);
f(16129, 127);
x = 128;
+f(0, 0);
f(128, 1);
f(256, 2);
f(384, 3);
@@ -250,6 +286,7 @@ f(8320, 65);
f(16256, 127);
f(16384, 128);
x = 129;
+f(0, 0);
f(129, 1);
f(258, 2);
f(387, 3);
@@ -271,6 +308,7 @@ f(16383, 127);
f(16512, 128);
f(16641, 129);
x = 255;
+f(0, 0);
f(255, 1);
f(510, 2);
f(765, 3);
@@ -293,6 +331,7 @@ f(32640, 128);
f(32895, 129);
f(65025, 255);
x = 256;
+f(0, 0);
f(256, 1);
f(512, 2);
f(768, 3);
@@ -316,6 +355,7 @@ f(33024, 129);
f(65280, 255);
f(65536, 256);
x = 257;
+f(0, 0);
f(257, 1);
f(514, 2);
f(771, 3);
@@ -340,6 +380,7 @@ f(65535, 255);
f(65792, 256);
f(66049, 257);
x = 511;
+f(0, 0);
f(511, 1);
f(1022, 2);
f(1533, 3);
@@ -365,6 +406,7 @@ f(130816, 256);
f(131327, 257);
f(261121, 511);
x = 512;
+f(0, 0);
f(512, 1);
f(1024, 2);
f(1536, 3);
@@ -391,6 +433,7 @@ f(131584, 257);
f(261632, 511);
f(262144, 512);
x = 513;
+f(0, 0);
f(513, 1);
f(1026, 2);
f(1539, 3);
@@ -418,6 +461,7 @@ f(262143, 511);
f(262656, 512);
f(263169, 513);
x = 1023;
+f(0, 0);
f(1023, 1);
f(2046, 2);
f(3069, 3);
@@ -446,6 +490,7 @@ f(523776, 512);
f(524799, 513);
f(1046529, 1023);
x = 1024;
+f(0, 0);
f(1024, 1);
f(2048, 2);
f(3072, 3);
@@ -475,6 +520,7 @@ f(525312, 513);
f(1047552, 1023);
f(1048576, 1024);
x = 1025;
+f(0, 0);
f(1025, 1);
f(2050, 2);
f(3075, 3);
@@ -505,6 +551,7 @@ f(1048575, 1023);
f(1049600, 1024);
f(1050625, 1025);
x = 2047;
+f(0, 0);
f(2047, 1);
f(4094, 2);
f(6141, 3);
@@ -536,6 +583,7 @@ f(2096128, 1024);
f(2098175, 1025);
f(4190209, 2047);
x = 2048;
+f(0, 0);
f(2048, 1);
f(4096, 2);
f(6144, 3);
@@ -568,6 +616,7 @@ f(2099200, 1025);
f(4192256, 2047);
f(4194304, 2048);
x = 2049;
+f(0, 0);
f(2049, 1);
f(4098, 2);
f(6147, 3);
@@ -601,6 +650,7 @@ f(4194303, 2047);
f(4196352, 2048);
f(4198401, 2049);
x = 4095;
+f(0, 0);
f(4095, 1);
f(8190, 2);
f(12285, 3);
@@ -635,6 +685,7 @@ f(8386560, 2048);
f(8390655, 2049);
f(16769025, 4095);
x = 4096;
+f(0, 0);
f(4096, 1);
f(8192, 2);
f(12288, 3);
@@ -670,6 +721,7 @@ f(8392704, 2049);
f(16773120, 4095);
f(16777216, 4096);
x = 4097;
+f(0, 0);
f(4097, 1);
f(8194, 2);
f(12291, 3);
@@ -706,6 +758,7 @@ f(16777215, 4095);
f(16781312, 4096);
f(16785409, 4097);
x = 8191;
+f(0, 0);
f(8191, 1);
f(16382, 2);
f(24573, 3);
@@ -743,6 +796,7 @@ f(33550336, 4096);
f(33558527, 4097);
f(67092481, 8191);
x = 8192;
+f(0, 0);
f(8192, 1);
f(16384, 2);
f(24576, 3);
@@ -781,6 +835,7 @@ f(33562624, 4097);
f(67100672, 8191);
f(67108864, 8192);
x = 8193;
+f(0, 0);
f(8193, 1);
f(16386, 2);
f(24579, 3);
@@ -820,6 +875,7 @@ f(67108863, 8191);
f(67117056, 8192);
f(67125249, 8193);
x = 16383;
+f(0, 0);
f(16383, 1);
f(32766, 2);
f(49149, 3);
@@ -860,6 +916,7 @@ f(134209536, 8192);
f(134225919, 8193);
f(268402689, 16383);
x = 16384;
+f(0, 0);
f(16384, 1);
f(32768, 2);
f(49152, 3);
@@ -901,6 +958,7 @@ f(134234112, 8193);
f(268419072, 16383);
f(268435456, 16384);
x = 16385;
+f(0, 0);
f(16385, 1);
f(32770, 2);
f(49155, 3);
@@ -943,6 +1001,7 @@ f(268435455, 16383);
f(268451840, 16384);
f(268468225, 16385);
x = 32767;
+f(0, 0);
f(32767, 1);
f(65534, 2);
f(98301, 3);
@@ -986,6 +1045,7 @@ f(536854528, 16384);
f(536887295, 16385);
f(1073676289, 32767);
x = 32768;
+f(0, 0);
f(32768, 1);
f(65536, 2);
f(98304, 3);
@@ -1030,6 +1090,7 @@ f(536903680, 16385);
f(1073709056, 32767);
f(1073741824, 32768);
x = 32769;
+f(0, 0);
f(32769, 1);
f(65538, 2);
f(98307, 3);
@@ -1075,6 +1136,7 @@ f(1073741823, 32767);
f(1073774592, 32768);
f(1073807361, 32769);
x = 65535;
+f(0, 0);
f(65535, 1);
f(131070, 2);
f(196605, 3);
@@ -1121,6 +1183,7 @@ f(2147450880, 32768);
f(2147516415, 32769);
f(4294836225, 65535);
x = 65536;
+f(0, 0);
f(65536, 1);
f(131072, 2);
f(196608, 3);
@@ -1168,6 +1231,7 @@ f(2147549184, 32769);
f(4294901760, 65535);
f(4294967296, 65536);
x = 65537;
+f(0, 0);
f(65537, 1);
f(131074, 2);
f(196611, 3);
@@ -1216,6 +1280,7 @@ f(4294967295, 65535);
f(4295032832, 65536);
f(4295098369, 65537);
x = 131071;
+f(0, 0);
f(131071, 1);
f(262142, 2);
f(393213, 3);
@@ -1265,6 +1330,7 @@ f(8589869056, 65536);
f(8590000127, 65537);
f(17179607041, 131071);
x = 131072;
+f(0, 0);
f(131072, 1);
f(262144, 2);
f(393216, 3);
@@ -1315,6 +1381,7 @@ f(8590065664, 65537);
f(17179738112, 131071);
f(17179869184, 131072);
x = 131073;
+f(0, 0);
f(131073, 1);
f(262146, 2);
f(393219, 3);
@@ -1366,6 +1433,7 @@ f(17179869183, 131071);
f(17180000256, 131072);
f(17180131329, 131073);
x = 262143;
+f(0, 0);
f(262143, 1);
f(524286, 2);
f(786429, 3);
@@ -1418,6 +1486,7 @@ f(34359607296, 131072);
f(34359869439, 131073);
f(68718952449, 262143);
x = 262144;
+f(0, 0);
f(262144, 1);
f(524288, 2);
f(786432, 3);
@@ -1471,6 +1540,7 @@ f(34360000512, 131073);
f(68719214592, 262143);
f(68719476736, 262144);
x = 262145;
+f(0, 0);
f(262145, 1);
f(524290, 2);
f(786435, 3);
@@ -1525,6 +1595,7 @@ f(68719476735, 262143);
f(68719738880, 262144);
f(68720001025, 262145);
x = 524287;
+f(0, 0);
f(524287, 1);
f(1048574, 2);
f(1572861, 3);
@@ -1580,6 +1651,7 @@ f(137438691328, 262144);
f(137439215615, 262145);
f(274876858369, 524287);
x = 524288;
+f(0, 0);
f(524288, 1);
f(1048576, 2);
f(1572864, 3);
@@ -1636,6 +1708,7 @@ f(137439477760, 262145);
f(274877382656, 524287);
f(274877906944, 524288);
x = 524289;
+f(0, 0);
f(524289, 1);
f(1048578, 2);
f(1572867, 3);
@@ -1693,6 +1766,7 @@ f(274877906943, 524287);
f(274878431232, 524288);
f(274878955521, 524289);
x = 1048575;
+f(0, 0);
f(1048575, 1);
f(2097150, 2);
f(3145725, 3);
@@ -1751,6 +1825,7 @@ f(549755289600, 524288);
f(549756338175, 524289);
f(1099509530625, 1048575);
x = 1048576;
+f(0, 0);
f(1048576, 1);
f(2097152, 2);
f(3145728, 3);
@@ -1810,6 +1885,7 @@ f(549756862464, 524289);
f(1099510579200, 1048575);
f(1099511627776, 1048576);
x = 1048577;
+f(0, 0);
f(1048577, 1);
f(2097154, 2);
f(3145731, 3);
@@ -1870,6 +1946,7 @@ f(1099511627775, 1048575);
f(1099512676352, 1048576);
f(1099513724929, 1048577);
x = 2097151;
+f(0, 0);
f(2097151, 1);
f(4194302, 2);
f(6291453, 3);
@@ -1931,6 +2008,7 @@ f(2199022206976, 1048576);
f(2199024304127, 1048577);
f(4398042316801, 2097151);
x = 2097152;
+f(0, 0);
f(2097152, 1);
f(4194304, 2);
f(6291456, 3);
@@ -1993,6 +2071,7 @@ f(2199025352704, 1048577);
f(4398044413952, 2097151);
f(4398046511104, 2097152);
x = 2097153;
+f(0, 0);
f(2097153, 1);
f(4194306, 2);
f(6291459, 3);
@@ -2056,6 +2135,7 @@ f(4398046511103, 2097151);
f(4398048608256, 2097152);
f(4398050705409, 2097153);
x = 4194303;
+f(0, 0);
f(4194303, 1);
f(8388606, 2);
f(12582909, 3);
@@ -2120,6 +2200,7 @@ f(8796090925056, 2097152);
f(8796095119359, 2097153);
f(17592177655809, 4194303);
x = 4194304;
+f(0, 0);
f(4194304, 1);
f(8388608, 2);
f(12582912, 3);
@@ -2185,6 +2266,7 @@ f(8796097216512, 2097153);
f(17592181850112, 4194303);
f(17592186044416, 4194304);
x = 4194305;
+f(0, 0);
f(4194305, 1);
f(8388610, 2);
f(12582915, 3);
@@ -2251,6 +2333,7 @@ f(17592186044415, 4194303);
f(17592190238720, 4194304);
f(17592194433025, 4194305);
x = 8388607;
+f(0, 0);
f(8388607, 1);
f(16777214, 2);
f(25165821, 3);
@@ -2318,6 +2401,7 @@ f(35184367894528, 4194304);
f(35184376283135, 4194305);
f(70368727400449, 8388607);
x = 8388608;
+f(0, 0);
f(8388608, 1);
f(16777216, 2);
f(25165824, 3);
@@ -2386,6 +2470,7 @@ f(35184380477440, 4194305);
f(70368735789056, 8388607);
f(70368744177664, 8388608);
x = 8388609;
+f(0, 0);
f(8388609, 1);
f(16777218, 2);
f(25165827, 3);
@@ -2455,6 +2540,7 @@ f(70368744177663, 8388607);
f(70368752566272, 8388608);
f(70368760954881, 8388609);
x = 16777215;
+f(0, 0);
f(16777215, 1);
f(33554430, 2);
f(50331645, 3);
@@ -2525,6 +2611,7 @@ f(140737479966720, 8388608);
f(140737496743935, 8388609);
f(281474943156225, 16777215);
x = 16777216;
+f(0, 0);
f(16777216, 1);
f(33554432, 2);
f(50331648, 3);
@@ -2596,6 +2683,7 @@ f(140737505132544, 8388609);
f(281474959933440, 16777215);
f(281474976710656, 16777216);
x = 16777217;
+f(0, 0);
f(16777217, 1);
f(33554434, 2);
f(50331651, 3);
@@ -2668,6 +2756,7 @@ f(281474976710655, 16777215);
f(281474993487872, 16777216);
f(281475010265089, 16777217);
x = 33554431;
+f(0, 0);
f(33554431, 1);
f(67108862, 2);
f(100663293, 3);
@@ -2741,6 +2830,7 @@ f(562949936644096, 16777216);
f(562949970198527, 16777217);
f(1125899839733761, 33554431);
x = 33554432;
+f(0, 0);
f(33554432, 1);
f(67108864, 2);
f(100663296, 3);
@@ -2815,6 +2905,7 @@ f(562949986975744, 16777217);
f(1125899873288192, 33554431);
f(1125899906842624, 33554432);
x = 33554433;
+f(0, 0);
f(33554433, 1);
f(67108866, 2);
f(100663299, 3);
@@ -2890,6 +2981,7 @@ f(1125899906842623, 33554431);
f(1125899940397056, 33554432);
f(1125899973951489, 33554433);
x = 67108863;
+f(0, 0);
f(67108863, 1);
f(134217726, 2);
f(201326589, 3);
@@ -2962,6 +3054,7 @@ f(1125899822956545, 16777215);
f(1125899890065408, 16777216);
f(1125899957174271, 16777217);
x = 67108864;
+f(0, 0);
f(67108864, 1);
f(134217728, 2);
f(201326592, 3);
@@ -3034,6 +3127,7 @@ f(1125899839733760, 16777215);
f(1125899906842624, 16777216);
f(1125899973951488, 16777217);
x = 67108865;
+f(0, 0);
f(67108865, 1);
f(134217730, 2);
f(201326595, 3);
@@ -3106,6 +3200,7 @@ f(1125899856510975, 16777215);
f(1125899923619840, 16777216);
f(1125899990728705, 16777217);
x = 134217727;
+f(0, 0);
f(134217727, 1);
f(268435454, 2);
f(402653181, 3);
@@ -3175,6 +3270,7 @@ f(1125899764236289, 8388607);
f(1125899898454016, 8388608);
f(1125900032671743, 8388609);
x = 134217728;
+f(0, 0);
f(134217728, 1);
f(268435456, 2);
f(402653184, 3);
@@ -3244,6 +3340,7 @@ f(1125899772624896, 8388607);
f(1125899906842624, 8388608);
f(1125900041060352, 8388609);
x = 134217729;
+f(0, 0);
f(134217729, 1);
f(268435458, 2);
f(402653187, 3);
@@ -3313,6 +3410,7 @@ f(1125899781013503, 8388607);
f(1125899915231232, 8388608);
f(1125900049448961, 8388609);
x = 268435455;
+f(0, 0);
f(268435455, 1);
f(536870910, 2);
f(805306365, 3);
@@ -3379,6 +3477,7 @@ f(1125899634212865, 4194303);
f(1125899902648320, 4194304);
f(1125900171083775, 4194305);
x = 268435456;
+f(0, 0);
f(268435456, 1);
f(536870912, 2);
f(805306368, 3);
@@ -3445,6 +3544,7 @@ f(1125899638407168, 4194303);
f(1125899906842624, 4194304);
f(1125900175278080, 4194305);
x = 268435457;
+f(0, 0);
f(268435457, 1);
f(536870914, 2);
f(805306371, 3);
@@ -3511,6 +3611,7 @@ f(1125899642601471, 4194303);
f(1125899911036928, 4194304);
f(1125900179472385, 4194305);
x = 536870911;
+f(0, 0);
f(536870911, 1);
f(1073741822, 2);
f(1610612733, 3);
@@ -3574,6 +3675,7 @@ f(1125899367874561, 2097151);
f(1125899904745472, 2097152);
f(1125900441616383, 2097153);
x = 536870912;
+f(0, 0);
f(536870912, 1);
f(1073741824, 2);
f(1610612736, 3);
@@ -3637,6 +3739,7 @@ f(1125899369971712, 2097151);
f(1125899906842624, 2097152);
f(1125900443713536, 2097153);
x = 536870913;
+f(0, 0);
f(536870913, 1);
f(1073741826, 2);
f(1610612739, 3);
@@ -3700,6 +3803,7 @@ f(1125899372068863, 2097151);
f(1125899908939776, 2097152);
f(1125900445810689, 2097153);
x = 1073741823;
+f(0, 0);
f(1073741823, 1);
f(2147483646, 2);
f(3221225469, 3);
@@ -3760,6 +3864,7 @@ f(1125898832052225, 1048575);
f(1125899905794048, 1048576);
f(1125900979535871, 1048577);
x = 1073741824;
+f(0, 0);
f(1073741824, 1);
f(2147483648, 2);
f(3221225472, 3);
@@ -3820,6 +3925,7 @@ f(1125898833100800, 1048575);
f(1125899906842624, 1048576);
f(1125900980584448, 1048577);
x = 1073741825;
+f(0, 0);
f(1073741825, 1);
f(2147483650, 2);
f(3221225475, 3);
@@ -3880,6 +3986,7 @@ f(1125898834149375, 1048575);
f(1125899907891200, 1048576);
f(1125900981633025, 1048577);
x = 2147483647;
+f(0, 0);
f(2147483647, 1);
f(4294967294, 2);
f(6442450941, 3);
@@ -3937,6 +4044,7 @@ f(1125897758834689, 524287);
f(1125899906318336, 524288);
f(1125902053801983, 524289);
x = 2147483648;
+f(0, 0);
f(2147483648, 1);
f(4294967296, 2);
f(6442450944, 3);
@@ -3994,6 +4102,7 @@ f(1125897759358976, 524287);
f(1125899906842624, 524288);
f(1125902054326272, 524289);
x = 2147483649;
+f(0, 0);
f(2147483649, 1);
f(4294967298, 2);
f(6442450947, 3);
@@ -4051,6 +4160,7 @@ f(1125897759883263, 524287);
f(1125899907366912, 524288);
f(1125902054850561, 524289);
x = 4294967295;
+f(0, 0);
f(4294967295, 1);
f(8589934590, 2);
f(12884901885, 3);
@@ -4105,6 +4215,7 @@ f(1125895611613185, 262143);
f(1125899906580480, 262144);
f(1125904201547775, 262145);
x = 4294967296;
+f(0, 0);
f(4294967296, 1);
f(8589934592, 2);
f(12884901888, 3);
@@ -4159,6 +4270,7 @@ f(1125895611875328, 262143);
f(1125899906842624, 262144);
f(1125904201809920, 262145);
x = 4294967297;
+f(0, 0);
f(4294967297, 1);
f(8589934594, 2);
f(12884901891, 3);
@@ -4213,6 +4325,7 @@ f(1125895612137471, 262143);
f(1125899907104768, 262144);
f(1125904202072065, 262145);
x = 8589934591;
+f(0, 0);
f(8589934591, 1);
f(17179869182, 2);
f(25769803773, 3);
@@ -4264,6 +4377,7 @@ f(1125891316776961, 131071);
f(1125899906711552, 131072);
f(1125908496646143, 131073);
x = 8589934592;
+f(0, 0);
f(8589934592, 1);
f(17179869184, 2);
f(25769803776, 3);
@@ -4315,6 +4429,7 @@ f(1125891316908032, 131071);
f(1125899906842624, 131072);
f(1125908496777216, 131073);
x = 8589934593;
+f(0, 0);
f(8589934593, 1);
f(17179869186, 2);
f(25769803779, 3);
@@ -4366,6 +4481,7 @@ f(1125891317039103, 131071);
f(1125899906973696, 131072);
f(1125908496908289, 131073);
x = 17179869183;
+f(0, 0);
f(17179869183, 1);
f(34359738366, 2);
f(51539607549, 3);
@@ -4414,6 +4530,7 @@ f(1125882726907905, 65535);
f(1125899906777088, 65536);
f(1125917086646271, 65537);
x = 17179869184;
+f(0, 0);
f(17179869184, 1);
f(34359738368, 2);
f(51539607552, 3);
@@ -4462,6 +4579,7 @@ f(1125882726973440, 65535);
f(1125899906842624, 65536);
f(1125917086711808, 65537);
x = 17179869185;
+f(0, 0);
f(17179869185, 1);
f(34359738370, 2);
f(51539607555, 3);
diff --git a/test/mjsunit/negate-zero.js b/test/mjsunit/negate-zero.js
index 31d460a2..558be94c 100644
--- a/test/mjsunit/negate-zero.js
+++ b/test/mjsunit/negate-zero.js
@@ -26,7 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function IsNegativeZero(x) {
- assertEquals(0, x);
+ assertTrue(x == 0); // Is 0 or -0.
var y = 1 / x;
assertFalse(isFinite(y));
return y < 0;
diff --git a/test/mjsunit/object-freeze.js b/test/mjsunit/object-freeze.js
index 15e19abb..3eefffda 100644
--- a/test/mjsunit/object-freeze.js
+++ b/test/mjsunit/object-freeze.js
@@ -70,12 +70,8 @@ Object.freeze(obj);
assertFalse(Object.isExtensible(obj));
assertTrue(Object.isFrozen(obj));
-try {
- obj.foo = 42;
- assertUnreachable();
-} catch(e) {
- assertTrue(/object is not extensible/.test(e));
-}
+obj.foo = 42;
+assertEquals(obj.foo, undefined);
desc = Object.getOwnPropertyDescriptor(obj, 'x');
assertFalse(desc.writable);
@@ -88,7 +84,7 @@ assertFalse(desc.configurable);
assertEquals("foobar", desc.value);
// Make sure that even if we try overwrite a value that is not writable, it is
-// not changed.
+// not changed.
obj.x = "tete";
assertEquals(42, obj.x);
obj.x = { get: function() {return 43}, set: function() {} };
@@ -118,12 +114,8 @@ assertEquals(undefined, desc.value);
assertEquals(set, desc.set);
assertEquals(get, desc.get);
-try {
- obj2.foo = 42;
- assertUnreachable();
-} catch(e) {
- assertTrue(/object is not extensible/.test(e));
-}
+obj2.foo = 42;
+assertEquals(obj2.foo, undefined);
// Test freeze on arrays.
diff --git a/test/mjsunit/object-prevent-extensions.js b/test/mjsunit/object-prevent-extensions.js
index ebc2cfa6..dc32342c 100644
--- a/test/mjsunit/object-prevent-extensions.js
+++ b/test/mjsunit/object-prevent-extensions.js
@@ -35,22 +35,11 @@ Object.preventExtensions(obj1);
// Make sure the is_extensible flag is set.
assertFalse(Object.isExtensible(obj1));
-// Try adding a new property.
-try {
- obj1.x = 42;
- assertUnreachable();
-} catch (e) {
- assertTrue(/object is not extensible/.test(e));
-}
+obj1.x = 42;
assertEquals(undefined, obj1.x);
// Try adding a new element.
-try {
- obj1[1] = 42;
- assertUnreachable();
-} catch (e) {
- assertTrue(/object is not extensible/.test(e));
-}
+obj1[1] = 42;
assertEquals(undefined, obj1[1]);
@@ -64,25 +53,14 @@ assertTrue(Object.isExtensible(obj2));
Object.preventExtensions(obj2);
assertEquals(42, obj2.x);
-try {
- obj2.y = 42;
- assertUnreachable();
-} catch (e) {
- assertTrue(/object is not extensible/.test(e));
-}
-
+obj2.y = 42;
// obj2.y should still be undefined.
assertEquals(undefined, obj2.y);
// Make sure we can still write values to obj.x.
obj2.x = 43;
assertEquals(43, obj2.x)
-try {
- obj2.y = new function() { return 42; };
- assertUnreachable();
-} catch (e) {
- assertTrue(/object is not extensible/.test(e));
-}
+obj2.y = new function() { return 42; };
// obj2.y should still be undefined.
assertEquals(undefined, obj2.y);
assertEquals(43, obj2.x)
@@ -97,12 +75,7 @@ try {
assertEquals(undefined, obj2.y);
assertEquals(43, obj2.x);
-try {
- obj2[1] = 42;
-} catch (e) {
- assertTrue(/object is not extensible/.test(e));
-}
-
+obj2[1] = 42;
assertEquals(undefined, obj2[1]);
var arr = new Array();
@@ -110,12 +83,7 @@ arr[1] = 10;
Object.preventExtensions(arr);
-try {
- arr[2] = 42;
- assertUnreachable();
-} catch (e) {
- assertTrue(/object is not extensible/.test(e));
-}
+arr[2] = 42;
assertEquals(10, arr[1]);
// We should still be able to change exiting elements.
@@ -134,12 +102,7 @@ var child = Object.create(parent);
child.y = 42;
// This should have no influence on the parent class.
-try {
- parent.y = 29;
- assertUnreachable();
-} catch (e) {
- assertTrue(/object is not extensible/.test(e));
-}
+parent.y = 29;
// Test that attributes on functions are also handled correctly.
@@ -149,9 +112,5 @@ function foo() {
Object.preventExtensions(foo);
-try {
- foo.x = 29;
- assertUnreachable();
-} catch (e) {
- assertTrue(/object is not extensible/.test(e));
-}
+foo.x = 29;
+assertEquals(undefined, foo.x);
diff --git a/test/mjsunit/object-seal.js b/test/mjsunit/object-seal.js
index 9e7f44b9..3ce2367b 100644
--- a/test/mjsunit/object-seal.js
+++ b/test/mjsunit/object-seal.js
@@ -75,12 +75,8 @@ assertTrue(Object.isSealed(obj));
assertFalse(Object.isFrozen(obj));
// We should not allow new properties to be added.
-try {
- obj.foo = 42;
- assertUnreachable();
-} catch(e) {
- assertTrue(/object is not extensible/.test(e));
-}
+obj.foo = 42;
+assertEquals(obj.foo, undefined);
desc = Object.getOwnPropertyDescriptor(obj, 'x');
assertTrue(desc.writable);
@@ -125,13 +121,8 @@ assertEquals(undefined, desc.value);
assertEquals(set, desc.set);
assertEquals(get, desc.get);
-try {
- obj2.foo = 42;
- assertUnreachable();
-} catch(e) {
- assertTrue(/object is not extensible/.test(e));
-}
-
+obj2.foo = 42;
+assertEquals(obj2.foo, undefined);
// Test seal on arrays.
var arr = new Array(42,43);
diff --git a/test/mjsunit/regress/regress-1233.js b/test/mjsunit/regress/regress-1233.js
new file mode 100644
index 00000000..a09b7152
--- /dev/null
+++ b/test/mjsunit/regress/regress-1233.js
@@ -0,0 +1,47 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that Object.freeze and Object.getOwnPropertyDescriptor do not
+// call toString or valueOf on members of the object.
+
+// See http://code.google.com/p/v8/issues/detail?id=1233.
+
+
+var delicate = new Object();
+delicate.toString = function(){ throw Error("toString"); };
+delicate.valueOf = function(){ throw Error("valueOf"); };
+
+var x = { foo: delicate };
+
+var status = "fail";
+try {
+ Object.getOwnPropertyDescriptor(x, "foo");
+ Object.freeze(x);
+ status = "succeed";
+} catch (e) {}
+
+assertEquals("succeed", status);
diff --git a/test/mjsunit/regress/regress-1236.js b/test/mjsunit/regress/regress-1236.js
new file mode 100644
index 00000000..48e3d3d3
--- /dev/null
+++ b/test/mjsunit/regress/regress-1236.js
@@ -0,0 +1,34 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Should not crash.
+
+pattern = RegExp("",""); // RegExp is irrelevant, as long as it's not an atom.
+string = 'a'; // Anything non-empty (flat ASCII).
+pattern.exec(string); // Ensure that JSRegExp is compiled.
+pattern["@"] = 42; // Change layout of JSRegExp object.
+pattern.exec(string); // Call again to trigger bug in stub.
diff --git a/test/mjsunit/regress/regress-1237.js b/test/mjsunit/regress/regress-1237.js
new file mode 100644
index 00000000..f97f9786
--- /dev/null
+++ b/test/mjsunit/regress/regress-1237.js
@@ -0,0 +1,36 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Deoptimization after a conditional expression in an effect context should
+// not see the value of the expression.
+function observe(x, y) { return x; }
+function test(x) {
+ return observe(1, ((x? observe(observe.prototype.x): 'c'), x + 1));
+}
+
+for (var i = 0; i < 10000000; ++i) test(0);
+test("a");
diff --git a/test/mjsunit/regress/regress-1240.js b/test/mjsunit/regress/regress-1240.js
new file mode 100644
index 00000000..1a0bf2ed
--- /dev/null
+++ b/test/mjsunit/regress/regress-1240.js
@@ -0,0 +1,39 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This regression tests that we are not allowed to overwrite an existing
+// non-configurable getter with a new getter. In addition, we should not
+// be able to change the configurable flag from false to true.
+
+var a = {};
+Object.defineProperty(a, 'b',
+ { get: function () { return 42; }, configurable: false });
+// Do not allow us to redefine b on a.
+a.__defineGetter__('b', function _b(){ return 'foo'; });
+assertEquals(42, a.b);
+var desc = Object.getOwnPropertyDescriptor(a, 'b');
+assertFalse(desc.configurable);
diff --git a/test/mjsunit/regress/regress-1257.js b/test/mjsunit/regress/regress-1257.js
new file mode 100644
index 00000000..c20fb860
--- /dev/null
+++ b/test/mjsunit/regress/regress-1257.js
@@ -0,0 +1,58 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function g(y) { assertEquals(y, 12); }
+
+var X = 0;
+
+function foo () {
+ var cnt = 0;
+ var l = -1;
+ var x = 0;
+ while (1) switch (l) {
+ case -1:
+ var y = x + 12;
+ l = 0;
+ break;
+ case 0:
+ // Loop for to hit OSR.
+ if (cnt++ < 10000000) {
+ l = 0;
+ break;
+ } else {
+ l = 1;
+ break;
+ }
+ case 1:
+ // This case will contain deoptimization
+ // because it has no type feedback.
+ g(y);
+ return;
+ };
+}
+
+foo();
diff --git a/test/mjsunit/regress/regress-1278.js b/test/mjsunit/regress/regress-1278.js
new file mode 100644
index 00000000..7ad8cda7
--- /dev/null
+++ b/test/mjsunit/regress/regress-1278.js
@@ -0,0 +1,69 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// See: http://code.google.com/p/v8/issues/detail?id=1278
+
+// Test that that handling of 0/-0 is correct for binary operations when the
+// TypeRecordingBinaryOpStub transitions through different states.
+
+function add(x, y) {
+ return x + y;
+}
+
+function sub(x, y) {
+ return x - y;
+}
+
+function mul(x, y) {
+ return x * y;
+}
+
+function div(x, y) {
+ return x / y;
+}
+
+for (var i = 0; i < 10; i++) {
+ assertEquals(0, add(0, 0));
+ assertEquals(0, add(0, -0));
+ assertEquals(0, add(-0, 0));
+ assertEquals(-0, add(-0, -0));
+
+ assertEquals(0, sub(0, 0));
+ assertEquals(0, sub(0, -0));
+ assertEquals(-0, sub(-0, 0));
+ assertEquals(0, sub(-0, -0));
+
+ assertEquals(0, mul(0, 0));
+ assertEquals(-0, mul(0, -0));
+ assertEquals(-0, mul(-0, 0));
+ assertEquals(0, mul(-0, -0));
+
+ assertEquals(0, div(0, 1));
+ assertEquals(-0, div(0, -1));
+ assertEquals(-0, div(-0, 1));
+ assertEquals(0, div(-0, -1));
+}
diff --git a/test/mjsunit/regress/regress-create-exception.js b/test/mjsunit/regress/regress-create-exception.js
index 2119ce2b..d3face9f 100644
--- a/test/mjsunit/regress/regress-create-exception.js
+++ b/test/mjsunit/regress/regress-create-exception.js
@@ -26,6 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --max-new-space-size=256
+"use strict";
// Check for GC bug constructing exceptions.
var v = [1, 2, 3, 4]
diff --git a/test/mjsunit/regress/regress-lazy-deopt-reloc.js b/test/mjsunit/regress/regress-lazy-deopt-reloc.js
new file mode 100644
index 00000000..f1fe6d55
--- /dev/null
+++ b/test/mjsunit/regress/regress-lazy-deopt-reloc.js
@@ -0,0 +1,52 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Do not generate debug code since that will space things differently
+// in the generated code.
+// Flags: --allow-natives-syntax --expose-gc --nodebug-code
+
+// Regression test for issue where we did not pad the relocation
+// information enough to have room for lazy deoptimization.
+
+function kaboom() {
+ var a = function () {},
+ b = function () {},
+ c, d = function () { var d = []; },
+ e = function () { var e = {}; };
+ c = function () { d(); b(); };
+ return function (x, y) {
+ c();
+ a();
+ return function f() { }({});
+ };
+}
+
+kaboom();
+
+%DeoptimizeFunction(kaboom);
+
+gc();
diff --git a/test/mjsunit/sin-cos.js b/test/mjsunit/sin-cos.js
index ae02451f..e38dfdf8 100644
--- a/test/mjsunit/sin-cos.js
+++ b/test/mjsunit/sin-cos.js
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -27,19 +27,24 @@
// Test Math.sin and Math.cos.
-var input_sin = [0, Math.PI / 2];
-var input_cos = [0, Math.PI];
+function sinTest() {
+ assertEquals(0, Math.sin(0));
+ assertEquals(1, Math.sin(Math.PI / 2));
+}
-var output_sin = input_sin.map(Math.sin);
-var output_cos = input_cos.map(Math.cos);
+function cosTest() {
+ assertEquals(1, Math.cos(0));
+ assertEquals(-1, Math.cos(Math.PI));
+}
-var expected_sin = [0, 1];
-var expected_cos = [1, -1];
-
-assertArrayEquals(expected_sin, output_sin, "sine");
-assertArrayEquals(expected_cos, output_cos, "cosine");
+sinTest();
+cosTest();
// By accident, the slow case for sine and cosine were both sine at
// some point. This is a regression test for that issue.
var x = Math.pow(2, 70);
assertTrue(Math.sin(x) != Math.cos(x));
+
+// Ensure that sine and log are not the same.
+x = 0.5;
+assertTrue(Math.sin(x) != Math.log(x));
diff --git a/test/mjsunit/smi-negative-zero.js b/test/mjsunit/smi-negative-zero.js
index ea2fa5a9..1bab920d 100644
--- a/test/mjsunit/smi-negative-zero.js
+++ b/test/mjsunit/smi-negative-zero.js
@@ -109,5 +109,5 @@ function foo(x) {
return -x;
}
-assertEquals(0, foo(x));
-assertEquals(0, foo(x));
+assertEquals(-0, foo(x));
+assertEquals(-0, foo(x));
diff --git a/test/mjsunit/str-to-num.js b/test/mjsunit/str-to-num.js
index 28e98d9f..bbfa7d33 100644
--- a/test/mjsunit/str-to-num.js
+++ b/test/mjsunit/str-to-num.js
@@ -190,7 +190,7 @@ assertEquals(100, toNumber("000100"));
assertEquals(Infinity, toNumber("1e999"), "1e999");
assertEquals(-Infinity, toNumber("-1e999"));
assertEquals(0, toNumber("1e-999"));
-assertEquals(0, toNumber("-1e-999"));
+assertEquals(-0, toNumber("-1e-999"));
assertEquals(Infinity, 1 / toNumber("1e-999"), "1e-999");
assertEquals(-Infinity, 1 / toNumber("-1e-999"));
diff --git a/test/mjsunit/strict-mode.js b/test/mjsunit/strict-mode.js
index 69be19c2..84ccb30f 100644
--- a/test/mjsunit/strict-mode.js
+++ b/test/mjsunit/strict-mode.js
@@ -957,3 +957,181 @@ repeat(10, function() { testAssignToUndefined(false); });
assertThrows(function() { str_obj.length = 1; }, TypeError);
assertThrows(function() { str_cat.length = 1; }, TypeError);
})();
+
+
+(function TestArgumentsAliasing() {
+ function strict(a, b) {
+ "use strict";
+ a = "c";
+ b = "d";
+ return [a, b, arguments[0], arguments[1]];
+ }
+
+ function nonstrict(a, b) {
+ a = "c";
+ b = "d";
+ return [a, b, arguments[0], arguments[1]];
+ }
+
+ assertEquals(["c", "d", "a", "b"], strict("a", "b"));
+ assertEquals(["c", "d", "c", "d"], nonstrict("a", "b"));
+})();
+
+
+function CheckPillDescriptor(func, name) {
+
+ function CheckPill(pill) {
+ assertEquals("function", typeof pill);
+ assertInstanceof(pill, Function);
+ pill.property = "value";
+ assertEquals(pill.value, undefined);
+ assertThrows(function() { 'use strict'; pill.property = "value"; },
+ TypeError);
+ assertThrows(pill, TypeError);
+ assertEquals(pill.prototype, (function(){}).prototype);
+ var d = Object.getOwnPropertyDescriptor(pill, "prototype");
+ assertFalse(d.writable);
+ assertFalse(d.configurable);
+ assertFalse(d.enumerable);
+ }
+
+ var descriptor = Object.getOwnPropertyDescriptor(func, name);
+ CheckPill(descriptor.get)
+ CheckPill(descriptor.set);
+ assertFalse(descriptor.enumerable);
+ assertFalse(descriptor.configurable);
+}
+
+
+(function TestStrictFunctionPills() {
+ function strict() {
+ "use strict";
+ }
+ assertThrows(function() { strict.caller; }, TypeError);
+ assertThrows(function() { strict.arguments; }, TypeError);
+
+ var another = new Function("'use strict'");
+ assertThrows(function() { another.caller; }, TypeError);
+ assertThrows(function() { another.arguments; }, TypeError);
+
+ var third = (function() { "use strict"; return function() {}; })();
+ assertThrows(function() { third.caller; }, TypeError);
+ assertThrows(function() { third.arguments; }, TypeError);
+
+ CheckPillDescriptor(strict, "caller");
+ CheckPillDescriptor(strict, "arguments");
+ CheckPillDescriptor(another, "caller");
+ CheckPillDescriptor(another, "arguments");
+ CheckPillDescriptor(third, "caller");
+ CheckPillDescriptor(third, "arguments");
+})();
+
+
+(function TestStrictFunctionWritablePrototype() {
+ "use strict";
+ function TheClass() {
+ }
+ assertThrows(function() { TheClass.caller; }, TypeError);
+ assertThrows(function() { TheClass.arguments; }, TypeError);
+
+ // Strict functions must have writable prototype.
+ TheClass.prototype = {
+ func: function() { return "func_value"; },
+ get accessor() { return "accessor_value"; },
+ property: "property_value",
+ };
+
+ var o = new TheClass();
+ assertEquals(o.func(), "func_value");
+ assertEquals(o.accessor, "accessor_value");
+ assertEquals(o.property, "property_value");
+})();
+
+
+(function TestStrictArgumentPills() {
+ function strict() {
+ "use strict";
+ return arguments;
+ }
+
+ var args = strict();
+ CheckPillDescriptor(args, "caller");
+ CheckPillDescriptor(args, "callee");
+
+ args = strict(17, "value", strict);
+ assertEquals(17, args[0])
+ assertEquals("value", args[1])
+ assertEquals(strict, args[2]);
+ CheckPillDescriptor(args, "caller");
+ CheckPillDescriptor(args, "callee");
+
+ function outer() {
+ "use strict";
+ function inner() {
+ return arguments;
+ }
+ return inner;
+ }
+
+ var args = outer()();
+ CheckPillDescriptor(args, "caller");
+ CheckPillDescriptor(args, "callee");
+
+ args = outer()(17, "value", strict);
+ assertEquals(17, args[0])
+ assertEquals("value", args[1])
+ assertEquals(strict, args[2]);
+ CheckPillDescriptor(args, "caller");
+ CheckPillDescriptor(args, "callee");
+})();
+
+
+(function TestNonStrictFunctionCallerPillSimple() {
+ function return_my_caller() {
+ return return_my_caller.caller;
+ }
+
+ function strict() {
+ "use strict";
+ return_my_caller();
+ }
+ assertThrows(strict, TypeError);
+
+ function non_strict() {
+ return return_my_caller();
+ }
+ assertSame(non_strict(), non_strict);
+})();
+
+
+(function TestNonStrictFunctionCallerPill() {
+ function strict(n) {
+ "use strict";
+ non_strict(n);
+ }
+
+ function recurse(n, then) {
+ if (n > 0) {
+ recurse(n - 1);
+ } else {
+ return then();
+ }
+ }
+
+ function non_strict(n) {
+ recurse(n, function() { non_strict.caller; });
+ }
+
+ function test(n) {
+ try {
+ recurse(n, function() { strict(n); });
+ } catch(e) {
+ return e instanceof TypeError;
+ }
+ return false;
+ }
+
+ for (var i = 0; i < 10; i ++) {
+ assertEquals(test(i), true);
+ }
+})();
diff --git a/test/mjsunit/testcfg.py b/test/mjsunit/testcfg.py
index 5cb46bc2..3dd65817 100644
--- a/test/mjsunit/testcfg.py
+++ b/test/mjsunit/testcfg.py
@@ -38,24 +38,31 @@ SELF_SCRIPT_PATTERN = re.compile(r"//\s+Env: TEST_FILE_NAME")
class MjsunitTestCase(test.TestCase):
- def __init__(self, path, file, mode, context, config):
+ def __init__(self, path, file, mode, context, config, isolates):
super(MjsunitTestCase, self).__init__(context, path, mode)
self.file = file
self.config = config
self.self_script = False
+ self.isolates = isolates
def GetLabel(self):
return "%s %s" % (self.mode, self.GetName())
def GetName(self):
- return self.path[-1]
+ return self.path[-1] + ["", "-isolates"][self.isolates]
- def GetCommand(self):
+ def TestsIsolates(self):
+ return self.isolates
+
+ def GetVmCommand(self, source):
result = self.config.context.GetVmCommand(self, self.mode)
- source = open(self.file).read()
flags_match = FLAGS_PATTERN.search(source)
if flags_match:
result += flags_match.group(1).strip().split()
+ return result
+
+ def GetVmArguments(self, source):
+ result = []
additional_files = []
files_match = FILES_PATTERN.search(source);
# Accept several lines of 'Files:'
@@ -73,6 +80,15 @@ class MjsunitTestCase(test.TestCase):
result += [framework, self.file]
return result
+ def GetCommand(self):
+ source = open(self.file).read()
+ result = self.GetVmCommand(source)
+ result += self.GetVmArguments(source)
+ if self.isolates:
+ result.append("--isolate")
+ result += self.GetVmArguments(source)
+ return result
+
def GetSource(self):
return open(self.file).read()
@@ -104,7 +120,7 @@ class MjsunitTestConfiguration(test.TestConfiguration):
return name.endswith('.js') and name != 'mjsunit.js'
return [f[:-3] for f in os.listdir(path) if SelectTest(f)]
- def ListTests(self, current_path, path, mode):
+ def ListTests(self, current_path, path, mode, variant_flags):
mjsunit = [current_path + [t] for t in self.Ls(self.root)]
regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
@@ -122,7 +138,8 @@ class MjsunitTestConfiguration(test.TestConfiguration):
for test in all_tests:
if self.Contains(path, test):
file_path = join(self.root, reduce(join, test[1:], "") + ".js")
- result.append(MjsunitTestCase(test, file_path, mode, self.context, self))
+ result.append(MjsunitTestCase(test, file_path, mode, self.context, self, False))
+ result.append(MjsunitTestCase(test, file_path, mode, self.context, self, True))
return result
def GetBuildRequirements(self):
diff --git a/test/mjsunit/tools/tickprocessor-test-func-info.log b/test/mjsunit/tools/tickprocessor-test-func-info.log
index 755fbb2a..e4015d48 100644
--- a/test/mjsunit/tools/tickprocessor-test-func-info.log
+++ b/test/mjsunit/tools/tickprocessor-test-func-info.log
@@ -5,7 +5,7 @@ profiler,"begin",1
code-creation,Stub,0x424260,348,"CompareStub_GE"
code-creation,LazyCompile,0x2a8100,18535,"DrawQube 3d-cube.js:188",0xf43abcac,
code-creation,LazyCompile,0x480100,3908,"DrawLine 3d-cube.js:17",0xf43abc50,
-tick,0x424284,0xbfffeea0,0x480600,0,0x2aaaa5
-tick,0x42429f,0xbfffed88,0x480600,0,0x2aacb4
-tick,0x48063d,0xbfffec7c,0x2d0f7c,0,0x2aaec6
+tick,0x424284,0xbfffeea0,0,0x480600,0,0x2aaaa5
+tick,0x42429f,0xbfffed88,0,0x480600,0,0x2aacb4
+tick,0x48063d,0xbfffec7c,0,0x2d0f7c,0,0x2aaec6
profiler,"end"
diff --git a/test/mjsunit/tools/tickprocessor-test.log b/test/mjsunit/tools/tickprocessor-test.log
index 80e7ec1a..db8be79f 100644
--- a/test/mjsunit/tools/tickprocessor-test.log
+++ b/test/mjsunit/tools/tickprocessor-test.log
@@ -9,17 +9,17 @@ code-creation,LazyCompile,0xf541d120,145,"exp native math.js:41"
function-creation,0xf441d280,0xf541d120
code-creation,LoadIC,0xf541d280,117,"j"
code-creation,LoadIC,0xf541d360,63,"i"
-tick,0x80f82d1,0xffdfe880,0,0,0xf541ce5c
-tick,0x80f89a1,0xffdfecf0,0,0,0xf541ce5c
-tick,0x8123b5c,0xffdff1a0,0,0,0xf541d1a1,0xf541ceea
-tick,0x8123b65,0xffdff1a0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf541d2be,0xffdff1e4,0,0
-tick,0xf541d320,0xffdff1dc,0,0
-tick,0xf541d384,0xffdff1d8,0,0
-tick,0xf7db94da,0xffdff0ec,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7db951c,0xffdff0f0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7dbc508,0xffdff14c,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7dbff21,0xffdff198,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7edec90,0xffdff0ec,0,0,0xf541d1a1,0xf541ceea
-tick,0xffffe402,0xffdff488,0,0
+tick,0x80f82d1,0xffdfe880,0,0,0,0xf541ce5c
+tick,0x80f89a1,0xffdfecf0,0,0,0,0xf541ce5c
+tick,0x8123b5c,0xffdff1a0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0x8123b65,0xffdff1a0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf541d2be,0xffdff1e4,0,0,0
+tick,0xf541d320,0xffdff1dc,0,0,0
+tick,0xf541d384,0xffdff1d8,0,0,0
+tick,0xf7db94da,0xffdff0ec,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7db951c,0xffdff0f0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbc508,0xffdff14c,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbff21,0xffdff198,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7edec90,0xffdff0ec,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xffffe402,0xffdff488,0,0,0
profiler,"end"
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index 3b6a524c..b9528bd9 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -745,8 +745,6 @@ js1_5/extensions/regress-342960: FAIL_OK || TIMEOUT if $mode == debug
# error message in debug mode.
js1_5/extensions/regress-336410-1: FAIL_OK || TIMEOUT if ($mode == debug && $arch == x64)
-
-
##################### DECOMPILATION TESTS #####################
# We don't really about the outcome of running the
diff --git a/test/mozilla/testcfg.py b/test/mozilla/testcfg.py
index 7a6438f1..3728f790 100644
--- a/test/mozilla/testcfg.py
+++ b/test/mozilla/testcfg.py
@@ -92,7 +92,7 @@ class MozillaTestConfiguration(test.TestConfiguration):
def __init__(self, context, root):
super(MozillaTestConfiguration, self).__init__(context, root)
- def ListTests(self, current_path, path, mode):
+ def ListTests(self, current_path, path, mode, variant_flags):
tests = []
for test_dir in TEST_DIRS:
current_root = join(self.root, 'data', test_dir)
diff --git a/test/sputnik/testcfg.py b/test/sputnik/testcfg.py
index 31e4b226..c1e3c1bb 100644
--- a/test/sputnik/testcfg.py
+++ b/test/sputnik/testcfg.py
@@ -81,7 +81,7 @@ class SputnikTestConfiguration(test.TestConfiguration):
def __init__(self, context, root):
super(SputnikTestConfiguration, self).__init__(context, root)
- def ListTests(self, current_path, path, mode):
+ def ListTests(self, current_path, path, mode, variant_flags):
# Import the sputnik test runner script as a module
testroot = join(self.root, 'sputniktests')
modroot = join(testroot, 'tools')
diff --git a/test/test262/README b/test/test262/README
new file mode 100644
index 00000000..6d9e56e7
--- /dev/null
+++ b/test/test262/README
@@ -0,0 +1,16 @@
+This directory contains code for binding the test262 test suite
+into the v8 test harness. To use the tests check out the test262
+tests from
+
+ http://hg.ecmascript.org/tests/test262
+
+at revision 62 as 'data' in this directory. Using later version
+may be possible but the tests are only known to pass (and indeed run)
+with that revision.
+
+hg clone -r 62 http://hg.ecmascript.org/tests/test262 data
+
+If you do update to a newer revision you may have to change the test
+harness adapter code since it uses internal functionality from the
+harness that comes bundled with the tests. You will most likely also
+have to update the test expectation file.
diff --git a/test/test262/harness-adapt.js b/test/test262/harness-adapt.js
new file mode 100644
index 00000000..b52afdba
--- /dev/null
+++ b/test/test262/harness-adapt.js
@@ -0,0 +1,80 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function fnGlobalObject() { return (function() { return this; })(); }
+
+var ES5Harness = (function() {
+ var currentTest = {};
+ var $this = this;
+
+ function Test262Error(id, path, description, codeString,
+ preconditionString, result, error) {
+ this.id = id;
+ this.path = path;
+ this.description = description;
+ this.result = result;
+ this.error = error;
+ this.code = codeString;
+ this.pre = preconditionString;
+ }
+
+ Test262Error.prototype.toString = function() {
+ return this.result;
+ }
+
+ function registerTest(test) {
+ if (!(test.precondition && !test.precondition())) {
+ var error;
+ try {
+ var res = test.test.call($this);
+ } catch(e) {
+ print(e);
+ res = 'fail'; error = e;
+ }
+ var retVal = /^s/i.test(test.id)
+ ? (res === true || typeof res == 'undefined' ? 'pass' : 'fail')
+ : (res === true ? 'pass' : 'fail');
+
+ if (retVal != 'pass') {
+ throw new Test262Error(
+ test.id,
+ test.path,
+ test.description,
+ test.test.toString(),
+ (test.precondition !== undefined)
+ ? test.precondition.toString()
+ : '',
+ retVal,
+ error);
+ }
+ }
+ }
+
+ return {
+ registerTest: registerTest
+ }
+})();
diff --git a/test/test262/test262.status b/test/test262/test262.status
new file mode 100644
index 00000000..bdc8b9c7
--- /dev/null
+++ b/test/test262/test262.status
@@ -0,0 +1,1506 @@
+# Copyright 2011 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#
+# ietestcenter tests.
+#
+
+prefix ietestcenter
+
+# BUG: 7.6 - SyntaxError expected: reserved words used as Identifier
+# Names in UTF8: class (class)
+7.6-30: FAIL
+# BUG: 7.6 - SyntaxError expected: reserved words used as Identifier
+# Names in UTF8: extends (extends)
+7.6-31: FAIL
+# BUG: 7.6 - SyntaxError expected: reserved words used as Identifier
+# Names in UTF8: \u0065\u006e\u0075\u006d (enum)
+7.6-32: FAIL
+# BUG: 7.6 - SyntaxError expected: reserved words used as Identifier
+# Names in UTF8: \u0073uper (super)
+7.6-33: FAIL
+# BUG: 7.6 - SyntaxError expected: reserved words used as Identifier
+# Names in UTF8: expor\u0074 (export)
+7.6-35: FAIL
+# BUG: 7.6 - SyntaxError expected: reserved words used as Identifier
+# Names in UTF8: \u0069\u006d\u0070\u006f\u0072\u0074 (import)
+7.6-36: FAIL
+# Invalid test: https://bugs.ecmascript.org/show_bug.cgi?id=76
+10.4.2-2-c-1: FAIL
+# BUG: 11.8.2 Greater-than Operator - Partial left to right order enforced
+# when using Greater-than operator: valueOf > valueOf
+11.8.2-1: FAIL
+# BUG: 11.8.2 Greater-than Operator - Partial left to right order enforced
+# when using Greater-than operator: valueOf > toString
+11.8.2-2: FAIL
+# BUG: 11.8.2 Greater-than Operator - Partial left to right order enforced
+# when using Greater-than operator: toString > valueOf
+11.8.2-3: FAIL
+# BUG: 11.8.2 Greater-than Operator - Partial left to right order enforced
+# when using Greater-than operator: toString > toString
+11.8.2-4: FAIL
+# BUG: 11.8.3 Less-than-or-equal Operator - Partial left to right order
+# enforced when using Less-than-or-equal operator: valueOf <= valueOf
+11.8.3-1: FAIL
+# BUG: 11.8.3 Less-than-or-equal Operator - Partial left to right order
+# enforced when using Less-than-or-equal operator: valueOf <= toString
+11.8.3-2: FAIL
+# BUG: 11.8.3 Less-than-or-equal Operator - Partial left to right order
+# enforced when using Less-than-or-equal operator: toString <= valueOf
+11.8.3-3: FAIL
+# BUG: 11.8.3 Less-than-or-equal Operator - Partial left to right order
+# enforced when using Less-than-or-equal operator: toString <= toString
+11.8.3-4: FAIL
+# BUG: 11.8.3 Less-than-or-equal Operator - Partial left to right order
+# enforced when using Less-than-or-equal operator: valueOf <= valueOf
+11.8.3-5: FAIL
+# BUG: Global.NaN is a data property with default attribute values
+15.1.1.1-0: FAIL
+# BUG: Global.Infinity is a data property with default attribute values
+15.1.1.2-0: FAIL
+# BUG: Global.undefined is a data property with default attribute values
+15.1.1.3-0: FAIL
+# BUG: Object.getOwnPropertyDescriptor returns data desc (all false)
+# for properties on built-ins (Global.NaN)
+15.2.3.3-4-178: FAIL
+# BUG: Object.getOwnPropertyDescriptor returns data desc (all false)
+# for properties on built-ins (Global.Infinity)
+15.2.3.3-4-179: FAIL
+# BUG: Object.getOwnPropertyDescriptor returns data desc (all false)
+# for properties on built-ins (Global.undefined)
+15.2.3.3-4-180: FAIL
+# BUG: Object.getOwnPropertyDescriptor returns data desc (all false)
+# for properties on built-ins (RegExp.prototype.source)
+# There is no RegExp.prototype.source
+15.2.3.3-4-212: FAIL
+# BUG: Object.getOwnPropertyDescriptor returns data desc (all false)
+# for properties on built-ins (RegExp.prototype.global)
+# There is no RegExp.prototype.global
+15.2.3.3-4-213: FAIL
+# BUG: Object.getOwnPropertyDescriptor returns data desc (all false)
+# for properties on built-ins (RegExp.prototype.ignoreCase)
+# There is no RegExp.prototype.ignoreCase
+15.2.3.3-4-214: FAIL
+# BUG: Object.getOwnPropertyDescriptor returns data desc (all false)
+# for properties on built-ins (RegExp.prototype.multiline)
+15.2.3.3-4-215: FAIL
+# Bug? Object.create - 'set' property of one property in 'Properties'
+# is not present (8.10.5 step 8)
+# V8 throws.
+15.2.3.5-4-267: FAIL
+# Bug? Object.create - 'set' property of one property in 'Properties'
+# is undefined (8.10.5 step 8.b)
+# V8 throws.
+15.2.3.5-4-292: FAIL
+# Bug? Object.defineProperty - 'set' property in 'Attributes' is not
+# present (8.10.5 step 8)
+# V8 throws.
+15.2.3.6-3-236: FAIL
+# Bug? Object.defineProperty - 'set' property in 'Attributes' is own
+# accessor property without a get function (8.10.5 step 8.a)
+# V8 throws.
+15.2.3.6-3-245: FAIL
+# Bug? Object.defineProperty - 'set' property in 'Attributes' is own
+# accessor property(without a get function) that overrides an inherited
+# accessor property (8.10.5 step 8.a)
+# V8 throws.
+15.2.3.6-3-246: FAIL
+# Bug? Object.defineProperty - 'set' property in 'Attributes' is an
+# inherited accessor property without a get function (8.10.5 step 8.a)
+# V8 throws.
+15.2.3.6-3-247: FAIL
+# Bug? Object.defineProperty - value of 'set' property in 'Attributes'
+# is undefined (8.10.5 step 8.b)
+# V8 throws.
+15.2.3.6-3-261: FAIL
+# Bug? Object.defineProperty - Update [[Enumerable]] attribute of 'name'
+# property to true successfully when [[Enumerable]] attribute of 'name'
+# is false and [[Configurable]] attribute of 'name' is true, the 'desc'
+# is a generic descriptor which only contains [[Enumerable]] attribute
+# as true, 'name' property is an index data property (8.12.9 step 8)
+15.2.3.6-4-82-18: FAIL
+# Bug? Object.defineProperty - Update [[Enumerable]] attribute of 'name'
+# property to false successfully when [[Enumerable]] and [[Configurable]]
+# attributes of 'name' property are true, the 'desc' is a generic
+# descriptor which only contains [Enumerable]] attribute as false and
+# 'name' property is an index accessor property (8.12.9 step 8)
+15.2.3.6-4-82-19: FAIL
+# Bug? Object.defineProperty - Update [[Enumerable]] attribute of 'name'
+# property to false successfully when [[Enumerable]] and [[Configurable]]
+# attributes of 'name' property are true, the 'desc' is a generic
+# descriptor which contains [Enumerable]] attribute as false and
+# [[Configurable]] property is true, 'name' property is an index accessor
+# property (8.12.9 step 8)
+15.2.3.6-4-82-20: FAIL
+# Bug? Object.defineProperty - Update [[Configurable]] attribute of 'name'
+# property to false successfully when [[Enumerable]] and [[Configurable]]
+# attributes of 'name' property are true, the 'desc' is a generic
+# descriptor which only contains [[Configurable]] attribute as false,
+# 'name' property is an index accessor property (8.12.9 step 8)
+15.2.3.6-4-82-21: FAIL
+# Bug? Object.defineProperty - Update [[Configurable]] attribute of 'name'
+# property to false successfully when [[Enumerable]] and [[Configurable]]
+# attributes of 'name' property are true, the 'desc' is a generic
+# descriptor which contains [[Enumerable]] attribute as true and
+# [[Configurable]] attribute is false, 'name' property is an index accessor
+# property (8.12.9 step 8)
+15.2.3.6-4-82-22: FAIL
+# Bug? Object.defineProperty - Update [[Enumerable]] and [[Configurable]]
+# attributes of 'name' property to false successfully when [[Enumerable]]
+# and [[Configurable]] attributes of 'name' property are true, the 'desc'
+# is a generic descriptor which contains [[Enumerable]] and
+# [[Configurable]] attributes as false, 'name' property is an index
+# accessor property (8.12.9 step 8)
+15.2.3.6-4-82-23: FAIL
+# Bug? Object.defineProperty - Update [[Enumerable]] attributes of 'name'
+# property to true successfully when [[Enumerable]] attribute of 'name' is
+# false and [[Configurable]] attribute of 'name' is true, the 'desc' is a
+# generic descriptor which only contains [[Enumerable]] attribute as true,
+# 'name' property is an index accessor property (8.12.9 step 8)
+15.2.3.6-4-82-24: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, test the length property of 'O'
+# is own data property (15.4.5.1 step 1)
+15.2.3.6-4-116: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, test the length property of 'O'
+# is own data property that overrides an inherited data property (15.4.5.1
+# step 1)
+15.2.3.6-4-117: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test that RangeError exception is thrown when [[Value]] field of
+# 'desc' is undefined (15.4.5.1 step 3.c)
+15.2.3.6-4-125: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is null (15.4.5.1 step 3.c)
+15.2.3.6-4-126: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is a boolean with value false
+# (15.4.5.1 step 3.c)
+15.2.3.6-4-127: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is a boolean with value true
+# (15.4.5.1 step 3.c)
+15.2.3.6-4-128: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is not thrown when the [[Value]] field of
+# 'desc' is 0 (15.4.5.1 step 3.c)
+15.2.3.6-4-129: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is not thrown when the [[Value]] field of
+# 'desc' is +0 (15.4.5.1 step 3.c)
+15.2.3.6-4-130: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is not thrown when the [[Value]] field of
+# 'desc' is -0 (15.4.5.1 step 3.c)
+15.2.3.6-4-131: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is not thrown when the [[Value]] field of
+# 'desc' is a positive number (15.4.5.1 step 3.c)
+15.2.3.6-4-132: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is thrown when the [[Value]] field of
+# 'desc' is a negative number (15.4.5.1 step 3.c)
+15.2.3.6-4-133: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is thrown when the [[Value]] field of
+# 'desc' is +Infinity (15.4.5.1 step 3.c)
+15.2.3.6-4-134: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is thrown when the [[Value]] field of
+# 'desc' is -Infinity (15.4.5.1 step 3.c)
+15.2.3.6-4-135: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is thrown when the [[Value]] field of
+# 'desc' is NaN (15.4.5.1 step 3.c)
+15.2.3.6-4-136: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is not thrown when the [[Value]] field of
+# 'desc' is a string containing a positive number (15.4.5.1 step 3.c)
+15.2.3.6-4-137: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is thrown when the [[Value]] field of
+# 'desc' is a string containing a negative number (15.4.5.1 step 3.c)
+15.2.3.6-4-138: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is thrown when the [[Value]] field of
+# 'desc' is a string containing a decimal number (15.4.5.1 step 3.c)
+15.2.3.6-4-139: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is thrown when the [[Value]] field of
+# 'desc' is a string containing +Infinity (15.4.5.1 step 3.c)
+15.2.3.6-4-140: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is thrown when the [[Value]] field of
+# 'desc' is a string containing -Infinity (15.4.5.1 step 3.c)
+15.2.3.6-4-141: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is a string containing an
+# exponential number (15.4.5.1 step 3.c)
+15.2.3.6-4-142: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is a string containing a hex
+# number (15.4.5.1 step 3.c)
+15.2.3.6-4-143: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is a string containing a number
+# with leading zeros (15.4.5.1 step 3.c)
+15.2.3.6-4-144: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError exception is thrown when the [[Value]] field of
+# 'desc' is a string which doesn't convert to a number (15.4.5.1 step 3.c)
+15.2.3.6-4-145: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is an object which has an own
+# toString method (15.4.5.1 step 3.c)
+15.2.3.6-4-146: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is an Object which has an own
+# valueOf method (15.4.5.1 step 3.c)
+15.2.3.6-4-147: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is an Object which has an own
+# valueOf method that returns an object and toString method that returns a
+# string (15.4.5.1 step 3.c)
+15.2.3.6-4-148: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is an Object which has an own
+# toString and valueOf method (15.4.5.1 step 3.c)
+15.2.3.6-4-149: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test TypeError is thrown when the [[Value]] field of 'desc' is an
+# Object that both toString and valueOf wouldn't return primitive value
+# (15.4.5.1 step 3.c)
+15.2.3.6-4-150: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', and the [[Value]] field of 'desc' is an Object with an own toString
+# method and an inherited valueOf method (15.4.5.1 step 3.c), test that the
+# inherited valueOf method is used
+15.2.3.6-4-151: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError is thrown when the [[Value]] field of 'desc' is a
+# positive non-integer values (15.4.5.1 step 3.c)
+15.2.3.6-4-152: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length prosperty
+# of 'O', test RangeError is thrown when the [[Value]] field of 'desc' is a
+# negative non-integer values (15.4.5.1 step 3.c)
+15.2.3.6-4-153: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is boundary value 2^32 - 2
+# (15.4.5.1 step 3.c)
+15.2.3.6-4-154: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test the [[Value]] field of 'desc' is boundary value 2^32 - 1
+# (15.4.5.1 step 3.c)
+15.2.3.6-4-155: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError is thrown when the [[Value]] field of 'desc' is
+# boundary value 2^32 (15.4.5.1 step 3.c)
+15.2.3.6-4-156: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', test RangeError is thrown when the [[Value]] field of 'desc' is
+# boundary value 2^32 + 1 (15.4.5.1 step 3.c)
+15.2.3.6-4-157: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', set the [[Value]] field of 'desc' to a value greater than the
+# existing value of length (15.4.5.1 step 3.f)
+15.2.3.6-4-159: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', set the [[Value]] field of 'desc' to a value lesser than the
+# existing value of length and test that indexes beyond the new length are
+# deleted(15.4.5.1 step 3.f)
+15.2.3.6-4-161: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property is set
+# to true after deleting properties with large index named if the
+# [[Writable]] field of 'desc' is absent (15.4.5.1 step 3.h)
+15.2.3.6-4-165: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property is set
+# to true after deleting properties with large index named if the
+# [[Writable]] field of 'desc' is true (15.4.5.1 step 3.h)
+15.2.3.6-4-166: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property is set
+# to false after deleting properties with large index named if the
+# [[Writable]] field of 'desc' is false (15.4.5.1 step 3.i.ii)
+15.2.3.6-4-167: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', whose writable attribute is being changed to false and the [[Value]]
+# field of 'desc' is less than value of the length property and also lesser
+# than an index of the array which is set to configurable:false, test that
+# new length is set to a value greater than the non-deletable index by 1,
+# writable attribute of length is set to false and TypeError exception is
+# thrown (15.4.5.1 step 3.i.iii)
+15.2.3.6-4-168: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property and also lesser than an index of the array which is set to
+# configurable: false, test that new length is set to a value greater than
+# the non-deletable index by 1, and TypeError is thrown (15.4.5.1 step
+# 3.l.i)
+15.2.3.6-4-169: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property and also lesser than an index of the array which is set to
+# configurable: false, test that new length is set to a value greater than
+# the non-deletable index by 1, writable attribute of length is set to
+# false and TypeError exception is thrown (15.4.5.1 step 3.l.ii)
+15.2.3.6-4-170: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of an inherited data
+# property with large index named in 'O' can't stop deleting index named
+# properties (15.4.5.1 step 3.l.ii)
+15.2.3.6-4-171: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own data property with
+# large index named in 'O' that overrides an inherited data property can
+# stop deleting index named properties (15.4.5.1 step 3.l.ii)
+15.2.3.6-4-172: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own data property with
+# large index named in 'O' that overrides an inherited accessor property
+# can stop deleting index named properties (15.4.5.1 step 3.l.ii)
+15.2.3.6-4-173: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own accessor property
+# with large index named in 'O' can stop deleting index named properties
+# (15.4.5.1 step 3.l.ii)
+15.2.3.6-4-174: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of an inherited accessor
+# property with large index named in 'O' can't stop deleting index named
+# properties (15.4.5.1 step 3.l.ii)
+15.2.3.6-4-175: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own accessor property
+# with large index named in 'O' that overrides an inherited data property
+# can stop deleting index named properties (15.4.5.1 step 3.l.ii)
+15.2.3.6-4-176: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own accessor property
+# with large index named in 'O' that overrides an inherited accessor
+# property can stop deleting index named properties (15.4.5.1 step 3.l.ii)
+15.2.3.6-4-177: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the configurable large index named property of 'O' is
+# deleted (15.4.5.1 step 3.l.ii)
+15.2.3.6-4-178: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is greater than value of the length
+# property, test value of the length property is same as [[Value]]
+# (15.4.5.1 step 3.l.iii.1)
+15.2.3.6-4-179-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property is set
+# to false at last when the [[Writable]] field of 'desc' is false and 'O'
+# doesn't contain non-configurable large index named property (15.4.5.1
+# step 3.m)
+15.2.3.6-4-181: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, 'name' is boundary value 2^32 - 2 (15.4.5.1 step 4.a)
+15.2.3.6-4-183: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, test TypeError is thrown if the [[Writable]] attribute of the
+# length property in 'O' is false and value of 'name' equals to value of
+# the length property (15.4.5.1 step 4.b)
+15.2.3.6-4-188: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, test TypeError is thrown if the [[Writable]] attribute of the
+# length property in 'O' is false and value of 'name' is greater than value
+# of the length property (15.4.5.1 step 4.b)
+15.2.3.6-4-189: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, 'desc' is accessor descriptor, test updating all attribute
+# values of 'name' (15.4.5.1 step 4.c)
+15.2.3.6-4-209: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, 'name' is accessor property and assignment to the accessor
+# property, fails to convert accessor property from accessor property to
+# data property (15.4.5.1 step 4.c)
+15.2.3.6-4-243-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, name is accessor property and 'desc' is accessor descriptor,
+# test updating the [[Enumerable]] attribute value of 'name' (15.4.5.1 step
+# 4.c)
+15.2.3.6-4-271: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, name is accessor property and 'desc' is accessor descriptor,
+# test updating the [[Configurable]] attribute value of 'name' (15.4.5.1
+# step 4.c)
+15.2.3.6-4-272: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, name is accessor property and 'desc' is accessor descriptor,
+# test updating multiple attribute values of 'name' (15.4.5.1 step 4.c)
+15.2.3.6-4-273: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, test the length property of 'O' is set as ToUint32('name') + 1
+# if ToUint32('name') equals to value of the length property in 'O'
+# (15.4.5.1 step 4.e.ii)
+15.2.3.6-4-275: FAIL
+# Bug? Object.defineProperty - 'O' is an Array, 'name' is an array index named
+# property, test the length property of 'O' is set as ToUint32('name') + 1
+# if ToUint32('name') is greater than value of the length property in 'O'
+# (15.4.5.1 step 4.e.ii)
+15.2.3.6-4-276: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
+# formal parameters, 'name' is own property which is defined in both
+# [[ParameterMap]] of 'O' and 'O', and is deleted afterwards, and 'desc' is
+# data descriptor, test 'name' is redefined in 'O' with all correct
+# attribute values (10.6 [[DefineOwnProperty]] step 3)
+15.2.3.6-4-289-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
+# formal parameters, 'name' is own property which is defined in both
+# [[ParameterMap]] of 'O' and 'O', is deleted afterwards, and 'desc' is
+# accessor descriptor, test 'name' is redefined in 'O' with all correct
+# attribute values (10.6 [[DefineOwnProperty]] step 3)
+15.2.3.6-4-290-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
+# formal parameters, 'name' is own accessor property of 'O' which is also
+# defined in [[ParameterMap]] of 'O', and 'desc' is accessor descriptor,
+# test updating multiple attribute values of 'name' (10.6
+# [[DefineOwnProperty]] step 3 and 5.a.i)
+15.2.3.6-4-291-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object, 'name' is own
+# accessor property of 'O', and 'desc' is accessor descriptor, test
+# updating multiple attribute values of 'name' (10.6 [[DefineOwnProperty]]
+# step 3)
+15.2.3.6-4-291: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
+# formal parameters, 'name' is own data property of 'O' which is also
+# defined in [[ParameterMap]] of 'O', test TypeError is not thrown when
+# updating the [[Value]] attribute value of 'name' which is defined as
+# non-writable and configurable (10.6 [[DefineOwnProperty]] step 3 and step
+# 5.b)
+15.2.3.6-4-293-3: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
+# formal parameters, 'name' is own accessor property of 'O' which is also
+# defined in [[ParameterMap]] of 'O', test TypeError is thrown when
+# updating the [[Get]] attribute value of 'name' which is defined as
+# non-configurable (10.6 [[DefineOwnProperty]] step 4 and step 5a)
+15.2.3.6-4-297-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
+# formal parameters, 'name' is own accessor property of 'O' which is also
+# defined in [[ParameterMap]] of 'O', test TypeError is thrown when
+# updating the [[Set]] attribute value of 'name' which is defined as
+# non-configurable (10.6 [[DefineOwnProperty]] steps 4 and 5a)
+15.2.3.6-4-298-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
+# formal parameters, 'name' is own accessor property of 'O' which is also
+# defined in [[ParameterMap]] of 'O', test TypeError is thrown when
+# updating the [[Enumerable]] attribute value of 'name' which is defined as
+# non-configurable (10.6 [[DefineOwnProperty]] steps 4 and 5a)
+15.2.3.6-4-299-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
+# formal parameters, 'name' is an index named property of 'O', and 'desc'
+# is data descriptor, test 'name' is defined in 'O' with all correct
+# attribute values (10.6 [[DefineOwnProperty]] step 3)
+15.2.3.6-4-301-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object of a function that has
+# formal parameters, 'name' is an index named property of 'O' but not
+# defined in [[ParameterMap]] of 'O', and 'desc' is accessor descriptor,
+# test 'name' is defined in 'O' with all correct attribute values (10.6
+# [[DefineOwnProperty]] step 3 and step 5a)
+15.2.3.6-4-302-1: FAIL
+# Bug? Object.defineProperty - 'O' is an Arguments object, 'name' is an index
+# named accessor property of 'O' but not defined in [[ParameterMap]] of
+# 'O', and 'desc' is accessor descriptor, test updating multiple attribute
+# values of 'name' (10.6 [[DefineOwnProperty]] step 3)
+15.2.3.6-4-303: FAIL
+# Bug? ES5 Attributes - [[Value]] attribute of data property is the activex host
+# object
+15.2.3.6-4-401: FAIL
+# Bug? ES5 Attributes - Failed to add a property to an object when the object's
+# object has a property with same name and [[Writable]] attribute is set to
+# false (Number instance)
+15.2.3.6-4-405: FAIL
+# Bug? ES5 Attributes - Failed to add a property to an object when the object's
+# prototype has a property with the same name and [[Writable]] set to false
+# (JSON)
+15.2.3.6-4-410: FAIL
+# Bug? ES5 Attributes - Failed to add properties to an object when the object's
+# prototype has properties with the same name and [[Writable]] set to false
+# (Object.create)
+15.2.3.6-4-415: FAIL
+# Bug? ES5 Attributes - Failed to add a property to an object when the object's
+# prototype has a property with the same name and [[Writable]] set to
+# false(Function.prototype.bind)
+15.2.3.6-4-420: FAIL
+# Bug? ES5 Attributes - Fail to add property into object (Number instance)
+15.2.3.6-4-581: FAIL
+# Bug? ES5 Attributes - Fail to update value of property into of [[Proptotype]]
+# internal property (JSON)
+15.2.3.6-4-586: FAIL
+# Bug? ES5 Attributes - Fail to update value of property of [[Proptotype]]
+# internal property (Object.create)
+15.2.3.6-4-591: FAIL
+# Bug? ES5 Attributes - Fail to update value of property into of [[Proptotype]]
+# internal property (Function.prototype.bind)
+15.2.3.6-4-596: FAIL
+# Bug? ES5 Attributes - all attributes in Array.prototype.indexOf are correct
+15.2.3.6-4-612: FAIL
+# Bug? ES5 Attributes - all attributes in Object.lastIndexOf are correct
+15.2.3.6-4-613: FAIL
+# Bug? ES5 Attributes - all attributes in Array.prototype.every are correct
+15.2.3.6-4-614: FAIL
+# Bug? ES5 Attributes - all attributes in Array.prototype.some are correct
+15.2.3.6-4-615: FAIL
+# Bug? ES5 Attributes - all attributes in Array.prototype.forEach are correct
+15.2.3.6-4-616: FAIL
+# Bug? ES5 Attributes - all attributes in Array.prototype.map are correct
+15.2.3.6-4-617: FAIL
+# Bug? ES5 Attributes - all attributes in Array.prototype.filter are correct
+15.2.3.6-4-618: FAIL
+# Bug? ES5 Attributes - all attributes in Array.prototype.reduce are correct
+15.2.3.6-4-619: FAIL
+# Bug? ES5 Attributes - all attributes in Array.prototype.reduceRight are
+# correct
+15.2.3.6-4-620: FAIL
+# Bug? ES5 Attributes - all attributes in String.prototype.trim are correct
+15.2.3.6-4-621: FAIL
+# Bug? ES5 Attributes - all attributes in Date.prototype.toISOString are correct
+15.2.3.6-4-623: FAIL
+# Bug? ES5 Attributes - all attributes in Date.prototype.toJSON are correct
+15.2.3.6-4-624: FAIL
+# Bug? Object.defineProperties - argument 'Properties' is an Error object
+# props.description = obj1;
+15.2.3.7-2-15: FAIL
+# Bug? Object.defineProperties - 'Properties' is an Error object which
+# implements its own [[Get]] method to get enumerable own property
+# props.description = obj1;
+15.2.3.7-5-a-16: FAIL
+# Bug? Object.defineProperties - 'set' property of 'descObj' is not present
+# (8.10.5 step 8)
+15.2.3.7-5-b-227: FAIL
+# Bug? Object.defineProperties - 'descObj' is an Error object which implements
+# its own [[Get]] method to get 'set' property (8.10.5 step 8.a)
+# descObj.description = { value: 11 };
+15.2.3.7-5-b-248: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, test the length property of
+# 'O' is own data property (15.4.5.1 step 1)
+15.2.3.7-6-a-112: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, test the length property of
+# 'O' is own data property that overrides an inherited data property
+# (15.4.5.1 step 1)
+15.2.3.7-6-a-113: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', test RangeError is thrown when setting the [[Value]] field of 'desc'
+# to undefined (15.4.5.1 step 3.c)
+15.2.3.7-6-a-121: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', test setting the [[Value]] field of 'desc' to null actuall is set to
+# 0 (15.4.5.1 step 3.c)
+15.2.3.7-6-a-122: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a boolean with value false
+# (15.4.5.1 step 3.c)
+15.2.3.7-6-a-123: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a boolean with value true
+# (15.4.5.1 step 3.c)
+15.2.3.7-6-a-124: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is 0 (15.4.5.1 step 3.c)
+15.2.3.7-6-a-125: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is +0 (15.4.5.1 step 3.c)
+15.2.3.7-6-a-126: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is -0 (15.4.5.1 step 3.c)
+15.2.3.7-6-a-127: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is positive number (15.4.5.1
+# step 3.c)
+15.2.3.7-6-a-128: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is negative number (15.4.5.1
+# step 3.c)
+15.2.3.7-6-a-129: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is +Infinity (15.4.5.1 step
+# 3.c)
+15.2.3.7-6-a-130: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is -Infinity (15.4.5.1 step
+# 3.c)
+15.2.3.7-6-a-131: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is NaN (15.4.5.1 step 3.c)
+15.2.3.7-6-a-132: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a string containing a
+# positive number (15.4.5.1 step 3.c)
+15.2.3.7-6-a-133: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a string containing a
+# negative number (15.4.5.1 step 3.c)
+15.2.3.7-6-a-134: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a string containing a
+# decimal number (15.4.5.1 step 3.c)
+15.2.3.7-6-a-135: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a string containing
+# +Infinity (15.4.5.1 step 3.c)
+15.2.3.7-6-a-136: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a string containing
+# -Infinity (15.4.5.1 step 3.c)
+15.2.3.7-6-a-137: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a string containing an
+# exponential number (15.4.5.1 step 3.c)
+15.2.3.7-6-a-138: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a string containing an hex
+# number (15.4.5.1 step 3.c)
+15.2.3.7-6-a-139: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is a string containing an
+# leading zero number (15.4.5.1 step 3.c)
+15.2.3.7-6-a-140: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', test the [[Value]] field of 'desc' is a string which doesn't convert
+# to a number (15.4.5.1 step 3.c)
+15.2.3.7-6-a-141: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', test the [[Value]] field of 'desc' is an Object which has an own
+# toString method (15.4.5.1 step 3.c)
+15.2.3.7-6-a-142: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is an Object which has an own
+# valueOf method (15.4.5.1 step 3.c)
+15.2.3.7-6-a-143: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is an Object which has an own
+# valueOf method that returns an object and toString method that returns a
+# string (15.4.5.1 step 3.c)
+15.2.3.7-6-a-144: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is an Object which has an own
+# toString and valueOf method (15.4.5.1 step 3.c)
+15.2.3.7-6-a-145: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test TypeError is thrown when the [[Value]] field of 'desc' is an
+# Object that both toString and valueOf wouldn't return primitive value
+# (15.4.5.1 step 3.c)
+15.2.3.7-6-a-146: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test using inherited valueOf method when the [[Value]] field of
+# 'desc' is an Objec with an own toString and inherited valueOf methods
+# (15.4.5.1 step 3.c)
+15.2.3.7-6-a-147: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test RangeError is thrown when the [[Value]] field of 'desc' is
+# positive non-integer values (15.4.5.1 step 3.c)
+15.2.3.7-6-a-148: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test RangeError is thrown when the [[Value]] field of 'desc' is
+# negative non-integer values (15.4.5.1 step 3.c)
+15.2.3.7-6-a-149: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is boundary value 2^32 - 2
+# (15.4.5.1 step 3.c)
+15.2.3.7-6-a-150: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test the [[Value]] field of 'desc' is boundary value 2^32 - 1
+# (15.4.5.1 step 3.c)
+15.2.3.7-6-a-151: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test RangeError is thrown when the [[Value]] field of 'desc' is
+# boundary value 2^32 (15.4.5.1 step 3.c)
+15.2.3.7-6-a-152: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'name' is the length property
+# of 'O', test RangeError is thrown when the [[Value]] field of 'desc' is
+# boundary value 2^32 + 1 (15.4.5.1 step 3.c)
+15.2.3.7-6-a-153: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', test the [[Value]] field of 'desc' which is greater than value of
+# the length property is defined into 'O' without deleting any property
+# with large index named (15.4.5.1 step 3.f)
+15.2.3.7-6-a-155: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', test the [[Value]] field of 'desc' which is less than value of the
+# length property is defined into 'O' with deleting properties with large
+# index named (15.4.5.1 step 3.f)
+15.2.3.7-6-a-157: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property is set
+# to true at last after deleting properties with large index named if the
+# [[Writable]] field of 'desc' is absent (15.4.5.1 step 3.h)
+15.2.3.7-6-a-161: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property is set
+# to true at last after deleting properties with large index named if the
+# [[Writable]] field of 'desc' is true (15.4.5.1 step 3.h)
+15.2.3.7-6-a-162: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property is set
+# to false at last after deleting properties with large index named if the
+# [[Writable]] field of 'desc' is false (15.4.5.1 step 3.i.ii)
+15.2.3.7-6-a-163: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property in 'O'
+# is set as true before deleting properties with large index named
+# (15.4.5.1 step 3.i.iii)
+15.2.3.7-6-a-164: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the length property is decreased by 1 (15.4.5.1 step
+# 3.l.i)
+15.2.3.7-6-a-165: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own data property with
+# large index named in 'O' can stop deleting index named properties
+# (15.4.5.1 step 3.l.ii)
+15.2.3.7-6-a-166: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of inherited data property
+# with large index named in 'O' can't stop deleting index named properties
+# (15.4.5.1 step 3.l.ii)
+15.2.3.7-6-a-167: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own data property with
+# large index named in 'O' that overrides inherited data property can stop
+# deleting index named properties (15.4.5.1 step 3.l.ii)
+15.2.3.7-6-a-168: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own data property with
+# large index named in 'O' that overrides inherited accessor property can
+# stop deleting index named properties (15.4.5.1 step 3.l.ii)
+15.2.3.7-6-a-169: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own accessor property
+# with large index named in 'O' can stop deleting index named properties
+# (15.4.5.1 step 3.l.ii)
+15.2.3.7-6-a-170: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of inherited accessor
+# property with large index named in 'O' can't stop deleting index named
+# properties (15.4.5.1 step 3.l.ii)
+15.2.3.7-6-a-171: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own accessor property
+# with large index named in 'O' that overrides inherited data property can
+# stop deleting index named properties (15.4.5.1 step 3.l.ii)
+15.2.3.7-6-a-172: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Configurable]] attribute of own accessor property
+# with large index named in 'O' that overrides inherited accessor property
+# can stop deleting index named properties (15.4.5.1 step 3.l.ii)
+15.2.3.7-6-a-173: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the configurable large index named property of 'O' can be
+# deleted (15.4.5.1 step 3.l.ii)
+15.2.3.7-6-a-174: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test value of the length property is set to the last
+# non-configurable index named property of 'O' plus 1 (15.4.5.1 step
+# 3.l.iii.1)
+15.2.3.7-6-a-175: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property is set
+# to false at last when the [[Writable]] field of 'desc' is false and 'O'
+# contains non-configurable large index named property (15.4.5.1 step
+# 3.l.iii.2)
+15.2.3.7-6-a-176: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is the length property of
+# 'O', the [[Value]] field of 'desc' is less than value of the length
+# property, test the [[Writable]] attribute of the length property is set
+# to false at last when the [[Writable]] field of 'desc' is false and 'O'
+# doesn't contain non-configurable large index named property (15.4.5.1
+# step 3.m)
+15.2.3.7-6-a-177: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
+# property, 'P' is boundary value 2^32 - 2 (15.4.5.1 step 4.a)
+15.2.3.7-6-a-179: FAIL
+# Bug? Object.defineProperties - TypeError is thrown if 'O' is an Array, 'P' is
+# an array index named property,[[Writable]] attribute of the length
+# property in 'O' is false, value of 'P' is equal to value of the length
+# property in 'O' (15.4.5.1 step 4.b)
+15.2.3.7-6-a-184: FAIL
+# Bug? Object.defineProperties - TypeError is thrown if 'O' is an Array, 'P' is
+# an array index named property,[[Writable]] attribute of the length
+# property in 'O' is false, value of 'P' is bigger than value of the length
+# property in 'O' (15.4.5.1 step 4.b)
+15.2.3.7-6-a-185: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
+# property, 'desc' is accessor descriptor, test updating all attribute
+# values of 'P' (15.4.5.1 step 4.c)
+15.2.3.7-6-a-205: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
+# property that already exists on 'O' is accessor property and 'desc' is
+# accessor descriptor, test updating the [[Enumerable]] attribute value of
+# 'P' (15.4.5.1 step 4.c)
+15.2.3.7-6-a-260: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
+# property that already exists on 'O' is accessor property and 'desc' is
+# accessor descriptor, test updating the [[Configurable]] attribute value
+# of 'P' (15.4.5.1 step 4.c)
+15.2.3.7-6-a-261: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
+# property that already exists on 'O' is accessor property and 'desc' is
+# accessor descriptor, test updating multiple attribute values of 'P'
+# (15.4.5.1 step 4.c)
+15.2.3.7-6-a-262: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
+# property, test the length property of 'O' is set as ToUint32('P') + 1 if
+# ToUint32('P') equals to value of the length property in 'O' (15.4.5.1
+# step 4.e.ii)
+15.2.3.7-6-a-264: FAIL
+# Bug? Object.defineProperties - 'O' is an Array, 'P' is an array index named
+# property, test the length property of 'O' is set as ToUint32('P') + 1 if
+# ToUint32('P') is greater than value of the length property in 'O'
+# (15.4.5.1 step 4.e.ii)
+15.2.3.7-6-a-265: FAIL
+# Bug? Object.defineProperties - 'O' is an Arguments object, 'P' is own accessor
+# property of 'O' which is also defined in [[ParameterMap]] of 'O', and
+# 'desc' is accessor descriptor, test updating multiple attribute values of
+# 'P' (10.6 [[DefineOwnProperty]] step 3)
+15.2.3.7-6-a-280: FAIL
+# Bug? Object.defineProperties - 'O' is an Arguments object, 'P' is an array
+# index named accessor property of 'O' but not defined in [[ParameterMap]]
+# of 'O', and 'desc' is accessor descriptor, test updating multiple
+# attribute values of 'P' (10.6 [[DefineOwnProperty]] step 3)
+15.2.3.7-6-a-292: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into the
+# returned object
+15.2.3.10-3-2: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into a
+# Function object
+15.2.3.10-3-3: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into an
+# Array object
+15.2.3.10-3-4: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into a
+# String object
+15.2.3.10-3-5-1: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into a
+# Boolean object
+15.2.3.10-3-6: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into a
+# Number object
+15.2.3.10-3-7: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into a Date
+# object
+15.2.3.10-3-8: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into a
+# RegExp object
+15.2.3.10-3-9: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into an
+# Error object
+15.2.3.10-3-10: FAIL
+# Bug? Object.preventExtensions - indexed properties cannot be added into an
+# Arguments object
+15.2.3.10-3-11: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into the
+# returned object
+15.2.3.10-3-12: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into a
+# Function object
+15.2.3.10-3-13: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into an Array
+# object
+15.2.3.10-3-14: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into a String
+# object
+15.2.3.10-3-15: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into a
+# Boolean object
+15.2.3.10-3-16: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into a Number
+# object
+15.2.3.10-3-17: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into a Date
+# object
+15.2.3.10-3-18: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into a RegExp
+# object
+15.2.3.10-3-19: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into an Error
+# object
+15.2.3.10-3-20: FAIL
+# Bug? Object.preventExtensions - named properties cannot be added into an
+# Arguments object
+15.2.3.10-3-21: FAIL
+# Bug? Object.prototype.toString - '[object Undefined]' will be returned when
+# 'this' value is undefined
+15.2.4.2-1-1: FAIL
+# Bug? Object.prototype.toString - '[object Undefined]' will be returned when
+# 'this' value is undefined
+15.2.4.2-1-2: FAIL
+# Bug? Object.prototype.toString - '[object Null]' will be returned when 'this'
+# value is null
+15.2.4.2-2-1: FAIL
+# Bug? Object.prototype.toString - '[object Null]' will be returned when 'this'
+# value is null
+15.2.4.2-2-2: FAIL
+# Bug? Function.prototype.bind - [[Get]] attribute of 'caller' property in 'F'
+# is thrower
+15.3.4.5-20-2: FAIL
+# Bug? Function.prototype.bind - [[Set]] attribute of 'caller' property in 'F'
+# is thrower
+15.3.4.5-20-3: FAIL
+# Bug? Function.prototype.bind - [[Get]] attribute of 'arguments' property in
+# 'F' is thrower
+15.3.4.5-21-2: FAIL
+# Bug? Function.prototype.bind - [[Set]] attribute of 'arguments' property in
+# 'F' is thrower
+15.3.4.5-21-3: FAIL
+# Bug? Array.prototype.concat will concat an Array when index property
+# (read-only) exists in Array.prototype (Step 5.c.i)
+15.4.4.4-5-c-i-1: FAIL
+# Bug? Array.prototype.indexOf applied to undefined throws a TypeError
+15.4.4.14-1-1: FAIL
+# Bug? Array.prototype.indexOf applied to null throws a TypeError
+15.4.4.14-1-2: FAIL
+# Bug? Array.prototype.indexOf - side effects produced by step 1 are visible
+# when an exception occurs
+15.4.4.14-5-28: FAIL
+# Bug? Array.prototype.indexOf - decreasing length of array does not delete
+# non-configurable properties
+15.4.4.14-9-a-19: FAIL
+# Bug? Array.prototype.indexOf - element to be retrieved is own accessor
+# property that overrides an inherited data property on an Array
+15.4.4.14-9-b-i-11: FAIL
+# Bug? Array.prototype.indexOf - element to be retrieved is own accessor
+# property that overrides an inherited accessor property on an Array
+15.4.4.14-9-b-i-13: FAIL
+# Bug? Array.prototype.indexOf - element to be retrieved is own accessor
+# property without a get function on an Array
+15.4.4.14-9-b-i-17: FAIL
+# Bug? Array.prototype.indexOf - element to be retrieved is own accessor
+# property without a get function that overrides an inherited accessor
+# property on an Array
+15.4.4.14-9-b-i-19: FAIL
+# Bug? Array.prototype.indexOf - side-effects are visible in subsequent
+# iterations on an Array
+15.4.4.14-9-b-i-28: FAIL
+# Bug? Array.prototype.indexOf - terminates iteration on unhandled exception on
+# an Array
+15.4.4.14-9-b-i-30: FAIL
+# Bug? Array.prototype.lastIndexOf applied to undefined throws a TypeError
+15.4.4.15-1-1: FAIL
+# Bug? Array.prototype.lastIndexOf applied to null throws a TypeError
+15.4.4.15-1-2: FAIL
+# Bug? Array.prototype.lastIndexOf - side effects produced by step 1 are visible
+# when an exception occurs
+15.4.4.15-5-28: FAIL
+# Bug? Array.prototype.lastIndexOf - deleting property of prototype causes
+# prototype index property not to be visited on an Array
+15.4.4.15-8-a-14: FAIL
+# Bug? Array.prototype.lastIndexOf - decreasing length of array does not delete
+# non-configurable properties
+15.4.4.15-8-a-19: FAIL
+# Bug? Array.prototype.lastIndexOf - element to be retrieved is own accessor
+# property that overrides an inherited data property on an Array
+15.4.4.15-8-b-i-11: FAIL
+# Bug? Array.prototype.lastIndexOf - element to be retrieved is own accessor
+# property that overrides an inherited accessor property on an Array
+15.4.4.15-8-b-i-13: FAIL
+# Bug? Array.prototype.lastIndexOf - element to be retrieved is own accessor
+# property without a get function on an Array
+15.4.4.15-8-b-i-17: FAIL
+# Bug? Array.prototype.lastIndexOf - side-effects are visible in subsequent
+# iterations on an Array
+15.4.4.15-8-b-i-28: FAIL
+# Bug? Array.prototype.lastIndexOf terminates iteration on unhandled exception
+# on an Array
+15.4.4.15-8-b-i-30: FAIL
+# Bug? Array.prototype.every - side effects produced by step 2 are visible when
+# an exception occurs
+15.4.4.16-4-8: FAIL
+# Bug? Array.prototype.every - side effects produced by step 3 are visible when
+# an exception occurs
+15.4.4.16-4-9: FAIL
+# Bug? Array.prototype.every - the exception is not thrown if exception was
+# thrown by step 2
+15.4.4.16-4-10: FAIL
+# Bug? Array.prototype.every - the exception is not thrown if exception was
+# thrown by step 3
+15.4.4.16-4-11: FAIL
+# Bug? Array.prototype.every - calling with no callbackfn is the same as passing
+# undefined for callbackfn
+15.4.4.16-4-15: FAIL
+# Bug? Array.prototype.every - decreasing length of array does not delete
+# non-configurable properties
+15.4.4.16-7-b-16: FAIL
+# Bug? Array.prototype.every - element to be retrieved is own accessor property
+# on an Array
+15.4.4.16-7-c-i-10: FAIL
+# Bug? Array.prototype.every - element to be retrieved is own accessor property
+# that overrides an inherited data property on an Array
+15.4.4.16-7-c-i-12: FAIL
+# Bug? Array.prototype.every - element to be retrieved is own accessor property
+# that overrides an inherited accessor property on an Array
+15.4.4.16-7-c-i-14: FAIL
+# Bug? Array.prototype.every - element to be retrieved is own accessor property
+# without a get function on an Array
+15.4.4.16-7-c-i-18: FAIL
+# Bug? Array.prototype.every - element to be retrieved is own accessor property
+# without a get function that overrides an inherited accessor property on
+# an Array
+15.4.4.16-7-c-i-20: FAIL
+# Bug? Array.prototype.every - element changed by getter on previous iterations
+# is observed on an Array
+15.4.4.16-7-c-i-28: FAIL
+# Bug? Array.prototype.some - side effects produced by step 2 are visible when
+# an exception occurs
+15.4.4.17-4-8: FAIL
+# Bug? Array.prototype.some - side effects produced by step 3 are visible when
+# an exception occurs
+15.4.4.17-4-9: FAIL
+# Bug? Array.prototype.some - the exception is not thrown if exception was
+# thrown by step 2
+15.4.4.17-4-10: FAIL
+# Bug? Array.prototype.some - the exception is not thrown if exception was
+# thrown by step 3
+15.4.4.17-4-11: FAIL
+# Bug? Array.prototype.some - calling with no callbackfn is the same as passing
+# undefined for callbackfn
+15.4.4.17-4-15: FAIL
+# Bug? Array.prototype.some - decreasing length of array does not delete
+# non-configurable properties
+15.4.4.17-7-b-16: FAIL
+# Bug? Array.prototype.some - element to be retrieved is own accessor property
+# on an Array
+15.4.4.17-7-c-i-10: FAIL
+# Bug? Array.prototype.some - element to be retrieved is own accessor property
+# that overrides an inherited data property on an Array
+15.4.4.17-7-c-i-12: FAIL
+# Bug? Array.prototype.some - element to be retrieved is own accessor property
+# that overrides an inherited accessor property on an Array
+15.4.4.17-7-c-i-14: FAIL
+# Bug? Array.prototype.some - element to be retrieved is own accessor property
+# without a get function on an Array
+15.4.4.17-7-c-i-18: FAIL
+# Bug? Array.prototype.some - element to be retrieved is own accessor property
+# without a get function that overrides an inherited accessor property on
+# an Array
+15.4.4.17-7-c-i-20: FAIL
+# Bug? Array.prototype.some - element changed by getter on previous iterations
+# is observed on an Array
+15.4.4.17-7-c-i-28: FAIL
+# Bug? Array.prototype.forEach - side effects produced by step 2 are visible
+# when an exception occurs
+15.4.4.18-4-8: FAIL
+# Bug? Array.prototype.forEach - side effects produced by step 3 are visible
+# when an exception occurs
+15.4.4.18-4-9: FAIL
+# Bug? Array.prototype.forEach - the exception is not thrown if exception was
+# thrown by step 2
+15.4.4.18-4-10: FAIL
+# Bug? Array.prototype.forEach - the exception is not thrown if exception was
+# thrown by step 3
+15.4.4.18-4-11: FAIL
+# Bug? Array.prototype.forEach - calling with no callbackfn is the same as
+# passing undefined for callbackfn
+15.4.4.18-4-15: FAIL
+# Bug? Array.prototype.forEach - decreasing length of array does not delete
+# non-configurable properties
+15.4.4.18-7-b-16: FAIL
+# Bug? Array.prototype.forEach - element to be retrieved is own accessor
+# property on an Array
+15.4.4.18-7-c-i-10: FAIL
+# Bug? Array.prototype.forEach - element to be retrieved is own accessor
+# property that overrides an inherited data property on an Array
+15.4.4.18-7-c-i-12: FAIL
+# Bug? Array.prototype.forEach - element to be retrieved is own accessor
+# property that overrides an inherited accessor property on an Array
+15.4.4.18-7-c-i-14: FAIL
+# Bug? Array.prototype.forEach - element to be retrieved is own accessor
+# property without a get function on an Array
+15.4.4.18-7-c-i-18: FAIL
+# Bug? Array.prototype.forEach - element to be retrieved is own accessor
+# property without a get function that overrides an inherited accessor
+# property on an Array
+15.4.4.18-7-c-i-20: FAIL
+# Bug? Array.prototype.forEach - element changed by getter on previous
+# iterations is observed on an Array
+15.4.4.18-7-c-i-28: FAIL
+# Bug? Array.prototype.map - applied to Array-like object, 'length' is an own
+# data property that overrides an inherited accessor property
+15.4.4.19-2-5: FAIL
+# Bug? Array.prototype.map - Side effects produced by step 2 are visible when an
+# exception occurs
+15.4.4.19-4-8: FAIL
+# Bug? Array.prototype.map - Side effects produced by step 3 are visible when an
+# exception occurs
+15.4.4.19-4-9: FAIL
+# Bug? Array.prototype.map - the exception is not thrown if exception was thrown
+# by step 2
+15.4.4.19-4-10: FAIL
+# Bug? Array.prototype.map - the exception is not thrown if exception was thrown
+# by step 3
+15.4.4.19-4-11: FAIL
+# Bug? Array.prototype.map - calling with no callbackfn is the same as passing
+# undefined for callbackfn
+15.4.4.19-4-15: FAIL
+# Bug? Array.prototype.map - decreasing length of array does not delete
+# non-configurable properties
+15.4.4.19-8-b-16: FAIL
+# Bug? Array.prototype.map - element to be retrieved is own accessor property on
+# an Array
+15.4.4.19-8-c-i-10: FAIL
+# Bug? Array.prototype.map - element to be retrieved is own accessor property
+# that overrides an inherited data property on an Array
+15.4.4.19-8-c-i-12: FAIL
+# Bug? Array.prototype.map - element to be retrieved is own accessor property
+# that overrides an inherited accessor property on an Array
+15.4.4.19-8-c-i-14: FAIL
+# Bug? Array.prototype.map - element to be retrieved is own accessor property
+# without a get function on an Array
+15.4.4.19-8-c-i-18: FAIL
+# Bug? Array.prototype.map - element to be retrieved is own accessor property
+# without a get function that overrides an inherited accessor property on
+# an Array
+15.4.4.19-8-c-i-19: FAIL
+# Bug? Array.prototype.map - element changed by getter on previous iterations is
+# observed on an Array
+15.4.4.19-8-c-i-28: FAIL
+# Bug? Array.prototype.filter - value of 'length' is a number (value is
+# negative)
+15.4.4.20-3-7: FAIL
+# Bug? Array.prototype.filter - value of 'length' is a number (value is
+# Infinity)
+# V8 timeout
+15.4.4.20-3-8: SKIP
+# Bug? Array.prototype.filter - 'length' is a string containing a negative
+# number
+15.4.4.20-3-12: FAIL
+# Bug? Array.prototype.filter - 'length' is a string containing a decimal number
+15.4.4.20-3-13: FAIL
+# Bug? Array.prototype.filter - 'length' is a string containing +/-Infinity
+15.4.4.20-3-14: SKIP
+# Bug? Array.prototype.filter - value of 'length' is a positive non-integer,
+# ensure truncation occurs in the proper direction
+# V8 timeout
+15.4.4.20-3-24: FAIL
+# Bug? Array.prototype.filter - value of 'length' is a negative non-integer,
+# ensure truncation occurs in the proper direction
+15.4.4.20-3-25: FAIL
+# Bug? Array.prototype.filter - value of 'length' is boundary value (2^32)
+# V8 timeout
+15.4.4.20-3-28: SKIP
+# Bug? Array.prototype.filter - value of 'length' is boundary value (2^32 + 1)
+# V8 timeout
+15.4.4.20-3-29: SKIP
+# Bug? Array.prototype.filter - side effects produced by step 2 are visible when
+# an exception occurs
+15.4.4.20-4-8: FAIL
+# Bug? Array.prototype.filter - side effects produced by step 3 are visible when
+# an exception occurs
+15.4.4.20-4-9: FAIL
+# Bug? Array.prototype.filter - the exception is not thrown if exception was
+# thrown by step 2
+15.4.4.20-4-10: FAIL
+# Bug? Array.prototype.filter - the exception is not thrown if exception was
+# thrown by step 3
+15.4.4.20-4-11: FAIL
+# Bug? Array.prototype.filter - calling with no callbackfn is the same as
+# passing undefined for callbackfn
+15.4.4.20-4-15: FAIL
+# Bug? Array.prototype.filter - properties can be added to prototype after
+# current position are visited on an Array-like object
+15.4.4.20-9-b-6: FAIL
+# Bug? Array.prototype.filter - properties can be added to prototype after
+# current position are visited on an Array
+15.4.4.20-9-b-7: FAIL
+# Bug? Array.prototype.filter - decreasing length of array does not delete
+# non-configurable properties
+15.4.4.20-9-b-16: FAIL
+# Bug? Array.prototype.filter - element to be retrieved is own data property
+# that overrides an inherited accessor property on an Array
+15.4.4.20-9-c-i-6: FAIL
+# Bug? Array.prototype.filter - element to be retrieved is own accessor property
+# on an Array
+15.4.4.20-9-c-i-10: FAIL
+# Bug? Array.prototype.filter - element to be retrieved is own accessor property
+# that overrides an inherited data property on an Array
+15.4.4.20-9-c-i-12: FAIL
+# Bug? Array.prototype.filter - element to be retrieved is own accessor property
+# that overrides an inherited accessor property on an Array
+15.4.4.20-9-c-i-14: FAIL
+# Bug? Array.prototype.filter - element to be retrieved is inherited accessor
+# property on an Array
+15.4.4.20-9-c-i-16: FAIL
+# Bug? Array.prototype.filter - element to be retrieved is own accessor property
+# without a get function on an Array
+15.4.4.20-9-c-i-18: FAIL
+# Bug? Array.prototype.filter - element to be retrieved is own accessor property
+# without a get function that overrides an inherited accessor property on
+# an Array
+15.4.4.20-9-c-i-20: FAIL
+# Bug? Array.prototype.filter - element to be retrieved is inherited accessor
+# property without a get function on an Array
+15.4.4.20-9-c-i-22: FAIL
+# Bug? Array.prototype.filter - element changed by getter on previous iterations
+# is observed on an Array
+15.4.4.20-9-c-i-28: FAIL
+# Bug? Array.prototype.reduce - value of 'length' is a number (value is
+# negative)
+15.4.4.21-3-7: FAIL
+# Bug? Array.prototype.reduce - value of 'length' is a number (value is
+# Infinity)
+# V8 timeout.
+15.4.4.21-3-8: SKIP
+# Bug? Array.prototype.reduce - 'length' is a string containing a negative
+# number
+15.4.4.21-3-12: FAIL
+# Bug? Array.prototype.reduce - 'length' is a string containing a decimal number
+15.4.4.21-3-13: FAIL
+# Bug? Array.prototype.reduce - 'length' is a string containing +/-Infinity
+# V8 timeout.
+15.4.4.21-3-14: SKIP
+# Bug? Array.prototype.reduce - value of 'length' is a positive non-integer,
+# ensure truncation occurs in the proper direction
+15.4.4.21-3-24: FAIL
+# Bug? Array.prototype.reduce - value of 'length' is a negative non-integer,
+# ensure truncation occurs in the proper direction
+15.4.4.21-3-25: FAIL
+# Bug? Array.prototype.reduce - value of 'length' is boundary value (2^32)
+# V8 timeout.
+15.4.4.21-3-28: SKIP
+# Bug? Array.prototype.reduce - value of 'length' is boundary value (2^32 + 1)
+# V8 timeout.
+15.4.4.21-3-29: SKIP
+# Bug? Array.prototype.reduce - side effects produced by step 2 are visible when
+# an exception occurs
+15.4.4.21-4-8: FAIL
+# Bug? Array.prototype.reduce - side effects produced by step 3 are visible when
+# an exception occurs
+15.4.4.21-4-9: FAIL
+# Bug? Array.prototype.reduce - the exception is not thrown if exception was
+# thrown by step 2
+15.4.4.21-4-10: FAIL
+# Bug? Array.prototype.reduce - the exception is not thrown if exception was
+# thrown by step 3
+15.4.4.21-4-11: FAIL
+# Bug? Array.prototype.reduce - calling with no callbackfn is the same as
+# passing undefined for callbackfn
+15.4.4.21-4-15: FAIL
+# Bug? Array.prototype.reduce - decreasing length of array in step 8 does not
+# delete non-configurable properties
+15.4.4.21-9-b-16: FAIL
+# Bug? Array.prototype.reduce - decreasing length of array does not delete
+# non-configurable properties
+15.4.4.21-9-b-29: FAIL
+# Bug? Array.prototype.reduceRight - value of 'length' is a number (value is
+# negative)
+15.4.4.22-3-7: FAIL
+# Bug? Array.prototype.reduceRight - value of 'length' is a number (value is
+# Infinity)
+# V8 timeout.
+15.4.4.22-3-8: SKIP
+# Bug? Array.prototype.reduceRight - value of 'length' is a string containing a
+# negative number
+15.4.4.22-3-12: FAIL
+# Bug? Array.prototype.reduceRight - value of 'length' is a string containing a
+# decimal number
+15.4.4.22-3-13: FAIL
+# Bug? Array.prototype.reduceRight - value of 'length' is a string containing
+# +/-Infinity
+# V8 timeout.
+15.4.4.22-3-14: SKIP
+# Bug? Array.prototype.reduceRight - value of 'length' is a positive
+# non-integer, ensure truncation occurs in the proper direction
+15.4.4.22-3-24: FAIL
+# Bug? Array.prototype.reduceRight - value of 'length' is a negative
+# non-integer, ensure truncation occurs in the proper direction
+15.4.4.22-3-25: FAIL
+# Bug? Array.prototype.reduceRight - value of 'length' is boundary value (2^32)
+# V8 timeout.
+15.4.4.22-3-28: SKIP
+# Bug? Array.prototype.reduceRight - value of 'length' is boundary value (2^32 +
+# 1)
+# V8 timeout.
+15.4.4.22-3-29: SKIP
+# Bug? Array.prototype.reduceRight - side effects produced by step 2 are visible
+# when an exception occurs
+15.4.4.22-4-8: FAIL
+# Bug? Array.prototype.reduceRight - side effects produced by step 3 are visible
+# when an exception occurs
+15.4.4.22-4-9: FAIL
+# Bug? Array.prototype.reduceRight - the exception is not thrown if exception
+# was thrown by step 2
+15.4.4.22-4-10: FAIL
+# Bug? Array.prototype.reduceRight - the exception is not thrown if exception
+# was thrown by step 3
+15.4.4.22-4-11: FAIL
+# Bug? Array.prototype.reduceRight - calling with no callbackfn is the same as
+# passing undefined for callbackfn
+15.4.4.22-4-15: FAIL
+# Bug? Array.prototype.reduceRight - element to be retrieved is own accessor
+# property that overrides an inherited data property on an Array
+15.4.4.22-8-b-iii-1-12: FAIL
+# Bug? Array.prototype.reduceRight - element to be retrieved is own accessor
+# property without a get function on an Array
+15.4.4.22-8-b-iii-1-18: FAIL
+# Bug? Array.prototype.reduceRight - element to be retrieved is own accessor
+# property without a get function that overrides an inherited accessor
+# property on an Array
+15.4.4.22-8-b-iii-1-20: FAIL
+# Bug? Array.prototype.reduceRight - element changed by getter on current
+# iteration is observed in subsequent iterations on an Array
+15.4.4.22-8-b-iii-1-30: FAIL
+# Bug? Array.prototype.reduceRight - Exception in getter terminate iteration on
+# an Array
+15.4.4.22-8-b-iii-1-33: FAIL
+# Bug? Array.prototype.reduceRight - modifications to length don't change number
+# of iterations in step 9
+15.4.4.22-8-b-2: FAIL
+# Bug? Array.prototype.reduceRight - deleting own property in step 8 causes
+# deleted index property not to be visited on an Array
+15.4.4.22-9-b-9: FAIL
+# Bug? Array.prototype.reduceRight - deleting own property with prototype
+# property in step 8 causes prototype index property to be visited on an
+# Array
+15.4.4.22-9-b-13: FAIL
+# Bug? Array.prototype.reduceRight - decreasing length of array in step 8 does
+# not delete non-configurable properties
+15.4.4.22-9-b-16: FAIL
+# Bug? Array.prototype.reduceRight - deleting property of prototype causes
+# deleted index property not to be visited on an Array
+15.4.4.22-9-b-24: FAIL
+# Bug? Array.prototype.reduceRight - deleting own property with prototype
+# property causes prototype index property to be visited on an Array
+15.4.4.22-9-b-26: FAIL
+# Bug? Array.prototype.reduceRight - decreasing length of array does not delete
+# non-configurable properties
+15.4.4.22-9-b-29: FAIL
+# Bug? Array.prototype.reduceRight - element changed by getter on previous
+# iterations is observed on an Array
+15.4.4.22-9-c-i-30: FAIL
+# Bug? Array.prototype.reduceRight - modifications to length will change number
+# of iterations
+15.4.4.22-9-9: FAIL
+# Bug? String.prototype.trim throws TypeError when string is undefined
+15.5.4.20-1-1: FAIL
+# Bug? String.prototype.trim throws TypeError when string is null
+15.5.4.20-1-2: FAIL
+# Bug? String.prototype.trim - 'S' is a string with all WhiteSpace
+15.5.4.20-3-2: FAIL
+# Bug? String.prototype.trim - 'S' is a string with all union of WhiteSpace and
+# LineTerminator
+15.5.4.20-3-3: FAIL
+# Bug? String.prototype.trim - 'S' is a string start with union of all
+# LineTerminator and all WhiteSpace
+15.5.4.20-3-4: FAIL
+# Bug? String.prototype.trim - 'S' is a string end with union of all
+# LineTerminator and all WhiteSpace
+15.5.4.20-3-5: FAIL
+# Bug? String.prototype.trim - 'S' is a string start with union of all
+# LineTerminator and all WhiteSpace and end with union of all
+# LineTerminator and all WhiteSpace
+15.5.4.20-3-6: FAIL
+# Bug? String.prototype.trim handles whitepace and lineterminators (\\uFEFFabc)
+15.5.4.20-4-10: FAIL
+# Bug? String.prototype.trim handles whitepace and lineterminators (abc\\uFEFF)
+15.5.4.20-4-18: FAIL
+# Bug? String.prototype.trim handles whitepace and lineterminators
+# (\\uFEFF\\uFEFF)
+15.5.4.20-4-34: FAIL
+# Bug? Date Time String Format - specified default values will be set for all
+# optional fields(MM, DD, mm, ss and time zone) when they are absent
+15.9.1.15-1: FAIL
+# Bug? Date.prototype.toISOString - RangeError is thrown when value of date is
+# Date(1970, 0, -99999999, 0, 0, 0, -1), the time zone is UTC(0)
+15.9.5.43-0-8: FAIL
+# Bug? Date.prototype.toISOString - RangeError is not thrown when value of date
+# is Date(1970, 0, 100000001, 0, 0, 0, -1), the time zone is UTC(0)
+15.9.5.43-0-11: FAIL
+# Bug? Date.prototype.toISOString - RangeError is not thrown when value of date
+# is Date(1970, 0, 100000001, 0, 0, 0, 0), the time zone is UTC(0)
+15.9.5.43-0-12: FAIL
+# Bug? Date.prototype.toISOString - RangeError is thrown when value of date is
+# Date(1970, 0, 100000001, 0, 0, 0, 1), the time zone is UTC(0)
+15.9.5.43-0-13: FAIL
+# Bug? Date.prototype.toISOString - when value of year is -Infinity
+# Date.prototype.toISOString throw the RangeError
+15.9.5.43-0-14: FAIL
+# Bug? Date.prototype.toISOString - value of year is Infinity
+# Date.prototype.toISOString throw the RangeError
+15.9.5.43-0-15: FAIL
+# Bug? RegExp - the thrown error is SyntaxError instead of RegExpError when 'F'
+# contains any character other than 'g', 'i', or 'm'
+15.10.4.1-3: FAIL
+# Bug? RegExp.prototype is itself a RegExp
+15.10.6: FAIL
+# Bug? RegExp.prototype.source is of type String
+15.10.7.1-1: FAIL
+# Bug? RegExp.prototype.source is a data property with default attribute values
+# (false)
+15.10.7.1-2: FAIL
+# Bug? RegExp.prototype.global is of type Boolean
+15.10.7.2-1: FAIL
+# Bug? RegExp.prototype.global is a data property with default attribute values
+# (false)
+15.10.7.2-2: FAIL
+# Bug? RegExp.prototype.ignoreCase is of type Boolean
+15.10.7.3-1: FAIL
+# Bug? RegExp.prototype.ignoreCase is a data property with default attribute
+# values (false)
+15.10.7.3-2: FAIL
+# Bug? RegExp.prototype.multiline is of type Boolean
+15.10.7.4-1: FAIL
+# Bug? RegExp.prototype.multiline is a data property with default attribute
+# values (false)
+15.10.7.4-2: FAIL
+# Bug? RegExp.prototype.lastIndex is of type Number
+15.10.7.5-1: FAIL
+# Bug? RegExp.prototype.lastIndex is a data property with specified attribute
+# values
+15.10.7.5-2: FAIL
+# Bug? Error.prototype.toString return the value of 'msg' when 'name' is empty
+# string and 'msg' isn't undefined
+15.11.4.4-8-1: FAIL
diff --git a/test/test262/testcfg.py b/test/test262/testcfg.py
new file mode 100644
index 00000000..aa1212e4
--- /dev/null
+++ b/test/test262/testcfg.py
@@ -0,0 +1,123 @@
+# Copyright 2011 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import test
+import os
+from os.path import join, exists
+
+
+TEST_262_HARNESS = ['sta.js']
+
+
+class Test262TestCase(test.TestCase):
+
+ def __init__(self, filename, path, context, root, mode, framework):
+ super(Test262TestCase, self).__init__(context, path, mode)
+ self.filename = filename
+ self.framework = framework
+ self.root = root
+
+ def IsNegative(self):
+ return self.filename.endswith('-n.js')
+
+ def GetLabel(self):
+ return "%s test262 %s %s" % (self.mode, self.GetGroup(), self.GetName())
+
+ def IsFailureOutput(self, output):
+ if output.exit_code != 0:
+ return True
+ return 'FAILED!' in output.stdout
+
+ def GetCommand(self):
+ result = self.context.GetVmCommand(self, self.mode)
+ result += ['-e', 'var window = this']
+ result += self.framework
+ result.append(self.filename)
+ return result
+
+ def GetName(self):
+ return self.path[-1]
+
+ def GetGroup(self):
+ return self.path[0]
+
+ def GetSource(self):
+ return open(self.filename).read()
+
+
+class Test262TestConfiguration(test.TestConfiguration):
+
+ def __init__(self, context, root):
+ super(Test262TestConfiguration, self).__init__(context, root)
+
+ def AddIETestCenter(self, tests, current_path, path, mode):
+ current_root = join(self.root, 'data', 'test', 'suite', 'ietestcenter')
+ harness = [join(self.root, 'data', 'test', 'harness', f)
+ for f in TEST_262_HARNESS]
+ harness += [join(self.root, 'harness-adapt.js')]
+ for root, dirs, files in os.walk(current_root):
+ for dotted in [x for x in dirs if x.startswith('.')]:
+ dirs.remove(dotted)
+ dirs.sort()
+ root_path = root[len(self.root):].split(os.path.sep)
+ root_path = current_path + [x for x in root_path if x]
+ files.sort()
+ for file in files:
+ if file.endswith('.js'):
+ if self.Contains(path, root_path):
+ test_path = ['ietestcenter', file[:-3]]
+ test = Test262TestCase(join(root, file), test_path, self.context,
+ self.root, mode, harness)
+ tests.append(test)
+
+ def AddSputnikConvertedTests(self, tests, current_path, path, mode):
+ # To be enabled
+ pass
+
+ def AddSputnikTests(self, tests, current_path, path, mode):
+ # To be enabled
+ pass
+
+ def ListTests(self, current_path, path, mode, variant_flags):
+ tests = []
+ self.AddIETestCenter(tests, current_path, path, mode)
+ self.AddSputnikConvertedTests(tests, current_path, path, mode)
+ self.AddSputnikTests(tests, current_path, path, mode)
+ return tests
+
+ def GetBuildRequirements(self):
+ return ['sample', 'sample=shell']
+
+ def GetTestStatus(self, sections, defs):
+ status_file = join(self.root, 'test262.status')
+ if exists(status_file):
+ test.ReadConfigurationInto(status_file, sections, defs)
+
+
+def GetConfiguration(context, root):
+ return Test262TestConfiguration(context, root)
diff --git a/tools/freebsd-tick-processor b/tools/freebsd-tick-processor
new file mode 100755
index 00000000..2bb2618b
--- /dev/null
+++ b/tools/freebsd-tick-processor
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# A wrapper script to call 'linux-tick-processor'.
+
+# Known issues on FreeBSD:
+# No ticks from C++ code.
+# You must have d8 built and in your path before calling this.
+
+tools_path=`cd $(dirname "$0");pwd`
+$tools_path/linux-tick-processor "$@"
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 6dab52d8..88044540 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -41,6 +41,7 @@
'ENABLE_LOGGING_AND_PROFILING',
'ENABLE_DEBUGGER_SUPPORT',
'ENABLE_VMSTATE_TRACKING',
+ 'V8_FAST_TLS',
],
'conditions': [
['OS!="mac"', {
@@ -211,38 +212,6 @@
},
},
{
- 'target_name': 'v8_preparser',
- 'include_dirs': [
- '../../include',
- '../../src',
- ],
- 'sources': [
- '../../src/allocation.cc',
- '../../src/hashmap.cc',
- '../../src/preparse-data.cc',
- '../../src/preparser.cc',
- '../../src/preparser-api.cc',
- '../../src/scanner-base.cc',
- '../../src/token.cc',
- '../../src/unicode.cc',
- ],
- 'conditions': [
- ['OS=="win" and component=="shared_library"', {
- 'sources': [ '../../src/v8preparserdll-main.cc' ],
- 'defines': [ 'BUILDING_V8_SHARED' ],
- 'direct_dependent_settings': {
- 'defines': [ 'USING_V8_SHARED' ]
- },
- 'type': '<(component)',
- } , {
- 'type': 'none'
- }],
- ['OS!="win"', {
- 'type': '<(library)'
- }],
- ]
- },
- {
'target_name': 'v8_snapshot',
'type': '<(library)',
'conditions': [
@@ -435,6 +404,8 @@
'../../src/jump-target.h',
'../../src/jsregexp.cc',
'../../src/jsregexp.h',
+ '../../src/isolate.cc',
+ '../../src/isolate.h',
'../../src/list-inl.h',
'../../src/list.h',
'../../src/lithium.cc',
@@ -455,7 +426,6 @@
'../../src/macro-assembler.h',
'../../src/mark-compact.cc',
'../../src/mark-compact.h',
- '../../src/memory.h',
'../../src/messages.cc',
'../../src/messages.h',
'../../src/natives.h',
@@ -468,6 +438,9 @@
'../../src/objects.h',
'../../src/parser.cc',
'../../src/parser.h',
+ '../../src/platform-tls-mac.h',
+ '../../src/platform-tls-win32.h',
+ '../../src/platform-tls.h',
'../../src/platform.h',
'../../src/preparse-data.cc',
'../../src/preparse-data.h',
@@ -511,6 +484,7 @@
'../../src/serialize.cc',
'../../src/serialize.h',
'../../src/shell.h',
+ '../../src/small-pointer-list.h',
'../../src/smart-pointer.h',
'../../src/snapshot-common.cc',
'../../src/snapshot.h',
@@ -544,6 +518,7 @@
'../../src/v8.h',
'../../src/v8checks.h',
'../../src/v8globals.h',
+ '../../src/v8memory.h',
'../../src/v8threads.cc',
'../../src/v8threads.h',
'../../src/v8utils.h',
diff --git a/tools/linux-tick-processor b/tools/linux-tick-processor
index 17157050..97896975 100755
--- a/tools/linux-tick-processor
+++ b/tools/linux-tick-processor
@@ -3,12 +3,12 @@
tools_path=`cd $(dirname "$0");pwd`
if [ ! "$D8_PATH" ]; then
d8_public=`which d8`
- if [ $d8_public ]; then D8_PATH=$(dirname "$d8_public"); fi
+ if [ -x $d8_public ]; then D8_PATH=$(dirname "$d8_public"); fi
fi
[ "$D8_PATH" ] || D8_PATH=$tools_path/..
d8_exec=$D8_PATH/d8
-if [ "$1" == "--no-build" ]; then
+if [ "$1" = "--no-build" ]; then
shift
else
# compile d8 if it doesn't exist, assuming this script
@@ -16,15 +16,17 @@ else
[ -x $d8_exec ] || scons -j4 -C $D8_PATH -Y $tools_path/.. d8
fi
+
# find the name of the log file to process, it must not start with a dash.
log_file="v8.log"
for arg in "$@"
do
- if [[ "${arg}" != -* ]]; then
+ if ! expr "X${arg}" : "^X-" > /dev/null; then
log_file=${arg}
fi
done
+
# nm spits out 'no symbols found' messages to stderr.
cat $log_file | $d8_exec $tools_path/splaytree.js $tools_path/codemap.js \
$tools_path/csvparser.js $tools_path/consarray.js \
diff --git a/tools/test.py b/tools/test.py
index 939ca0c4..066a5593 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -340,6 +340,9 @@ class TestCase(object):
def IsNegative(self):
return False
+ def TestsIsolates(self):
+ return False
+
def CompareTime(self, other):
return cmp(other.duration, self.duration)
@@ -371,6 +374,9 @@ class TestCase(object):
def AfterRun(self, result):
pass
+ def GetCustomFlags(self, mode):
+ return None
+
def Run(self):
self.BeforeRun()
try:
@@ -499,11 +505,19 @@ def PrintError(str):
def CheckedUnlink(name):
- try:
- os.unlink(name)
- except OSError, e:
- PrintError("os.unlink() " + str(e))
-
+ # On Windows, when run with -jN in parallel processes,
+ # OS often fails to unlink the temp file. Not sure why.
+ # Need to retry.
+ # Idea from https://bugs.webkit.org/attachment.cgi?id=75982&action=prettypatch
+ retry_count = 0
+ while retry_count < 30:
+ try:
+ os.unlink(name)
+ return
+ except OSError, e:
+ retry_count += 1;
+ time.sleep(retry_count * 0.1)
+ PrintError("os.unlink() " + str(e))
def Execute(args, context, timeout=None):
(fd_out, outname) = tempfile.mkstemp()
@@ -600,7 +614,7 @@ class TestRepository(TestSuite):
def AddTestsToList(self, result, current_path, path, context, mode):
for v in VARIANT_FLAGS:
- tests = self.GetConfiguration(context).ListTests(current_path, path, mode)
+ tests = self.GetConfiguration(context).ListTests(current_path, path, mode, v)
for t in tests: t.variant_flags = v
result += tests
@@ -623,7 +637,7 @@ class LiteralTestSuite(TestSuite):
result += test.GetBuildRequirements(rest, context)
return result
- def ListTests(self, current_path, path, context, mode):
+ def ListTests(self, current_path, path, context, mode, variant_flags):
(name, rest) = CarCdr(path)
result = [ ]
for test in self.tests:
@@ -671,7 +685,10 @@ class Context(object):
return [self.GetVm(mode)] + self.GetVmFlags(testcase, mode)
def GetVmFlags(self, testcase, mode):
- return testcase.variant_flags + FLAGS[mode]
+ flags = testcase.GetCustomFlags(mode)
+ if flags is None:
+ flags = FLAGS[mode]
+ return testcase.variant_flags + flags
def GetTimeout(self, testcase, mode):
result = self.timeout * TIMEOUT_SCALEFACTOR[mode]
@@ -1007,6 +1024,9 @@ class ClassifiedTest(object):
self.case = case
self.outcomes = outcomes
+ def TestsIsolates(self):
+ return self.case.TestsIsolates()
+
class Configuration(object):
"""The parsed contents of a configuration file"""
@@ -1166,6 +1186,7 @@ def BuildOptions():
result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests",
dest="suppress_dialogs", action="store_false")
result.add_option("--shell", help="Path to V8 shell", default="shell")
+ result.add_option("--isolates", help="Whether to test isolates", default=False, action="store_true")
result.add_option("--store-unexpected-output",
help="Store the temporary JS files from tests that fails",
dest="store_unexpected_output", default=True, action="store_true")
@@ -1398,7 +1419,7 @@ def Main():
'simulator': options.simulator,
'crankshaft': options.crankshaft
}
- test_list = root.ListTests([], path, context, mode)
+ test_list = root.ListTests([], path, context, mode, [])
unclassified_tests += test_list
(cases, unused_rules, all_outcomes) = config.ClassifyTests(test_list, env)
if globally_unused_rules is None:
@@ -1432,6 +1453,8 @@ def Main():
def DoSkip(case):
return SKIP in case.outcomes or SLOW in case.outcomes
cases_to_run = [ c for c in all_cases if not DoSkip(c) ]
+ if not options.isolates:
+ cases_to_run = [c for c in cases_to_run if not c.TestsIsolates()]
if len(cases_to_run) == 0:
print "No tests to run."
return 0
diff --git a/tools/tickprocessor.js b/tools/tickprocessor.js
index f105a21c..7a05ef1e 100644
--- a/tools/tickprocessor.js
+++ b/tools/tickprocessor.js
@@ -161,7 +161,9 @@ function TickProcessor(
processor: this.processFunctionMove },
'snapshot-pos': { parsers: [parseInt, parseInt],
processor: this.processSnapshotPosition },
- 'tick': { parsers: [parseInt, parseInt, parseInt, parseInt, 'var-args'],
+ 'tick': {
+ parsers: [parseInt, parseInt, parseInt,
+ parseInt, parseInt, 'var-args'],
processor: this.processTick },
'heap-sample-begin': { parsers: [null, null, parseInt],
processor: this.processHeapSampleBegin },
@@ -344,22 +346,33 @@ TickProcessor.prototype.includeTick = function(vmState) {
};
-TickProcessor.prototype.processTick = function(pc, sp, tos, vmState, stack) {
+TickProcessor.prototype.processTick = function(pc,
+ sp,
+ is_external_callback,
+ tos_or_external_callback,
+ vmState,
+ stack) {
this.ticks_.total++;
if (vmState == TickProcessor.VmStates.GC) this.ticks_.gc++;
if (!this.includeTick(vmState)) {
this.ticks_.excluded++;
return;
}
-
- if (tos) {
- var funcEntry = this.profile_.findEntry(tos);
+ if (is_external_callback) {
+ // Don't use PC when in external callback code, as it can point
+ // inside callback's code, and we will erroneously report
+ // that a callback calls itself.
+ pc = 0;
+ } else if (tos_or_external_callback) {
+ // Find out, if top of stack was pointing inside a JS function
+ // meaning that we have encountered a frameless invocation.
+ var funcEntry = this.profile_.findEntry(tos_or_external_callback);
if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction()) {
- tos = 0;
+ tos_or_external_callback = 0;
}
}
- this.profile_.recordTick(this.processStack(pc, tos, stack));
+ this.profile_.recordTick(this.processStack(pc, tos_or_external_callback, stack));
};
diff --git a/tools/v8.xcodeproj/project.pbxproj b/tools/v8.xcodeproj/project.pbxproj
index 10fbc58a..386e7f01 100644
--- a/tools/v8.xcodeproj/project.pbxproj
+++ b/tools/v8.xcodeproj/project.pbxproj
@@ -210,6 +210,9 @@
895692A412D4ED240072C313 /* gc-extension.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893E24DA12B14B9F0083370F /* gc-extension.cc */; };
895692A512D4ED240072C313 /* objects-printer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8946827412C26EB700C914BC /* objects-printer.cc */; };
8956B6CF0F5D86730033B5A2 /* debug-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8956B6CD0F5D86570033B5A2 /* debug-agent.cc */; };
+ 895D5B531334212D00254083 /* isolate.cc in Sources */ = {isa = PBXBuildFile; fileRef = 895D5B521334212D00254083 /* isolate.cc */; };
+ 895D5B541334212D00254083 /* isolate.cc in Sources */ = {isa = PBXBuildFile; fileRef = 895D5B521334212D00254083 /* isolate.cc */; };
+ 895D5B551334212D00254083 /* isolate.cc in Sources */ = {isa = PBXBuildFile; fileRef = 895D5B521334212D00254083 /* isolate.cc */; };
895FA753107FFED3006F39D4 /* constants-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 895FA748107FFE73006F39D4 /* constants-arm.cc */; };
896FA1E5130F93D300042054 /* lithium-gap-resolver-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 896FA1E3130F93D300042054 /* lithium-gap-resolver-arm.cc */; };
896FD03A0E78D717003DFB6A /* libv8-arm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89F23C870E78D5B2006B2466 /* libv8-arm.a */; };
@@ -562,6 +565,8 @@
58950D5A0F55514900F3E8BA /* virtual-frame.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "virtual-frame.cc"; sourceTree = "<group>"; };
58950D5B0F55514900F3E8BA /* virtual-frame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "virtual-frame.h"; sourceTree = "<group>"; };
8900116B0E71CA2300F91F35 /* libraries.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libraries.cc; sourceTree = "<group>"; };
+ 891C92FD1334226000FF4757 /* lithium-allocator-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "lithium-allocator-inl.h"; sourceTree = "<group>"; };
+ 891C92FE133422EB00FF4757 /* isolate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = isolate.h; sourceTree = "<group>"; };
8924315A12F8539900906AB2 /* lithium-gap-resolver-x64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lithium-gap-resolver-x64.cc"; path = "x64/lithium-gap-resolver-x64.cc"; sourceTree = "<group>"; };
8924315B12F8539900906AB2 /* lithium-gap-resolver-x64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lithium-gap-resolver-x64.h"; path = "x64/lithium-gap-resolver-x64.h"; sourceTree = "<group>"; };
8938A2A212D63B630080CDDE /* lithium-x64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lithium-x64.cc"; path = "x64/lithium-x64.cc"; sourceTree = "<group>"; };
@@ -638,6 +643,8 @@
895692AA12D4ED240072C313 /* libv8-x64.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libv8-x64.a"; sourceTree = BUILT_PRODUCTS_DIR; };
8956B6CD0F5D86570033B5A2 /* debug-agent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "debug-agent.cc"; sourceTree = "<group>"; };
8956B6CE0F5D86570033B5A2 /* debug-agent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "debug-agent.h"; sourceTree = "<group>"; };
+ 895D5B4C1334210400254083 /* allocation-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "allocation-inl.h"; sourceTree = "<group>"; };
+ 895D5B521334212D00254083 /* isolate.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = isolate.cc; sourceTree = "<group>"; };
895FA720107FFB15006F39D4 /* jump-target-heavy-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "jump-target-heavy-inl.h"; sourceTree = "<group>"; };
895FA725107FFB57006F39D4 /* codegen-ia32-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "codegen-ia32-inl.h"; path = "ia32/codegen-ia32-inl.h"; sourceTree = "<group>"; };
895FA72A107FFB85006F39D4 /* register-allocator-ia32-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "register-allocator-ia32-inl.h"; path = "ia32/register-allocator-ia32-inl.h"; sourceTree = "<group>"; };
@@ -754,7 +761,7 @@
897FF1580E719B8F00D62E90 /* macro-assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "macro-assembler.h"; sourceTree = "<group>"; };
897FF1590E719B8F00D62E90 /* mark-compact.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "mark-compact.cc"; sourceTree = "<group>"; };
897FF15A0E719B8F00D62E90 /* mark-compact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mark-compact.h"; sourceTree = "<group>"; };
- 897FF15B0E719B8F00D62E90 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = "<group>"; };
+ 897FF15B0E719B8F00D62E90 /* v8memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v8memory.h; sourceTree = "<group>"; };
897FF15C0E719B8F00D62E90 /* messages.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = messages.cc; sourceTree = "<group>"; };
897FF15D0E719B8F00D62E90 /* messages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = messages.h; sourceTree = "<group>"; };
897FF15E0E719B8F00D62E90 /* mksnapshot.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mksnapshot.cc; sourceTree = "<group>"; };
@@ -907,6 +914,9 @@
89F3605A12DCDF6400ACF8A6 /* lithium-codegen-x64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lithium-codegen-x64.cc"; path = "x64/lithium-codegen-x64.cc"; sourceTree = "<group>"; };
89FB0E360F8E531900B04B3C /* d8-posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-posix.cc"; path = "../src/d8-posix.cc"; sourceTree = "<group>"; };
89FB0E370F8E531900B04B3C /* d8-windows.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-windows.cc"; path = "../src/d8-windows.cc"; sourceTree = "<group>"; };
+ 9C1F8E1D133906180068B362 /* small-pointer-list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "small-pointer-list.h"; sourceTree = "<group>"; };
+ 9C76176D133FB7740057370B /* platform-tls-mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "platform-tls-mac.h"; sourceTree = "<group>"; };
+ 9C8E8061133CF772004058A5 /* platform-tls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "platform-tls.h"; sourceTree = "<group>"; };
9F11D99E105AF0A300EBE5B2 /* heap-profiler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "heap-profiler.cc"; sourceTree = "<group>"; };
9F11D99F105AF0A300EBE5B2 /* heap-profiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "heap-profiler.h"; sourceTree = "<group>"; };
9F2B370E114FF62D007CDAF4 /* circular-queue-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "circular-queue-inl.h"; sourceTree = "<group>"; };
@@ -1055,6 +1065,7 @@
89B91B7A12D4EF65002FF4BC /* x64 */,
897FF0F60E719B8F00D62E90 /* accessors.cc */,
897FF0F70E719B8F00D62E90 /* accessors.h */,
+ 895D5B4C1334210400254083 /* allocation-inl.h */,
897FF0F80E719B8F00D62E90 /* allocation.cc */,
897FF0F90E719B8F00D62E90 /* allocation.h */,
897FF0FA0E719B8F00D62E90 /* api.cc */,
@@ -1180,6 +1191,8 @@
89D7DDD912E8DE09001E2B82 /* inspector.h */,
89A15C660EE4665300B48DEB /* interpreter-irregexp.cc */,
89A15C670EE4665300B48DEB /* interpreter-irregexp.h */,
+ 895D5B521334212D00254083 /* isolate.cc */,
+ 891C92FE133422EB00FF4757 /* isolate.h */,
897FF14E0E719B8F00D62E90 /* jsregexp.cc */,
897FF14F0E719B8F00D62E90 /* jsregexp.h */,
895FA720107FFB15006F39D4 /* jump-target-heavy-inl.h */,
@@ -1193,6 +1206,7 @@
58950D510F55514900F3E8BA /* jump-target.h */,
897FF1500E719B8F00D62E90 /* list-inl.h */,
897FF1510E719B8F00D62E90 /* list.h */,
+ 891C92FD1334226000FF4757 /* lithium-allocator-inl.h */,
893E249312B14B3D0083370F /* lithium-allocator.cc */,
893E249412B14B3D0083370F /* lithium-allocator.h */,
894A59E712D777E80000766D /* lithium.cc */,
@@ -1207,7 +1221,7 @@
897FF1580E719B8F00D62E90 /* macro-assembler.h */,
897FF1590E719B8F00D62E90 /* mark-compact.cc */,
897FF15A0E719B8F00D62E90 /* mark-compact.h */,
- 897FF15B0E719B8F00D62E90 /* memory.h */,
+ 897FF15B0E719B8F00D62E90 /* v8memory.h */,
897FF15C0E719B8F00D62E90 /* messages.cc */,
897FF15D0E719B8F00D62E90 /* messages.h */,
897FF15E0E719B8F00D62E90 /* mksnapshot.cc */,
@@ -1226,6 +1240,8 @@
897FF1670E719B8F00D62E90 /* platform-macos.cc */,
897FF1680E719B8F00D62E90 /* platform-nullos.cc */,
893A72230F7B0FF200303DD2 /* platform-posix.cc */,
+ 9C76176D133FB7740057370B /* platform-tls-mac.h */,
+ 9C8E8061133CF772004058A5 /* platform-tls.h */,
897FF1690E719B8F00D62E90 /* platform-win32.cc */,
897FF16A0E719B8F00D62E90 /* platform.h */,
893E249512B14B3D0083370F /* preparse-data.cc */,
@@ -1272,6 +1288,7 @@
897FF17B0E719B8F00D62E90 /* serialize.h */,
897FF17C0E719B8F00D62E90 /* shell.h */,
893E24A012B14B3D0083370F /* simulator.h */,
+ 9C1F8E1D133906180068B362 /* small-pointer-list.h */,
897FF1810E719B8F00D62E90 /* smart-pointer.h */,
897FF1820E719B8F00D62E90 /* snapshot-common.cc */,
897FF1830E719B8F00D62E90 /* snapshot-empty.cc */,
@@ -1982,6 +1999,7 @@
89D7DDDE12E8DE09001E2B82 /* gdb-jit.cc in Sources */,
89D7DDDF12E8DE09001E2B82 /* inspector.cc in Sources */,
8924315C12F8539900906AB2 /* lithium-gap-resolver-x64.cc in Sources */,
+ 895D5B551334212D00254083 /* isolate.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2119,6 +2137,7 @@
89D7DDD512E8DDCF001E2B82 /* lithium-gap-resolver-ia32.cc in Sources */,
89D7DDDA12E8DE09001E2B82 /* gdb-jit.cc in Sources */,
89D7DDDB12E8DE09001E2B82 /* inspector.cc in Sources */,
+ 895D5B531334212D00254083 /* isolate.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2296,6 +2315,7 @@
89D7DDDC12E8DE09001E2B82 /* gdb-jit.cc in Sources */,
89D7DDDD12E8DE09001E2B82 /* inspector.cc in Sources */,
896FA1E5130F93D300042054 /* lithium-gap-resolver-arm.cc in Sources */,
+ 895D5B541334212D00254083 /* isolate.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/tools/visual_studio/v8_base.vcproj b/tools/visual_studio/v8_base.vcproj
index 5f76069d..a005f7a3 100644
--- a/tools/visual_studio/v8_base.vcproj
+++ b/tools/visual_studio/v8_base.vcproj
@@ -781,7 +781,7 @@
>
</File>
<File
- RelativePath="..\..\src\memory.h"
+ RelativePath="..\..\src\v8memory.h"
>
</File>
<File
@@ -870,6 +870,14 @@
>
</File>
<File
+ RelativePath="..\..\src\platform-tls-win32.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\platform-tls.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\platform-win32.cc"
>
</File>
@@ -1026,6 +1034,10 @@
>
</File>
<File
+ RelativePath="..\..\src\small-pointer-list.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\snapshot-common.cc"
>
</File>
diff --git a/tools/visual_studio/v8_base_arm.vcproj b/tools/visual_studio/v8_base_arm.vcproj
index feb7e6c6..87c178ab 100644
--- a/tools/visual_studio/v8_base_arm.vcproj
+++ b/tools/visual_studio/v8_base_arm.vcproj
@@ -765,7 +765,7 @@
>
</File>
<File
- RelativePath="..\..\src\memory.h"
+ RelativePath="..\..\src\v8memory.h"
>
</File>
<File
@@ -984,6 +984,10 @@
>
</File>
<File
+ RelativePath="..\..\src\small-pointer-list.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\snapshot-common.cc"
>
</File>
diff --git a/tools/visual_studio/v8_base_x64.vcproj b/tools/visual_studio/v8_base_x64.vcproj
index 14ed77e0..de921bc9 100644
--- a/tools/visual_studio/v8_base_x64.vcproj
+++ b/tools/visual_studio/v8_base_x64.vcproj
@@ -782,7 +782,7 @@
>
</File>
<File
- RelativePath="..\..\src\memory.h"
+ RelativePath="..\..\src\v8memory.h"
>
</File>
<File
@@ -1026,6 +1026,10 @@
>
</File>
<File
+ RelativePath="..\..\src\small-pointer-list.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\snapshot-common.cc"
>
</File>