libv8 3.3.10.4 → 3.5.10.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/libv8/scons/CHANGES.txt +24 -231
- data/lib/libv8/scons/LICENSE.txt +1 -1
- data/lib/libv8/scons/MANIFEST +0 -1
- data/lib/libv8/scons/PKG-INFO +1 -1
- data/lib/libv8/scons/README.txt +9 -9
- data/lib/libv8/scons/RELEASE.txt +75 -77
- data/lib/libv8/scons/engine/SCons/Action.py +6 -22
- data/lib/libv8/scons/engine/SCons/Builder.py +2 -2
- data/lib/libv8/scons/engine/SCons/CacheDir.py +2 -2
- data/lib/libv8/scons/engine/SCons/Debug.py +2 -2
- data/lib/libv8/scons/engine/SCons/Defaults.py +10 -24
- data/lib/libv8/scons/engine/SCons/Environment.py +19 -118
- data/lib/libv8/scons/engine/SCons/Errors.py +2 -2
- data/lib/libv8/scons/engine/SCons/Executor.py +2 -2
- data/lib/libv8/scons/engine/SCons/Job.py +2 -2
- data/lib/libv8/scons/engine/SCons/Memoize.py +2 -2
- data/lib/libv8/scons/engine/SCons/Node/Alias.py +2 -2
- data/lib/libv8/scons/engine/SCons/Node/FS.py +121 -281
- data/lib/libv8/scons/engine/SCons/Node/Python.py +2 -2
- data/lib/libv8/scons/engine/SCons/Node/__init__.py +5 -6
- data/lib/libv8/scons/engine/SCons/Options/BoolOption.py +2 -2
- data/lib/libv8/scons/engine/SCons/Options/EnumOption.py +2 -2
- data/lib/libv8/scons/engine/SCons/Options/ListOption.py +2 -2
- data/lib/libv8/scons/engine/SCons/Options/PackageOption.py +2 -2
- data/lib/libv8/scons/engine/SCons/Options/PathOption.py +2 -2
- data/lib/libv8/scons/engine/SCons/Options/__init__.py +2 -2
- data/lib/libv8/scons/engine/SCons/PathList.py +2 -2
- data/lib/libv8/scons/engine/SCons/Platform/__init__.py +2 -2
- data/lib/libv8/scons/engine/SCons/Platform/aix.py +2 -2
- data/lib/libv8/scons/engine/SCons/Platform/cygwin.py +2 -2
- data/lib/libv8/scons/engine/SCons/Platform/darwin.py +3 -27
- data/lib/libv8/scons/engine/SCons/Platform/hpux.py +2 -2
- data/lib/libv8/scons/engine/SCons/Platform/irix.py +2 -2
- data/lib/libv8/scons/engine/SCons/Platform/os2.py +2 -2
- data/lib/libv8/scons/engine/SCons/Platform/posix.py +2 -2
- data/lib/libv8/scons/engine/SCons/Platform/sunos.py +2 -2
- data/lib/libv8/scons/engine/SCons/Platform/win32.py +2 -2
- data/lib/libv8/scons/engine/SCons/SConf.py +2 -2
- data/lib/libv8/scons/engine/SCons/SConsign.py +3 -9
- data/lib/libv8/scons/engine/SCons/Scanner/C.py +2 -2
- data/lib/libv8/scons/engine/SCons/Scanner/D.py +2 -2
- data/lib/libv8/scons/engine/SCons/Scanner/Dir.py +2 -2
- data/lib/libv8/scons/engine/SCons/Scanner/Fortran.py +2 -2
- data/lib/libv8/scons/engine/SCons/Scanner/IDL.py +2 -2
- data/lib/libv8/scons/engine/SCons/Scanner/LaTeX.py +2 -5
- data/lib/libv8/scons/engine/SCons/Scanner/Prog.py +2 -2
- data/lib/libv8/scons/engine/SCons/Scanner/RC.py +3 -3
- data/lib/libv8/scons/engine/SCons/Scanner/__init__.py +2 -2
- data/lib/libv8/scons/engine/SCons/Script/Interactive.py +2 -2
- data/lib/libv8/scons/engine/SCons/Script/Main.py +11 -82
- data/lib/libv8/scons/engine/SCons/Script/SConsOptions.py +5 -5
- data/lib/libv8/scons/engine/SCons/Script/SConscript.py +2 -2
- data/lib/libv8/scons/engine/SCons/Script/__init__.py +2 -2
- data/lib/libv8/scons/engine/SCons/Sig.py +2 -2
- data/lib/libv8/scons/engine/SCons/Subst.py +2 -2
- data/lib/libv8/scons/engine/SCons/Taskmaster.py +2 -10
- data/lib/libv8/scons/engine/SCons/Tool/386asm.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/BitKeeper.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/CVS.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/FortranCommon.py +2 -19
- data/lib/libv8/scons/engine/SCons/Tool/JavaCommon.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/MSCommon/__init__.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/MSCommon/arch.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/MSCommon/common.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/MSCommon/netframework.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/MSCommon/sdk.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/MSCommon/vc.py +6 -9
- data/lib/libv8/scons/engine/SCons/Tool/MSCommon/vs.py +2 -29
- data/lib/libv8/scons/engine/SCons/Tool/Perforce.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/PharLapCommon.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/RCS.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/SCCS.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/Subversion.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/__init__.py +3 -3
- data/lib/libv8/scons/engine/SCons/Tool/aixc++.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/aixcc.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/aixf77.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/aixlink.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/applelink.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/ar.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/as.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/bcc32.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/c++.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/cc.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/cvf.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/default.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/dmd.py +7 -24
- data/lib/libv8/scons/engine/SCons/Tool/dvi.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/dvipdf.py +2 -3
- data/lib/libv8/scons/engine/SCons/Tool/dvips.py +2 -3
- data/lib/libv8/scons/engine/SCons/Tool/f77.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/f90.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/f95.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/filesystem.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/fortran.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/g++.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/g77.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/gas.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/gcc.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/gfortran.py +3 -3
- data/lib/libv8/scons/engine/SCons/Tool/gnulink.py +3 -2
- data/lib/libv8/scons/engine/SCons/Tool/gs.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/hpc++.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/hpcc.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/hplink.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/icc.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/icl.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/ifl.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/ifort.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/ilink.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/ilink32.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/install.py +3 -57
- data/lib/libv8/scons/engine/SCons/Tool/intelc.py +25 -65
- data/lib/libv8/scons/engine/SCons/Tool/ipkg.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/jar.py +3 -9
- data/lib/libv8/scons/engine/SCons/Tool/javac.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/javah.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/latex.py +2 -3
- data/lib/libv8/scons/engine/SCons/Tool/lex.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/link.py +5 -6
- data/lib/libv8/scons/engine/SCons/Tool/linkloc.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/m4.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/masm.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/midl.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/mingw.py +10 -31
- data/lib/libv8/scons/engine/SCons/Tool/mslib.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/mslink.py +9 -61
- data/lib/libv8/scons/engine/SCons/Tool/mssdk.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/msvc.py +11 -21
- data/lib/libv8/scons/engine/SCons/Tool/msvs.py +59 -477
- data/lib/libv8/scons/engine/SCons/Tool/mwcc.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/mwld.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/nasm.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/__init__.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/ipk.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/msi.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/rpm.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/src_tarbz2.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/src_targz.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/src_zip.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/tarbz2.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/targz.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/packaging/zip.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/pdf.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/pdflatex.py +2 -3
- data/lib/libv8/scons/engine/SCons/Tool/pdftex.py +2 -3
- data/lib/libv8/scons/engine/SCons/Tool/qt.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/rmic.py +3 -9
- data/lib/libv8/scons/engine/SCons/Tool/rpcgen.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/rpm.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/sgiar.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/sgic++.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/sgicc.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/sgilink.py +3 -2
- data/lib/libv8/scons/engine/SCons/Tool/sunar.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/sunc++.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/suncc.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/sunf77.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/sunf90.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/sunf95.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/sunlink.py +3 -2
- data/lib/libv8/scons/engine/SCons/Tool/swig.py +5 -6
- data/lib/libv8/scons/engine/SCons/Tool/tar.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/tex.py +43 -96
- data/lib/libv8/scons/engine/SCons/Tool/textfile.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/tlib.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/wix.py +2 -2
- data/lib/libv8/scons/engine/SCons/Tool/yacc.py +2 -12
- data/lib/libv8/scons/engine/SCons/Tool/zip.py +2 -2
- data/lib/libv8/scons/engine/SCons/Util.py +3 -3
- data/lib/libv8/scons/engine/SCons/Variables/BoolVariable.py +2 -2
- data/lib/libv8/scons/engine/SCons/Variables/EnumVariable.py +3 -3
- data/lib/libv8/scons/engine/SCons/Variables/ListVariable.py +2 -2
- data/lib/libv8/scons/engine/SCons/Variables/PackageVariable.py +2 -2
- data/lib/libv8/scons/engine/SCons/Variables/PathVariable.py +2 -2
- data/lib/libv8/scons/engine/SCons/Variables/__init__.py +2 -2
- data/lib/libv8/scons/engine/SCons/Warnings.py +2 -2
- data/lib/libv8/scons/engine/SCons/__init__.py +6 -6
- data/lib/libv8/scons/engine/SCons/compat/__init__.py +2 -2
- data/lib/libv8/scons/engine/SCons/compat/_scons_builtins.py +2 -2
- data/lib/libv8/scons/engine/SCons/compat/_scons_collections.py +2 -2
- data/lib/libv8/scons/engine/SCons/compat/_scons_dbm.py +2 -2
- data/lib/libv8/scons/engine/SCons/compat/_scons_hashlib.py +2 -2
- data/lib/libv8/scons/engine/SCons/compat/_scons_io.py +2 -2
- data/lib/libv8/scons/engine/SCons/cpp.py +2 -2
- data/lib/libv8/scons/engine/SCons/dblite.py +1 -4
- data/lib/libv8/scons/engine/SCons/exitfuncs.py +2 -2
- data/lib/libv8/scons/scons-time.1 +3 -3
- data/lib/libv8/scons/scons.1 +1164 -1170
- data/lib/libv8/scons/sconsign.1 +3 -3
- data/lib/libv8/scons/script/scons +22 -22
- data/lib/libv8/scons/script/scons-time +2 -2
- data/lib/libv8/scons/script/scons.bat +4 -7
- data/lib/libv8/scons/script/sconsign +20 -21
- data/lib/libv8/scons/setup.cfg +1 -0
- data/lib/libv8/scons/setup.py +40 -38
- data/lib/libv8/v8/.gitignore +1 -1
- data/lib/libv8/v8/AUTHORS +2 -0
- data/lib/libv8/v8/ChangeLog +387 -0
- data/lib/libv8/v8/Makefile +171 -0
- data/lib/libv8/v8/SConstruct +124 -51
- data/lib/libv8/v8/build/README.txt +31 -14
- data/lib/libv8/v8/build/all.gyp +11 -4
- data/lib/libv8/v8/build/armu.gypi +6 -2
- data/lib/libv8/v8/build/common.gypi +240 -94
- data/lib/libv8/v8/build/gyp_v8 +32 -4
- data/lib/libv8/v8/build/standalone.gypi +200 -0
- data/lib/libv8/v8/include/v8-debug.h +0 -0
- data/lib/libv8/v8/include/v8-profiler.h +8 -11
- data/lib/libv8/v8/include/v8.h +191 -108
- data/lib/libv8/v8/preparser/SConscript +2 -2
- data/lib/libv8/v8/preparser/preparser-process.cc +3 -3
- data/lib/libv8/v8/preparser/preparser.gyp +42 -0
- data/lib/libv8/v8/src/SConscript +33 -8
- data/lib/libv8/v8/src/accessors.cc +77 -43
- data/lib/libv8/v8/src/api.cc +393 -191
- data/lib/libv8/v8/src/api.h +4 -8
- data/lib/libv8/v8/src/apinatives.js +15 -3
- data/lib/libv8/v8/src/arguments.h +8 -0
- data/lib/libv8/v8/src/arm/assembler-arm.cc +120 -120
- data/lib/libv8/v8/src/arm/assembler-arm.h +92 -43
- data/lib/libv8/v8/src/arm/builtins-arm.cc +32 -39
- data/lib/libv8/v8/src/arm/code-stubs-arm.cc +572 -351
- data/lib/libv8/v8/src/arm/code-stubs-arm.h +8 -77
- data/lib/libv8/v8/src/arm/codegen-arm.h +0 -2
- data/lib/libv8/v8/src/arm/deoptimizer-arm.cc +50 -30
- data/lib/libv8/v8/src/arm/disasm-arm.cc +1 -1
- data/lib/libv8/v8/src/arm/frames-arm.h +9 -5
- data/lib/libv8/v8/src/arm/full-codegen-arm.cc +331 -432
- data/lib/libv8/v8/src/arm/ic-arm.cc +192 -124
- data/lib/libv8/v8/src/arm/lithium-arm.cc +216 -232
- data/lib/libv8/v8/src/arm/lithium-arm.h +106 -259
- data/lib/libv8/v8/src/arm/lithium-codegen-arm.cc +633 -642
- data/lib/libv8/v8/src/arm/lithium-codegen-arm.h +4 -4
- data/lib/libv8/v8/src/arm/lithium-gap-resolver-arm.cc +1 -3
- data/lib/libv8/v8/src/arm/macro-assembler-arm.cc +260 -185
- data/lib/libv8/v8/src/arm/macro-assembler-arm.h +45 -25
- data/lib/libv8/v8/src/arm/regexp-macro-assembler-arm.cc +25 -13
- data/lib/libv8/v8/src/arm/regexp-macro-assembler-arm.h +3 -0
- data/lib/libv8/v8/src/arm/stub-cache-arm.cc +413 -226
- data/lib/libv8/v8/src/array.js +38 -18
- data/lib/libv8/v8/src/assembler.cc +12 -5
- data/lib/libv8/v8/src/assembler.h +15 -9
- data/lib/libv8/v8/src/ast-inl.h +34 -25
- data/lib/libv8/v8/src/ast.cc +141 -72
- data/lib/libv8/v8/src/ast.h +255 -181
- data/lib/libv8/v8/src/bignum.cc +3 -4
- data/lib/libv8/v8/src/bootstrapper.cc +55 -11
- data/lib/libv8/v8/src/bootstrapper.h +3 -2
- data/lib/libv8/v8/src/builtins.cc +8 -2
- data/lib/libv8/v8/src/builtins.h +4 -0
- data/lib/libv8/v8/src/cached-powers.cc +8 -4
- data/lib/libv8/v8/src/checks.h +3 -3
- data/lib/libv8/v8/src/code-stubs.cc +173 -28
- data/lib/libv8/v8/src/code-stubs.h +104 -148
- data/lib/libv8/v8/src/codegen.cc +8 -8
- data/lib/libv8/v8/src/compilation-cache.cc +2 -47
- data/lib/libv8/v8/src/compilation-cache.h +0 -10
- data/lib/libv8/v8/src/compiler.cc +27 -16
- data/lib/libv8/v8/src/compiler.h +13 -18
- data/lib/libv8/v8/src/contexts.cc +107 -72
- data/lib/libv8/v8/src/contexts.h +70 -34
- data/lib/libv8/v8/src/conversions-inl.h +572 -14
- data/lib/libv8/v8/src/conversions.cc +9 -707
- data/lib/libv8/v8/src/conversions.h +23 -12
- data/lib/libv8/v8/src/cpu-profiler-inl.h +2 -19
- data/lib/libv8/v8/src/cpu-profiler.cc +4 -21
- data/lib/libv8/v8/src/cpu-profiler.h +8 -17
- data/lib/libv8/v8/src/d8-debug.cc +5 -3
- data/lib/libv8/v8/src/d8-debug.h +6 -7
- data/lib/libv8/v8/src/d8-posix.cc +1 -10
- data/lib/libv8/v8/src/d8.cc +721 -219
- data/lib/libv8/v8/src/d8.gyp +37 -12
- data/lib/libv8/v8/src/d8.h +141 -19
- data/lib/libv8/v8/src/d8.js +17 -8
- data/lib/libv8/v8/src/date.js +16 -5
- data/lib/libv8/v8/src/dateparser-inl.h +242 -39
- data/lib/libv8/v8/src/dateparser.cc +38 -4
- data/lib/libv8/v8/src/dateparser.h +170 -28
- data/lib/libv8/v8/src/debug-agent.cc +5 -3
- data/lib/libv8/v8/src/debug-agent.h +11 -7
- data/lib/libv8/v8/src/debug-debugger.js +65 -34
- data/lib/libv8/v8/src/debug.cc +30 -60
- data/lib/libv8/v8/src/debug.h +5 -3
- data/lib/libv8/v8/src/deoptimizer.cc +227 -10
- data/lib/libv8/v8/src/deoptimizer.h +133 -9
- data/lib/libv8/v8/src/disassembler.cc +22 -14
- data/lib/libv8/v8/src/diy-fp.cc +4 -3
- data/lib/libv8/v8/src/diy-fp.h +3 -3
- data/lib/libv8/v8/src/elements.cc +634 -0
- data/lib/libv8/v8/src/elements.h +95 -0
- data/lib/libv8/v8/src/execution.cc +5 -21
- data/lib/libv8/v8/src/extensions/experimental/break-iterator.cc +3 -1
- data/lib/libv8/v8/src/extensions/experimental/break-iterator.h +1 -1
- data/lib/libv8/v8/src/extensions/experimental/collator.cc +6 -2
- data/lib/libv8/v8/src/extensions/experimental/collator.h +1 -2
- data/lib/libv8/v8/src/extensions/experimental/datetime-format.cc +384 -0
- data/lib/libv8/v8/src/extensions/experimental/datetime-format.h +83 -0
- data/lib/libv8/v8/src/extensions/experimental/experimental.gyp +18 -7
- data/lib/libv8/v8/src/extensions/experimental/i18n-extension.cc +12 -16
- data/lib/libv8/v8/src/extensions/experimental/i18n-extension.h +1 -1
- data/lib/libv8/v8/src/extensions/experimental/i18n-js2c.py +126 -0
- data/lib/libv8/v8/src/extensions/experimental/i18n-locale.cc +3 -4
- data/lib/libv8/v8/src/extensions/experimental/i18n-locale.h +1 -1
- data/lib/libv8/v8/src/{shell.h → extensions/experimental/i18n-natives.h} +8 -20
- data/lib/libv8/v8/src/extensions/experimental/i18n-utils.cc +45 -1
- data/lib/libv8/v8/src/extensions/experimental/i18n-utils.h +21 -1
- data/lib/libv8/v8/src/extensions/experimental/i18n.js +211 -11
- data/lib/libv8/v8/src/extensions/experimental/language-matcher.cc +4 -3
- data/lib/libv8/v8/src/extensions/experimental/language-matcher.h +1 -1
- data/lib/libv8/v8/src/extensions/experimental/number-format.cc +374 -0
- data/lib/libv8/v8/src/extensions/experimental/number-format.h +71 -0
- data/lib/libv8/v8/src/factory.cc +89 -18
- data/lib/libv8/v8/src/factory.h +36 -8
- data/lib/libv8/v8/src/flag-definitions.h +11 -44
- data/lib/libv8/v8/src/frames-inl.h +8 -1
- data/lib/libv8/v8/src/frames.cc +39 -3
- data/lib/libv8/v8/src/frames.h +10 -3
- data/lib/libv8/v8/src/full-codegen.cc +311 -293
- data/lib/libv8/v8/src/full-codegen.h +183 -143
- data/lib/libv8/v8/src/func-name-inferrer.cc +29 -15
- data/lib/libv8/v8/src/func-name-inferrer.h +19 -9
- data/lib/libv8/v8/src/gdb-jit.cc +658 -55
- data/lib/libv8/v8/src/gdb-jit.h +6 -2
- data/lib/libv8/v8/src/global-handles.cc +368 -312
- data/lib/libv8/v8/src/global-handles.h +29 -36
- data/lib/libv8/v8/src/globals.h +3 -1
- data/lib/libv8/v8/src/handles.cc +43 -69
- data/lib/libv8/v8/src/handles.h +21 -16
- data/lib/libv8/v8/src/heap-inl.h +11 -13
- data/lib/libv8/v8/src/heap-profiler.cc +0 -999
- data/lib/libv8/v8/src/heap-profiler.h +0 -303
- data/lib/libv8/v8/src/heap.cc +366 -141
- data/lib/libv8/v8/src/heap.h +87 -26
- data/lib/libv8/v8/src/hydrogen-instructions.cc +192 -81
- data/lib/libv8/v8/src/hydrogen-instructions.h +711 -482
- data/lib/libv8/v8/src/hydrogen.cc +1146 -629
- data/lib/libv8/v8/src/hydrogen.h +100 -64
- data/lib/libv8/v8/src/ia32/assembler-ia32.cc +19 -0
- data/lib/libv8/v8/src/ia32/assembler-ia32.h +15 -2
- data/lib/libv8/v8/src/ia32/builtins-ia32.cc +34 -39
- data/lib/libv8/v8/src/ia32/code-stubs-ia32.cc +675 -377
- data/lib/libv8/v8/src/ia32/code-stubs-ia32.h +8 -69
- data/lib/libv8/v8/src/ia32/codegen-ia32.cc +1 -0
- data/lib/libv8/v8/src/ia32/codegen-ia32.h +0 -2
- data/lib/libv8/v8/src/ia32/cpu-ia32.cc +3 -2
- data/lib/libv8/v8/src/ia32/deoptimizer-ia32.cc +28 -3
- data/lib/libv8/v8/src/ia32/disasm-ia32.cc +21 -10
- data/lib/libv8/v8/src/ia32/frames-ia32.h +6 -5
- data/lib/libv8/v8/src/ia32/full-codegen-ia32.cc +459 -465
- data/lib/libv8/v8/src/ia32/ic-ia32.cc +196 -147
- data/lib/libv8/v8/src/ia32/lithium-codegen-ia32.cc +575 -650
- data/lib/libv8/v8/src/ia32/lithium-codegen-ia32.h +19 -21
- data/lib/libv8/v8/src/ia32/lithium-gap-resolver-ia32.cc +7 -2
- data/lib/libv8/v8/src/ia32/lithium-ia32.cc +261 -256
- data/lib/libv8/v8/src/ia32/lithium-ia32.h +234 -335
- data/lib/libv8/v8/src/ia32/macro-assembler-ia32.cc +224 -67
- data/lib/libv8/v8/src/ia32/macro-assembler-ia32.h +63 -19
- data/lib/libv8/v8/src/ia32/regexp-macro-assembler-ia32.cc +22 -8
- data/lib/libv8/v8/src/ia32/regexp-macro-assembler-ia32.h +3 -0
- data/lib/libv8/v8/src/ia32/stub-cache-ia32.cc +380 -239
- data/lib/libv8/v8/src/ic.cc +198 -234
- data/lib/libv8/v8/src/ic.h +32 -30
- data/lib/libv8/v8/src/interpreter-irregexp.cc +6 -4
- data/lib/libv8/v8/src/isolate.cc +112 -95
- data/lib/libv8/v8/src/isolate.h +55 -71
- data/lib/libv8/v8/src/json-parser.h +486 -48
- data/lib/libv8/v8/src/json.js +28 -23
- data/lib/libv8/v8/src/jsregexp.cc +163 -208
- data/lib/libv8/v8/src/jsregexp.h +0 -1
- data/lib/libv8/v8/src/lithium-allocator-inl.h +29 -27
- data/lib/libv8/v8/src/lithium-allocator.cc +22 -17
- data/lib/libv8/v8/src/lithium-allocator.h +8 -8
- data/lib/libv8/v8/src/lithium.cc +16 -11
- data/lib/libv8/v8/src/lithium.h +31 -34
- data/lib/libv8/v8/src/liveedit.cc +111 -15
- data/lib/libv8/v8/src/liveedit.h +3 -4
- data/lib/libv8/v8/src/liveobjectlist.cc +116 -80
- data/lib/libv8/v8/src/liveobjectlist.h +2 -2
- data/lib/libv8/v8/src/log-inl.h +0 -4
- data/lib/libv8/v8/src/log-utils.cc +25 -143
- data/lib/libv8/v8/src/log-utils.h +13 -92
- data/lib/libv8/v8/src/log.cc +26 -249
- data/lib/libv8/v8/src/log.h +6 -17
- data/lib/libv8/v8/src/macros.py +9 -6
- data/lib/libv8/v8/src/mark-compact.cc +276 -56
- data/lib/libv8/v8/src/mark-compact.h +20 -0
- data/lib/libv8/v8/src/messages.js +93 -39
- data/lib/libv8/v8/src/mips/assembler-mips-inl.h +9 -3
- data/lib/libv8/v8/src/mips/assembler-mips.cc +297 -189
- data/lib/libv8/v8/src/mips/assembler-mips.h +121 -54
- data/lib/libv8/v8/src/mips/builtins-mips.cc +23 -24
- data/lib/libv8/v8/src/mips/code-stubs-mips.cc +484 -263
- data/lib/libv8/v8/src/mips/code-stubs-mips.h +8 -83
- data/lib/libv8/v8/src/mips/codegen-mips.h +0 -2
- data/lib/libv8/v8/src/mips/constants-mips.h +37 -11
- data/lib/libv8/v8/src/mips/deoptimizer-mips.cc +6 -1
- data/lib/libv8/v8/src/mips/frames-mips.h +8 -7
- data/lib/libv8/v8/src/mips/full-codegen-mips.cc +258 -419
- data/lib/libv8/v8/src/mips/ic-mips.cc +181 -121
- data/lib/libv8/v8/src/mips/macro-assembler-mips.cc +640 -382
- data/lib/libv8/v8/src/mips/macro-assembler-mips.h +94 -89
- data/lib/libv8/v8/src/mips/regexp-macro-assembler-mips.cc +23 -10
- data/lib/libv8/v8/src/mips/regexp-macro-assembler-mips.h +6 -1
- data/lib/libv8/v8/src/mips/simulator-mips.cc +249 -49
- data/lib/libv8/v8/src/mips/simulator-mips.h +25 -1
- data/lib/libv8/v8/src/mips/stub-cache-mips.cc +373 -161
- data/lib/libv8/v8/src/mirror-debugger.js +55 -8
- data/lib/libv8/v8/src/misc-intrinsics.h +89 -0
- data/lib/libv8/v8/src/mksnapshot.cc +36 -4
- data/lib/libv8/v8/src/natives.h +5 -2
- data/lib/libv8/v8/src/objects-debug.cc +73 -6
- data/lib/libv8/v8/src/objects-inl.h +529 -164
- data/lib/libv8/v8/src/objects-printer.cc +67 -12
- data/lib/libv8/v8/src/objects-visiting.cc +13 -2
- data/lib/libv8/v8/src/objects-visiting.h +41 -1
- data/lib/libv8/v8/src/objects.cc +2200 -1177
- data/lib/libv8/v8/src/objects.h +912 -283
- data/lib/libv8/v8/src/parser.cc +566 -371
- data/lib/libv8/v8/src/parser.h +35 -33
- data/lib/libv8/v8/src/platform-cygwin.cc +10 -25
- data/lib/libv8/v8/src/platform-freebsd.cc +4 -29
- data/lib/libv8/v8/src/platform-linux.cc +60 -57
- data/lib/libv8/v8/src/platform-macos.cc +4 -27
- data/lib/libv8/v8/src/platform-nullos.cc +3 -16
- data/lib/libv8/v8/src/platform-openbsd.cc +247 -85
- data/lib/libv8/v8/src/platform-posix.cc +43 -1
- data/lib/libv8/v8/src/platform-solaris.cc +151 -112
- data/lib/libv8/v8/src/platform-tls.h +1 -1
- data/lib/libv8/v8/src/platform-win32.cc +65 -39
- data/lib/libv8/v8/src/platform.h +17 -14
- data/lib/libv8/v8/src/preparse-data-format.h +2 -2
- data/lib/libv8/v8/src/preparse-data.h +8 -2
- data/lib/libv8/v8/src/preparser-api.cc +2 -18
- data/lib/libv8/v8/src/preparser.cc +106 -65
- data/lib/libv8/v8/src/preparser.h +26 -5
- data/lib/libv8/v8/src/prettyprinter.cc +25 -43
- data/lib/libv8/v8/src/profile-generator-inl.h +0 -4
- data/lib/libv8/v8/src/profile-generator.cc +213 -34
- data/lib/libv8/v8/src/profile-generator.h +9 -9
- data/lib/libv8/v8/src/property.h +1 -0
- data/lib/libv8/v8/src/proxy.js +74 -4
- data/lib/libv8/v8/src/regexp-macro-assembler.cc +10 -6
- data/lib/libv8/v8/src/regexp.js +16 -11
- data/lib/libv8/v8/src/rewriter.cc +24 -133
- data/lib/libv8/v8/src/runtime-profiler.cc +27 -151
- data/lib/libv8/v8/src/runtime-profiler.h +5 -31
- data/lib/libv8/v8/src/runtime.cc +1450 -681
- data/lib/libv8/v8/src/runtime.h +47 -31
- data/lib/libv8/v8/src/runtime.js +2 -1
- data/lib/libv8/v8/src/scanner-base.cc +358 -220
- data/lib/libv8/v8/src/scanner-base.h +30 -138
- data/lib/libv8/v8/src/scanner.cc +0 -18
- data/lib/libv8/v8/src/scanner.h +0 -15
- data/lib/libv8/v8/src/scopeinfo.cc +3 -1
- data/lib/libv8/v8/src/scopeinfo.h +1 -6
- data/lib/libv8/v8/src/scopes.cc +243 -253
- data/lib/libv8/v8/src/scopes.h +58 -109
- data/lib/libv8/v8/src/serialize.cc +12 -54
- data/lib/libv8/v8/src/serialize.h +47 -0
- data/lib/libv8/v8/src/small-pointer-list.h +25 -0
- data/lib/libv8/v8/src/spaces-inl.h +4 -50
- data/lib/libv8/v8/src/spaces.cc +64 -131
- data/lib/libv8/v8/src/spaces.h +19 -70
- data/lib/libv8/v8/src/string-stream.cc +3 -1
- data/lib/libv8/v8/src/string.js +10 -6
- data/lib/libv8/v8/src/strtod.cc +7 -3
- data/lib/libv8/v8/src/stub-cache.cc +59 -129
- data/lib/libv8/v8/src/stub-cache.h +42 -54
- data/lib/libv8/v8/src/third_party/valgrind/valgrind.h +1447 -1339
- data/lib/libv8/v8/src/token.cc +4 -4
- data/lib/libv8/v8/src/token.h +6 -5
- data/lib/libv8/v8/src/type-info.cc +173 -129
- data/lib/libv8/v8/src/type-info.h +40 -22
- data/lib/libv8/v8/src/utils.cc +25 -304
- data/lib/libv8/v8/src/utils.h +118 -3
- data/lib/libv8/v8/src/v8-counters.h +3 -6
- data/lib/libv8/v8/src/v8.cc +34 -27
- data/lib/libv8/v8/src/v8.h +7 -7
- data/lib/libv8/v8/src/v8conversions.cc +129 -0
- data/lib/libv8/v8/src/v8conversions.h +60 -0
- data/lib/libv8/v8/src/v8globals.h +15 -6
- data/lib/libv8/v8/src/v8natives.js +300 -78
- data/lib/libv8/v8/src/v8threads.cc +14 -6
- data/lib/libv8/v8/src/v8threads.h +4 -1
- data/lib/libv8/v8/src/v8utils.cc +360 -0
- data/lib/libv8/v8/src/v8utils.h +17 -66
- data/lib/libv8/v8/src/variables.cc +7 -12
- data/lib/libv8/v8/src/variables.h +12 -10
- data/lib/libv8/v8/src/version.cc +2 -2
- data/lib/libv8/v8/src/vm-state-inl.h +0 -41
- data/lib/libv8/v8/src/vm-state.h +0 -11
- data/lib/libv8/v8/src/weakmap.js +103 -0
- data/lib/libv8/v8/src/x64/assembler-x64.h +6 -3
- data/lib/libv8/v8/src/x64/builtins-x64.cc +25 -22
- data/lib/libv8/v8/src/x64/code-stubs-x64.cc +523 -250
- data/lib/libv8/v8/src/x64/code-stubs-x64.h +8 -71
- data/lib/libv8/v8/src/x64/codegen-x64.cc +1 -0
- data/lib/libv8/v8/src/x64/codegen-x64.h +0 -2
- data/lib/libv8/v8/src/x64/cpu-x64.cc +2 -1
- data/lib/libv8/v8/src/x64/deoptimizer-x64.cc +40 -8
- data/lib/libv8/v8/src/x64/disasm-x64.cc +12 -10
- data/lib/libv8/v8/src/x64/frames-x64.h +7 -6
- data/lib/libv8/v8/src/x64/full-codegen-x64.cc +310 -415
- data/lib/libv8/v8/src/x64/ic-x64.cc +180 -117
- data/lib/libv8/v8/src/x64/lithium-codegen-x64.cc +411 -523
- data/lib/libv8/v8/src/x64/lithium-codegen-x64.h +11 -6
- data/lib/libv8/v8/src/x64/lithium-x64.cc +191 -216
- data/lib/libv8/v8/src/x64/lithium-x64.h +112 -263
- data/lib/libv8/v8/src/x64/macro-assembler-x64.cc +177 -61
- data/lib/libv8/v8/src/x64/macro-assembler-x64.h +23 -7
- data/lib/libv8/v8/src/x64/regexp-macro-assembler-x64.cc +21 -9
- data/lib/libv8/v8/src/x64/regexp-macro-assembler-x64.h +6 -0
- data/lib/libv8/v8/src/x64/stub-cache-x64.cc +273 -107
- data/lib/libv8/v8/src/zone.cc +31 -22
- data/lib/libv8/v8/src/zone.h +12 -6
- data/lib/libv8/v8/tools/codemap.js +8 -0
- data/lib/libv8/v8/tools/gcmole/Makefile +43 -0
- data/lib/libv8/v8/tools/gcmole/gcmole.lua +0 -2
- data/lib/libv8/v8/tools/gdb-v8-support.py +154 -0
- data/lib/libv8/v8/tools/grokdump.py +44 -35
- data/lib/libv8/v8/tools/gyp/v8.gyp +94 -248
- data/lib/libv8/v8/tools/js2c.py +83 -52
- data/lib/libv8/v8/tools/linux-tick-processor +4 -6
- data/lib/libv8/v8/tools/ll_prof.py +3 -3
- data/lib/libv8/v8/tools/oom_dump/README +3 -1
- data/lib/libv8/v8/tools/presubmit.py +11 -4
- data/lib/libv8/v8/tools/profile.js +46 -2
- data/lib/libv8/v8/tools/splaytree.js +11 -0
- data/lib/libv8/v8/tools/stats-viewer.py +15 -11
- data/lib/libv8/v8/tools/test-wrapper-gypbuild.py +227 -0
- data/lib/libv8/v8/tools/test.py +28 -8
- data/lib/libv8/v8/tools/tickprocessor.js +0 -16
- data/lib/libv8/version.rb +1 -1
- data/libv8.gemspec +2 -2
- metadata +31 -19
- data/lib/libv8/scons/engine/SCons/Tool/f03.py +0 -63
- data/lib/libv8/v8/src/json-parser.cc +0 -504
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
#include "hashmap.h"
|
|
34
34
|
#include "lithium-allocator.h"
|
|
35
35
|
#include "parser.h"
|
|
36
|
+
#include "scopeinfo.h"
|
|
36
37
|
#include "scopes.h"
|
|
37
38
|
#include "stub-cache.h"
|
|
38
39
|
|
|
@@ -68,8 +69,8 @@ HBasicBlock::HBasicBlock(HGraph* graph)
|
|
|
68
69
|
last_instruction_index_(-1),
|
|
69
70
|
deleted_phis_(4),
|
|
70
71
|
parent_loop_header_(NULL),
|
|
71
|
-
is_inline_return_target_(false)
|
|
72
|
-
}
|
|
72
|
+
is_inline_return_target_(false),
|
|
73
|
+
is_deoptimizing_(false) { }
|
|
73
74
|
|
|
74
75
|
|
|
75
76
|
void HBasicBlock::AttachLoopInformation() {
|
|
@@ -131,16 +132,16 @@ HDeoptimize* HBasicBlock::CreateDeoptimize(
|
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
|
|
134
|
-
HSimulate* HBasicBlock::CreateSimulate(int
|
|
135
|
+
HSimulate* HBasicBlock::CreateSimulate(int ast_id) {
|
|
135
136
|
ASSERT(HasEnvironment());
|
|
136
137
|
HEnvironment* environment = last_environment();
|
|
137
|
-
ASSERT(
|
|
138
|
-
environment->closure()->shared()->VerifyBailoutId(
|
|
138
|
+
ASSERT(ast_id == AstNode::kNoNumber ||
|
|
139
|
+
environment->closure()->shared()->VerifyBailoutId(ast_id));
|
|
139
140
|
|
|
140
141
|
int push_count = environment->push_count();
|
|
141
142
|
int pop_count = environment->pop_count();
|
|
142
143
|
|
|
143
|
-
HSimulate* instr = new(zone()) HSimulate(
|
|
144
|
+
HSimulate* instr = new(zone()) HSimulate(ast_id, pop_count);
|
|
144
145
|
for (int i = push_count - 1; i >= 0; --i) {
|
|
145
146
|
instr->AddPushedValue(environment->ExpressionStackAt(i));
|
|
146
147
|
}
|
|
@@ -157,23 +158,19 @@ void HBasicBlock::Finish(HControlInstruction* end) {
|
|
|
157
158
|
ASSERT(!IsFinished());
|
|
158
159
|
AddInstruction(end);
|
|
159
160
|
end_ = end;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (end->SecondSuccessor() != NULL) {
|
|
163
|
-
end->SecondSuccessor()->RegisterPredecessor(this);
|
|
164
|
-
}
|
|
161
|
+
for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
|
|
162
|
+
it.Current()->RegisterPredecessor(this);
|
|
165
163
|
}
|
|
166
164
|
}
|
|
167
165
|
|
|
168
166
|
|
|
169
|
-
void HBasicBlock::Goto(HBasicBlock* block
|
|
167
|
+
void HBasicBlock::Goto(HBasicBlock* block) {
|
|
170
168
|
if (block->IsInlineReturnTarget()) {
|
|
171
169
|
AddInstruction(new(zone()) HLeaveInlined);
|
|
172
170
|
last_environment_ = last_environment()->outer();
|
|
173
171
|
}
|
|
174
172
|
AddSimulate(AstNode::kNoNumber);
|
|
175
173
|
HGoto* instr = new(zone()) HGoto(block);
|
|
176
|
-
instr->set_include_stack_check(include_stack_check);
|
|
177
174
|
Finish(instr);
|
|
178
175
|
}
|
|
179
176
|
|
|
@@ -197,7 +194,7 @@ void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
|
|
|
197
194
|
}
|
|
198
195
|
|
|
199
196
|
|
|
200
|
-
void HBasicBlock::SetJoinId(int
|
|
197
|
+
void HBasicBlock::SetJoinId(int ast_id) {
|
|
201
198
|
int length = predecessors_.length();
|
|
202
199
|
ASSERT(length > 0);
|
|
203
200
|
for (int i = 0; i < length; i++) {
|
|
@@ -207,8 +204,8 @@ void HBasicBlock::SetJoinId(int id) {
|
|
|
207
204
|
// We only need to verify the ID once.
|
|
208
205
|
ASSERT(i != 0 ||
|
|
209
206
|
predecessor->last_environment()->closure()->shared()
|
|
210
|
-
->VerifyBailoutId(
|
|
211
|
-
simulate->set_ast_id(
|
|
207
|
+
->VerifyBailoutId(ast_id));
|
|
208
|
+
simulate->set_ast_id(ast_id);
|
|
212
209
|
}
|
|
213
210
|
}
|
|
214
211
|
|
|
@@ -401,8 +398,9 @@ class ReachabilityAnalyzer BASE_EMBEDDED {
|
|
|
401
398
|
void Analyze() {
|
|
402
399
|
while (!stack_.is_empty()) {
|
|
403
400
|
HControlInstruction* end = stack_.RemoveLast()->end();
|
|
404
|
-
|
|
405
|
-
|
|
401
|
+
for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
|
|
402
|
+
PushBlock(it.Current());
|
|
403
|
+
}
|
|
406
404
|
}
|
|
407
405
|
}
|
|
408
406
|
|
|
@@ -521,6 +519,12 @@ HConstant* HGraph::GetConstantFalse() {
|
|
|
521
519
|
return GetConstant(&constant_false_, isolate()->heap()->false_value());
|
|
522
520
|
}
|
|
523
521
|
|
|
522
|
+
|
|
523
|
+
HConstant* HGraph::GetConstantHole() {
|
|
524
|
+
return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value());
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
|
|
524
528
|
HGraphBuilder::HGraphBuilder(CompilationInfo* info,
|
|
525
529
|
TypeFeedbackOracle* oracle)
|
|
526
530
|
: function_state_(NULL),
|
|
@@ -572,7 +576,7 @@ HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement,
|
|
|
572
576
|
HBasicBlock* body_exit,
|
|
573
577
|
HBasicBlock* loop_successor,
|
|
574
578
|
HBasicBlock* break_block) {
|
|
575
|
-
if (body_exit != NULL) body_exit->Goto(loop_entry
|
|
579
|
+
if (body_exit != NULL) body_exit->Goto(loop_entry);
|
|
576
580
|
loop_entry->PostProcessLoopHeader(statement);
|
|
577
581
|
if (break_block != NULL) {
|
|
578
582
|
if (loop_successor != NULL) loop_successor->Goto(break_block);
|
|
@@ -691,8 +695,9 @@ void HGraph::PostorderLoopBlocks(HLoopInformation* loop,
|
|
|
691
695
|
HBasicBlock* loop_header) {
|
|
692
696
|
for (int i = 0; i < loop->blocks()->length(); ++i) {
|
|
693
697
|
HBasicBlock* b = loop->blocks()->at(i);
|
|
694
|
-
|
|
695
|
-
|
|
698
|
+
for (HSuccessorIterator it(b->end()); !it.Done(); it.Advance()) {
|
|
699
|
+
Postorder(it.Current(), visited, order, loop_header);
|
|
700
|
+
}
|
|
696
701
|
if (b->IsLoopHeader() && b != loop->loop_header()) {
|
|
697
702
|
PostorderLoopBlocks(b->loop_information(), visited, order, loop_header);
|
|
698
703
|
}
|
|
@@ -709,11 +714,13 @@ void HGraph::Postorder(HBasicBlock* block,
|
|
|
709
714
|
visited->Add(block->block_id());
|
|
710
715
|
if (block->IsLoopHeader()) {
|
|
711
716
|
PostorderLoopBlocks(block->loop_information(), visited, order, loop_header);
|
|
712
|
-
|
|
713
|
-
|
|
717
|
+
for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) {
|
|
718
|
+
Postorder(it.Current(), visited, order, block);
|
|
719
|
+
}
|
|
714
720
|
} else {
|
|
715
|
-
|
|
716
|
-
|
|
721
|
+
for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) {
|
|
722
|
+
Postorder(it.Current(), visited, order, loop_header);
|
|
723
|
+
}
|
|
717
724
|
}
|
|
718
725
|
ASSERT(block->end()->FirstSuccessor() == NULL ||
|
|
719
726
|
order->Contains(block->end()->FirstSuccessor()) ||
|
|
@@ -729,6 +736,8 @@ void HGraph::AssignDominators() {
|
|
|
729
736
|
HPhase phase("Assign dominators", this);
|
|
730
737
|
for (int i = 0; i < blocks_.length(); ++i) {
|
|
731
738
|
if (blocks_[i]->IsLoopHeader()) {
|
|
739
|
+
// Only the first predecessor of a loop header is from outside the loop.
|
|
740
|
+
// All others are back edges, and thus cannot dominate the loop header.
|
|
732
741
|
blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first());
|
|
733
742
|
} else {
|
|
734
743
|
for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) {
|
|
@@ -738,6 +747,20 @@ void HGraph::AssignDominators() {
|
|
|
738
747
|
}
|
|
739
748
|
}
|
|
740
749
|
|
|
750
|
+
// Mark all blocks that are dominated by an unconditional soft deoptimize to
|
|
751
|
+
// prevent code motion across those blocks.
|
|
752
|
+
void HGraph::PropagateDeoptimizingMark() {
|
|
753
|
+
HPhase phase("Propagate deoptimizing mark", this);
|
|
754
|
+
MarkAsDeoptimizingRecursively(entry_block());
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
void HGraph::MarkAsDeoptimizingRecursively(HBasicBlock* block) {
|
|
758
|
+
for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
|
|
759
|
+
HBasicBlock* dominated = block->dominated_blocks()->at(i);
|
|
760
|
+
if (block->IsDeoptimizing()) dominated->MarkAsDeoptimizing();
|
|
761
|
+
MarkAsDeoptimizingRecursively(dominated);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
741
764
|
|
|
742
765
|
void HGraph::EliminateRedundantPhis() {
|
|
743
766
|
HPhase phase("Redundant phi elimination", this);
|
|
@@ -817,6 +840,19 @@ void HGraph::EliminateUnreachablePhis() {
|
|
|
817
840
|
}
|
|
818
841
|
|
|
819
842
|
|
|
843
|
+
bool HGraph::CheckPhis() {
|
|
844
|
+
int block_count = blocks_.length();
|
|
845
|
+
for (int i = 0; i < block_count; ++i) {
|
|
846
|
+
for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
|
|
847
|
+
HPhi* phi = blocks_[i]->phis()->at(j);
|
|
848
|
+
// We don't support phi uses of arguments for now.
|
|
849
|
+
if (phi->CheckFlag(HValue::kIsArguments)) return false;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
|
|
820
856
|
bool HGraph::CollectPhis() {
|
|
821
857
|
int block_count = blocks_.length();
|
|
822
858
|
phi_list_ = new ZoneList<HPhi*>(block_count);
|
|
@@ -824,8 +860,10 @@ bool HGraph::CollectPhis() {
|
|
|
824
860
|
for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
|
|
825
861
|
HPhi* phi = blocks_[i]->phis()->at(j);
|
|
826
862
|
phi_list_->Add(phi);
|
|
827
|
-
//
|
|
828
|
-
|
|
863
|
+
// Check for the hole value (from an uninitialized const).
|
|
864
|
+
for (int k = 0; k < phi->OperandCount(); k++) {
|
|
865
|
+
if (phi->OperandAt(k) == GetConstantHole()) return false;
|
|
866
|
+
}
|
|
829
867
|
}
|
|
830
868
|
}
|
|
831
869
|
return true;
|
|
@@ -864,9 +902,8 @@ class HRangeAnalysis BASE_EMBEDDED {
|
|
|
864
902
|
private:
|
|
865
903
|
void TraceRange(const char* msg, ...);
|
|
866
904
|
void Analyze(HBasicBlock* block);
|
|
867
|
-
void InferControlFlowRange(
|
|
868
|
-
void
|
|
869
|
-
void InferPhiRange(HPhi* phi);
|
|
905
|
+
void InferControlFlowRange(HCompareIDAndBranch* test, HBasicBlock* dest);
|
|
906
|
+
void UpdateControlFlowRange(Token::Value op, HValue* value, HValue* other);
|
|
870
907
|
void InferRange(HValue* value);
|
|
871
908
|
void RollBackTo(int index);
|
|
872
909
|
void AddRange(HValue* value, Range* range);
|
|
@@ -888,7 +925,7 @@ void HRangeAnalysis::TraceRange(const char* msg, ...) {
|
|
|
888
925
|
|
|
889
926
|
void HRangeAnalysis::Analyze() {
|
|
890
927
|
HPhase phase("Range analysis", graph_);
|
|
891
|
-
Analyze(graph_->
|
|
928
|
+
Analyze(graph_->entry_block());
|
|
892
929
|
}
|
|
893
930
|
|
|
894
931
|
|
|
@@ -900,15 +937,15 @@ void HRangeAnalysis::Analyze(HBasicBlock* block) {
|
|
|
900
937
|
// Infer range based on control flow.
|
|
901
938
|
if (block->predecessors()->length() == 1) {
|
|
902
939
|
HBasicBlock* pred = block->predecessors()->first();
|
|
903
|
-
if (pred->end()->
|
|
904
|
-
InferControlFlowRange(
|
|
940
|
+
if (pred->end()->IsCompareIDAndBranch()) {
|
|
941
|
+
InferControlFlowRange(HCompareIDAndBranch::cast(pred->end()), block);
|
|
905
942
|
}
|
|
906
943
|
}
|
|
907
944
|
|
|
908
945
|
// Process phi instructions.
|
|
909
946
|
for (int i = 0; i < block->phis()->length(); ++i) {
|
|
910
947
|
HPhi* phi = block->phis()->at(i);
|
|
911
|
-
|
|
948
|
+
InferRange(phi);
|
|
912
949
|
}
|
|
913
950
|
|
|
914
951
|
// Go through all instructions of the current block.
|
|
@@ -927,28 +964,26 @@ void HRangeAnalysis::Analyze(HBasicBlock* block) {
|
|
|
927
964
|
}
|
|
928
965
|
|
|
929
966
|
|
|
930
|
-
void HRangeAnalysis::InferControlFlowRange(
|
|
967
|
+
void HRangeAnalysis::InferControlFlowRange(HCompareIDAndBranch* test,
|
|
968
|
+
HBasicBlock* dest) {
|
|
931
969
|
ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
|
|
932
|
-
if (test->
|
|
933
|
-
|
|
934
|
-
if (
|
|
935
|
-
|
|
936
|
-
if (test->SecondSuccessor() == dest) {
|
|
937
|
-
op = Token::NegateCompareOp(op);
|
|
938
|
-
}
|
|
939
|
-
Token::Value inverted_op = Token::InvertCompareOp(op);
|
|
940
|
-
InferControlFlowRange(op, compare->left(), compare->right());
|
|
941
|
-
InferControlFlowRange(inverted_op, compare->right(), compare->left());
|
|
970
|
+
if (test->GetInputRepresentation().IsInteger32()) {
|
|
971
|
+
Token::Value op = test->token();
|
|
972
|
+
if (test->SecondSuccessor() == dest) {
|
|
973
|
+
op = Token::NegateCompareOp(op);
|
|
942
974
|
}
|
|
975
|
+
Token::Value inverted_op = Token::InvertCompareOp(op);
|
|
976
|
+
UpdateControlFlowRange(op, test->left(), test->right());
|
|
977
|
+
UpdateControlFlowRange(inverted_op, test->right(), test->left());
|
|
943
978
|
}
|
|
944
979
|
}
|
|
945
980
|
|
|
946
981
|
|
|
947
982
|
// We know that value [op] other. Use this information to update the range on
|
|
948
983
|
// value.
|
|
949
|
-
void HRangeAnalysis::
|
|
950
|
-
|
|
951
|
-
|
|
984
|
+
void HRangeAnalysis::UpdateControlFlowRange(Token::Value op,
|
|
985
|
+
HValue* value,
|
|
986
|
+
HValue* other) {
|
|
952
987
|
Range temp_range;
|
|
953
988
|
Range* range = other->range() != NULL ? other->range() : &temp_range;
|
|
954
989
|
Range* new_range = NULL;
|
|
@@ -979,12 +1014,6 @@ void HRangeAnalysis::InferControlFlowRange(Token::Value op,
|
|
|
979
1014
|
}
|
|
980
1015
|
|
|
981
1016
|
|
|
982
|
-
void HRangeAnalysis::InferPhiRange(HPhi* phi) {
|
|
983
|
-
// TODO(twuerthinger): Infer loop phi ranges.
|
|
984
|
-
InferRange(phi);
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
|
|
988
1017
|
void HRangeAnalysis::InferRange(HValue* value) {
|
|
989
1018
|
ASSERT(!value->HasRange());
|
|
990
1019
|
if (!value->representation().IsNone()) {
|
|
@@ -1211,8 +1240,6 @@ class HStackCheckEliminator BASE_EMBEDDED {
|
|
|
1211
1240
|
void Process();
|
|
1212
1241
|
|
|
1213
1242
|
private:
|
|
1214
|
-
void RemoveStackCheck(HBasicBlock* block);
|
|
1215
|
-
|
|
1216
1243
|
HGraph* graph_;
|
|
1217
1244
|
};
|
|
1218
1245
|
|
|
@@ -1227,31 +1254,23 @@ void HStackCheckEliminator::Process() {
|
|
|
1227
1254
|
if (block->IsLoopHeader()) {
|
|
1228
1255
|
HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge();
|
|
1229
1256
|
HBasicBlock* dominator = back_edge;
|
|
1230
|
-
|
|
1231
|
-
while (dominator != block && !back_edge_dominated_by_call) {
|
|
1257
|
+
while (true) {
|
|
1232
1258
|
HInstruction* instr = dominator->first();
|
|
1233
|
-
while (instr != NULL
|
|
1259
|
+
while (instr != NULL) {
|
|
1234
1260
|
if (instr->IsCall()) {
|
|
1235
|
-
|
|
1236
|
-
|
|
1261
|
+
block->loop_information()->stack_check()->Eliminate();
|
|
1262
|
+
break;
|
|
1237
1263
|
}
|
|
1238
1264
|
instr = instr->next();
|
|
1239
1265
|
}
|
|
1240
|
-
dominator = dominator->dominator();
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
1266
|
|
|
1267
|
+
// Done when the loop header is processed.
|
|
1268
|
+
if (dominator == block) break;
|
|
1246
1269
|
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
if (instr->IsGoto()) {
|
|
1251
|
-
HGoto::cast(instr)->set_include_stack_check(false);
|
|
1252
|
-
return;
|
|
1270
|
+
// Move up the dominator tree.
|
|
1271
|
+
dominator = dominator->dominator();
|
|
1272
|
+
}
|
|
1253
1273
|
}
|
|
1254
|
-
instr = instr->next();
|
|
1255
1274
|
}
|
|
1256
1275
|
}
|
|
1257
1276
|
|
|
@@ -1263,7 +1282,12 @@ class SparseSet {
|
|
|
1263
1282
|
: capacity_(capacity),
|
|
1264
1283
|
length_(0),
|
|
1265
1284
|
dense_(zone->NewArray<int>(capacity)),
|
|
1266
|
-
sparse_(zone->NewArray<int>(capacity)) {
|
|
1285
|
+
sparse_(zone->NewArray<int>(capacity)) {
|
|
1286
|
+
#ifndef NVALGRIND
|
|
1287
|
+
// Initialize the sparse array to make valgrind happy.
|
|
1288
|
+
memset(sparse_, 0, sizeof(sparse_[0]) * capacity);
|
|
1289
|
+
#endif
|
|
1290
|
+
}
|
|
1267
1291
|
|
|
1268
1292
|
bool Contains(int n) const {
|
|
1269
1293
|
ASSERT(0 <= n && n < capacity_);
|
|
@@ -1346,7 +1370,7 @@ void HGlobalValueNumberer::Analyze() {
|
|
|
1346
1370
|
LoopInvariantCodeMotion();
|
|
1347
1371
|
}
|
|
1348
1372
|
HValueMap* map = new(zone()) HValueMap();
|
|
1349
|
-
AnalyzeBlock(graph_->
|
|
1373
|
+
AnalyzeBlock(graph_->entry_block(), map);
|
|
1350
1374
|
}
|
|
1351
1375
|
|
|
1352
1376
|
|
|
@@ -1438,37 +1462,9 @@ bool HGlobalValueNumberer::AllowCodeMotion() {
|
|
|
1438
1462
|
|
|
1439
1463
|
bool HGlobalValueNumberer::ShouldMove(HInstruction* instr,
|
|
1440
1464
|
HBasicBlock* loop_header) {
|
|
1441
|
-
// If we've disabled code motion
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
// If --aggressive-loop-invariant-motion, move everything except change
|
|
1445
|
-
// instructions.
|
|
1446
|
-
if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) {
|
|
1447
|
-
return true;
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
|
-
// Otherwise only move instructions that postdominate the loop header
|
|
1451
|
-
// (i.e. are always executed inside the loop). This is to avoid
|
|
1452
|
-
// unnecessary deoptimizations assuming the loop is executed at least
|
|
1453
|
-
// once. TODO(fschneider): Better type feedback should give us
|
|
1454
|
-
// information about code that was never executed.
|
|
1455
|
-
HBasicBlock* block = instr->block();
|
|
1456
|
-
bool result = true;
|
|
1457
|
-
if (block != loop_header) {
|
|
1458
|
-
for (int i = 1; i < loop_header->predecessors()->length(); ++i) {
|
|
1459
|
-
bool found = false;
|
|
1460
|
-
HBasicBlock* pred = loop_header->predecessors()->at(i);
|
|
1461
|
-
while (pred != loop_header) {
|
|
1462
|
-
if (pred == block) found = true;
|
|
1463
|
-
pred = pred->dominator();
|
|
1464
|
-
}
|
|
1465
|
-
if (!found) {
|
|
1466
|
-
result = false;
|
|
1467
|
-
break;
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
return result;
|
|
1465
|
+
// If we've disabled code motion or we're in a block that unconditionally
|
|
1466
|
+
// deoptimizes, don't move any instructions.
|
|
1467
|
+
return AllowCodeMotion() && !instr->block()->IsDeoptimizing();
|
|
1472
1468
|
}
|
|
1473
1469
|
|
|
1474
1470
|
|
|
@@ -1685,8 +1681,8 @@ void HInferRepresentation::Analyze() {
|
|
|
1685
1681
|
HValue* use = it.value();
|
|
1686
1682
|
if (use->IsPhi()) {
|
|
1687
1683
|
int id = HPhi::cast(use)->phi_id();
|
|
1688
|
-
|
|
1689
|
-
|
|
1684
|
+
if (connected_phis[i]->UnionIsChanged(*connected_phis[id]))
|
|
1685
|
+
change = true;
|
|
1690
1686
|
}
|
|
1691
1687
|
}
|
|
1692
1688
|
}
|
|
@@ -1841,6 +1837,8 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
|
|
|
1841
1837
|
// change instructions for them.
|
|
1842
1838
|
HInstruction* new_value = NULL;
|
|
1843
1839
|
bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32);
|
|
1840
|
+
bool deoptimize_on_undefined =
|
|
1841
|
+
use_value->CheckFlag(HValue::kDeoptimizeOnUndefined);
|
|
1844
1842
|
if (value->IsConstant()) {
|
|
1845
1843
|
HConstant* constant = HConstant::cast(value);
|
|
1846
1844
|
// Try to create a new copy of the constant with the new representation.
|
|
@@ -1850,8 +1848,8 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
|
|
|
1850
1848
|
}
|
|
1851
1849
|
|
|
1852
1850
|
if (new_value == NULL) {
|
|
1853
|
-
new_value =
|
|
1854
|
-
|
|
1851
|
+
new_value = new(zone()) HChange(value, value->representation(), to,
|
|
1852
|
+
is_truncating, deoptimize_on_undefined);
|
|
1855
1853
|
}
|
|
1856
1854
|
|
|
1857
1855
|
new_value->InsertBefore(next);
|
|
@@ -1933,6 +1931,40 @@ void HGraph::InsertRepresentationChanges() {
|
|
|
1933
1931
|
}
|
|
1934
1932
|
|
|
1935
1933
|
|
|
1934
|
+
void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) {
|
|
1935
|
+
if (phi->CheckFlag(HValue::kDeoptimizeOnUndefined)) return;
|
|
1936
|
+
phi->SetFlag(HValue::kDeoptimizeOnUndefined);
|
|
1937
|
+
for (int i = 0; i < phi->OperandCount(); ++i) {
|
|
1938
|
+
HValue* input = phi->OperandAt(i);
|
|
1939
|
+
if (input->IsPhi()) {
|
|
1940
|
+
RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input));
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
|
|
1946
|
+
void HGraph::MarkDeoptimizeOnUndefined() {
|
|
1947
|
+
HPhase phase("MarkDeoptimizeOnUndefined", this);
|
|
1948
|
+
// Compute DeoptimizeOnUndefined flag for phis.
|
|
1949
|
+
// Any phi that can reach a use with DeoptimizeOnUndefined set must
|
|
1950
|
+
// have DeoptimizeOnUndefined set. Currently only HCompareIDAndBranch, with
|
|
1951
|
+
// double input representation, has this flag set.
|
|
1952
|
+
// The flag is used by HChange tagged->double, which must deoptimize
|
|
1953
|
+
// if one of its uses has this flag set.
|
|
1954
|
+
for (int i = 0; i < phi_list()->length(); i++) {
|
|
1955
|
+
HPhi* phi = phi_list()->at(i);
|
|
1956
|
+
if (phi->representation().IsDouble()) {
|
|
1957
|
+
for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
|
|
1958
|
+
if (it.value()->CheckFlag(HValue::kDeoptimizeOnUndefined)) {
|
|
1959
|
+
RecursivelyMarkPhiDeoptimizeOnUndefined(phi);
|
|
1960
|
+
break;
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
|
|
1936
1968
|
void HGraph::ComputeMinusZeroChecks() {
|
|
1937
1969
|
BitVector visited(GetMaximumValueID());
|
|
1938
1970
|
for (int i = 0; i < blocks_.length(); ++i) {
|
|
@@ -1976,9 +2008,10 @@ FunctionState::FunctionState(HGraphBuilder* owner,
|
|
|
1976
2008
|
HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
|
|
1977
2009
|
if_true->MarkAsInlineReturnTarget();
|
|
1978
2010
|
if_false->MarkAsInlineReturnTarget();
|
|
2011
|
+
Expression* cond = TestContext::cast(owner->ast_context())->condition();
|
|
1979
2012
|
// The AstContext constructor pushed on the context stack. This newed
|
|
1980
2013
|
// instance is the reason that AstContext can't be BASE_EMBEDDED.
|
|
1981
|
-
test_context_ = new TestContext(owner, if_true, if_false);
|
|
2014
|
+
test_context_ = new TestContext(owner, cond, if_true, if_false);
|
|
1982
2015
|
} else {
|
|
1983
2016
|
function_return_ = owner->graph()->CreateBasicBlock();
|
|
1984
2017
|
function_return()->MarkAsInlineReturnTarget();
|
|
@@ -2052,14 +2085,28 @@ void TestContext::ReturnValue(HValue* value) {
|
|
|
2052
2085
|
|
|
2053
2086
|
|
|
2054
2087
|
void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) {
|
|
2088
|
+
ASSERT(!instr->IsControlInstruction());
|
|
2055
2089
|
owner()->AddInstruction(instr);
|
|
2056
2090
|
if (instr->HasSideEffects()) owner()->AddSimulate(ast_id);
|
|
2057
2091
|
}
|
|
2058
2092
|
|
|
2059
2093
|
|
|
2094
|
+
void EffectContext::ReturnControl(HControlInstruction* instr, int ast_id) {
|
|
2095
|
+
ASSERT(!instr->HasSideEffects());
|
|
2096
|
+
HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
|
|
2097
|
+
HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
|
|
2098
|
+
instr->SetSuccessorAt(0, empty_true);
|
|
2099
|
+
instr->SetSuccessorAt(1, empty_false);
|
|
2100
|
+
owner()->current_block()->Finish(instr);
|
|
2101
|
+
HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
|
|
2102
|
+
owner()->set_current_block(join);
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
|
|
2060
2106
|
void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) {
|
|
2107
|
+
ASSERT(!instr->IsControlInstruction());
|
|
2061
2108
|
if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
|
|
2062
|
-
owner()->Bailout("bad value context for arguments object value");
|
|
2109
|
+
return owner()->Bailout("bad value context for arguments object value");
|
|
2063
2110
|
}
|
|
2064
2111
|
owner()->AddInstruction(instr);
|
|
2065
2112
|
owner()->Push(instr);
|
|
@@ -2067,7 +2114,28 @@ void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) {
|
|
|
2067
2114
|
}
|
|
2068
2115
|
|
|
2069
2116
|
|
|
2117
|
+
void ValueContext::ReturnControl(HControlInstruction* instr, int ast_id) {
|
|
2118
|
+
ASSERT(!instr->HasSideEffects());
|
|
2119
|
+
if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
|
|
2120
|
+
return owner()->Bailout("bad value context for arguments object value");
|
|
2121
|
+
}
|
|
2122
|
+
HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
|
|
2123
|
+
HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
|
|
2124
|
+
instr->SetSuccessorAt(0, materialize_true);
|
|
2125
|
+
instr->SetSuccessorAt(1, materialize_false);
|
|
2126
|
+
owner()->current_block()->Finish(instr);
|
|
2127
|
+
owner()->set_current_block(materialize_true);
|
|
2128
|
+
owner()->Push(owner()->graph()->GetConstantTrue());
|
|
2129
|
+
owner()->set_current_block(materialize_false);
|
|
2130
|
+
owner()->Push(owner()->graph()->GetConstantFalse());
|
|
2131
|
+
HBasicBlock* join =
|
|
2132
|
+
owner()->CreateJoin(materialize_true, materialize_false, ast_id);
|
|
2133
|
+
owner()->set_current_block(join);
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
|
|
2070
2137
|
void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) {
|
|
2138
|
+
ASSERT(!instr->IsControlInstruction());
|
|
2071
2139
|
HGraphBuilder* builder = owner();
|
|
2072
2140
|
builder->AddInstruction(instr);
|
|
2073
2141
|
// We expect a simulate after every expression with side effects, though
|
|
@@ -2081,22 +2149,37 @@ void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) {
|
|
|
2081
2149
|
}
|
|
2082
2150
|
|
|
2083
2151
|
|
|
2152
|
+
void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) {
|
|
2153
|
+
ASSERT(!instr->HasSideEffects());
|
|
2154
|
+
HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
|
|
2155
|
+
HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
|
|
2156
|
+
instr->SetSuccessorAt(0, empty_true);
|
|
2157
|
+
instr->SetSuccessorAt(1, empty_false);
|
|
2158
|
+
owner()->current_block()->Finish(instr);
|
|
2159
|
+
empty_true->Goto(if_true());
|
|
2160
|
+
empty_false->Goto(if_false());
|
|
2161
|
+
owner()->set_current_block(NULL);
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
|
|
2084
2165
|
void TestContext::BuildBranch(HValue* value) {
|
|
2085
2166
|
// We expect the graph to be in edge-split form: there is no edge that
|
|
2086
2167
|
// connects a branch node to a join node. We conservatively ensure that
|
|
2087
2168
|
// property by always adding an empty block on the outgoing edges of this
|
|
2088
2169
|
// branch.
|
|
2089
2170
|
HGraphBuilder* builder = owner();
|
|
2090
|
-
if (value->CheckFlag(HValue::kIsArguments)) {
|
|
2171
|
+
if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
|
|
2091
2172
|
builder->Bailout("arguments object value in a test context");
|
|
2092
2173
|
}
|
|
2093
2174
|
HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
|
|
2094
2175
|
HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
|
|
2095
|
-
|
|
2176
|
+
unsigned test_id = condition()->test_id();
|
|
2177
|
+
ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id));
|
|
2178
|
+
HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
|
|
2096
2179
|
builder->current_block()->Finish(test);
|
|
2097
2180
|
|
|
2098
|
-
empty_true->Goto(if_true()
|
|
2099
|
-
empty_false->Goto(if_false()
|
|
2181
|
+
empty_true->Goto(if_true());
|
|
2182
|
+
empty_false->Goto(if_false());
|
|
2100
2183
|
builder->set_current_block(NULL);
|
|
2101
2184
|
}
|
|
2102
2185
|
|
|
@@ -2148,14 +2231,17 @@ void HGraphBuilder::VisitForTypeOf(Expression* expr) {
|
|
|
2148
2231
|
void HGraphBuilder::VisitForControl(Expression* expr,
|
|
2149
2232
|
HBasicBlock* true_block,
|
|
2150
2233
|
HBasicBlock* false_block) {
|
|
2151
|
-
TestContext for_test(this, true_block, false_block);
|
|
2234
|
+
TestContext for_test(this, expr, true_block, false_block);
|
|
2152
2235
|
Visit(expr);
|
|
2153
2236
|
}
|
|
2154
2237
|
|
|
2155
2238
|
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2239
|
+
HValue* HGraphBuilder::VisitArgument(Expression* expr) {
|
|
2240
|
+
VisitForValue(expr);
|
|
2241
|
+
if (HasStackOverflow() || current_block() == NULL) return NULL;
|
|
2242
|
+
HValue* value = Pop();
|
|
2243
|
+
Push(AddInstruction(new(zone()) HPushArgument(value)));
|
|
2244
|
+
return value;
|
|
2159
2245
|
}
|
|
2160
2246
|
|
|
2161
2247
|
|
|
@@ -2188,7 +2274,9 @@ HGraph* HGraphBuilder::CreateGraph() {
|
|
|
2188
2274
|
}
|
|
2189
2275
|
SetupScope(scope);
|
|
2190
2276
|
VisitDeclarations(scope->declarations());
|
|
2191
|
-
|
|
2277
|
+
HValue* context = environment()->LookupContext();
|
|
2278
|
+
AddInstruction(
|
|
2279
|
+
new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry));
|
|
2192
2280
|
|
|
2193
2281
|
// Add an edge to the body entry. This is warty: the graph's start
|
|
2194
2282
|
// environment will be used by the Lithium translation as the initial
|
|
@@ -2222,29 +2310,26 @@ HGraph* HGraphBuilder::CreateGraph() {
|
|
|
2222
2310
|
|
|
2223
2311
|
graph()->OrderBlocks();
|
|
2224
2312
|
graph()->AssignDominators();
|
|
2313
|
+
graph()->PropagateDeoptimizingMark();
|
|
2225
2314
|
graph()->EliminateRedundantPhis();
|
|
2315
|
+
if (!graph()->CheckPhis()) {
|
|
2316
|
+
Bailout("Unsupported phi use of arguments object");
|
|
2317
|
+
return NULL;
|
|
2318
|
+
}
|
|
2226
2319
|
if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis();
|
|
2227
2320
|
if (!graph()->CollectPhis()) {
|
|
2228
|
-
Bailout("
|
|
2321
|
+
Bailout("Unsupported phi use of uninitialized constant");
|
|
2229
2322
|
return NULL;
|
|
2230
2323
|
}
|
|
2231
2324
|
|
|
2232
2325
|
HInferRepresentation rep(graph());
|
|
2233
2326
|
rep.Analyze();
|
|
2234
2327
|
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
rangeAnalysis.Analyze();
|
|
2238
|
-
}
|
|
2328
|
+
graph()->MarkDeoptimizeOnUndefined();
|
|
2329
|
+
graph()->InsertRepresentationChanges();
|
|
2239
2330
|
|
|
2240
2331
|
graph()->InitializeInferredTypes();
|
|
2241
2332
|
graph()->Canonicalize();
|
|
2242
|
-
graph()->InsertRepresentationChanges();
|
|
2243
|
-
graph()->ComputeMinusZeroChecks();
|
|
2244
|
-
|
|
2245
|
-
// Eliminate redundant stack checks on backwards branches.
|
|
2246
|
-
HStackCheckEliminator sce(graph());
|
|
2247
|
-
sce.Process();
|
|
2248
2333
|
|
|
2249
2334
|
// Perform common subexpression elimination and loop-invariant code motion.
|
|
2250
2335
|
if (FLAG_use_gvn) {
|
|
@@ -2253,10 +2338,42 @@ HGraph* HGraphBuilder::CreateGraph() {
|
|
|
2253
2338
|
gvn.Analyze();
|
|
2254
2339
|
}
|
|
2255
2340
|
|
|
2341
|
+
if (FLAG_use_range) {
|
|
2342
|
+
HRangeAnalysis rangeAnalysis(graph());
|
|
2343
|
+
rangeAnalysis.Analyze();
|
|
2344
|
+
}
|
|
2345
|
+
graph()->ComputeMinusZeroChecks();
|
|
2346
|
+
|
|
2347
|
+
// Eliminate redundant stack checks on backwards branches.
|
|
2348
|
+
HStackCheckEliminator sce(graph());
|
|
2349
|
+
sce.Process();
|
|
2350
|
+
|
|
2351
|
+
// Replace the results of check instructions with the original value, if the
|
|
2352
|
+
// result is used. This is safe now, since we don't do code motion after this
|
|
2353
|
+
// point. It enables better register allocation since the value produced by
|
|
2354
|
+
// check instructions is really a copy of the original value.
|
|
2355
|
+
graph()->ReplaceCheckedValues();
|
|
2356
|
+
|
|
2256
2357
|
return graph();
|
|
2257
2358
|
}
|
|
2258
2359
|
|
|
2259
2360
|
|
|
2361
|
+
void HGraph::ReplaceCheckedValues() {
|
|
2362
|
+
HPhase phase("Replace checked values", this);
|
|
2363
|
+
for (int i = 0; i < blocks()->length(); ++i) {
|
|
2364
|
+
HInstruction* instr = blocks()->at(i)->first();
|
|
2365
|
+
while (instr != NULL) {
|
|
2366
|
+
if (instr->IsBoundsCheck()) {
|
|
2367
|
+
// Replace all uses of the checked value with the original input.
|
|
2368
|
+
ASSERT(instr->UseCount() > 0);
|
|
2369
|
+
instr->ReplaceAllUsesWith(HBoundsCheck::cast(instr)->index());
|
|
2370
|
+
}
|
|
2371
|
+
instr = instr->next();
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
|
|
2260
2377
|
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
|
|
2261
2378
|
ASSERT(current_block() != NULL);
|
|
2262
2379
|
current_block()->AddInstruction(instr);
|
|
@@ -2264,9 +2381,9 @@ HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
|
|
|
2264
2381
|
}
|
|
2265
2382
|
|
|
2266
2383
|
|
|
2267
|
-
void HGraphBuilder::AddSimulate(int
|
|
2384
|
+
void HGraphBuilder::AddSimulate(int ast_id) {
|
|
2268
2385
|
ASSERT(current_block() != NULL);
|
|
2269
|
-
current_block()->AddSimulate(
|
|
2386
|
+
current_block()->AddSimulate(ast_id);
|
|
2270
2387
|
}
|
|
2271
2388
|
|
|
2272
2389
|
|
|
@@ -2298,9 +2415,6 @@ HInstruction* HGraphBuilder::PreProcessCall(HCall<V>* call) {
|
|
|
2298
2415
|
|
|
2299
2416
|
|
|
2300
2417
|
void HGraphBuilder::SetupScope(Scope* scope) {
|
|
2301
|
-
// We don't yet handle the function name for named function expressions.
|
|
2302
|
-
if (scope->function() != NULL) return Bailout("named function expression");
|
|
2303
|
-
|
|
2304
2418
|
HConstant* undefined_constant = new(zone()) HConstant(
|
|
2305
2419
|
isolate()->factory()->undefined_value(), Representation::Tagged());
|
|
2306
2420
|
AddInstruction(undefined_constant);
|
|
@@ -2329,18 +2443,13 @@ void HGraphBuilder::SetupScope(Scope* scope) {
|
|
|
2329
2443
|
// Handle the arguments and arguments shadow variables specially (they do
|
|
2330
2444
|
// not have declarations).
|
|
2331
2445
|
if (scope->arguments() != NULL) {
|
|
2332
|
-
if (!scope->arguments()->IsStackAllocated()
|
|
2333
|
-
(scope->arguments_shadow() != NULL &&
|
|
2334
|
-
!scope->arguments_shadow()->IsStackAllocated())) {
|
|
2446
|
+
if (!scope->arguments()->IsStackAllocated()) {
|
|
2335
2447
|
return Bailout("context-allocated arguments");
|
|
2336
2448
|
}
|
|
2337
2449
|
HArgumentsObject* object = new(zone()) HArgumentsObject;
|
|
2338
2450
|
AddInstruction(object);
|
|
2339
2451
|
graph()->SetArgumentsObject(object);
|
|
2340
2452
|
environment()->Bind(scope->arguments(), object);
|
|
2341
|
-
if (scope->arguments_shadow() != NULL) {
|
|
2342
|
-
environment()->Bind(scope->arguments_shadow(), object);
|
|
2343
|
-
}
|
|
2344
2453
|
}
|
|
2345
2454
|
}
|
|
2346
2455
|
|
|
@@ -2372,6 +2481,9 @@ void HGraphBuilder::VisitBlock(Block* stmt) {
|
|
|
2372
2481
|
ASSERT(!HasStackOverflow());
|
|
2373
2482
|
ASSERT(current_block() != NULL);
|
|
2374
2483
|
ASSERT(current_block()->HasPredecessor());
|
|
2484
|
+
if (stmt->block_scope() != NULL) {
|
|
2485
|
+
return Bailout("ScopedBlock");
|
|
2486
|
+
}
|
|
2375
2487
|
BreakAndContinueInfo break_info(stmt);
|
|
2376
2488
|
{ BreakAndContinueScope push(&break_info, this);
|
|
2377
2489
|
CHECK_BAILOUT(VisitStatements(stmt->statements()));
|
|
@@ -2433,7 +2545,7 @@ void HGraphBuilder::VisitIfStatement(IfStatement* stmt) {
|
|
|
2433
2545
|
cond_false = NULL;
|
|
2434
2546
|
}
|
|
2435
2547
|
|
|
2436
|
-
HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->
|
|
2548
|
+
HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId());
|
|
2437
2549
|
set_current_block(join);
|
|
2438
2550
|
}
|
|
2439
2551
|
}
|
|
@@ -2511,7 +2623,7 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
|
|
|
2511
2623
|
test->if_false());
|
|
2512
2624
|
} else if (context->IsEffect()) {
|
|
2513
2625
|
CHECK_ALIVE(VisitForEffect(stmt->expression()));
|
|
2514
|
-
current_block()->Goto(function_return()
|
|
2626
|
+
current_block()->Goto(function_return());
|
|
2515
2627
|
} else {
|
|
2516
2628
|
ASSERT(context->IsValue());
|
|
2517
2629
|
CHECK_ALIVE(VisitForValue(stmt->expression()));
|
|
@@ -2523,19 +2635,19 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
|
|
|
2523
2635
|
}
|
|
2524
2636
|
|
|
2525
2637
|
|
|
2526
|
-
void HGraphBuilder::
|
|
2638
|
+
void HGraphBuilder::VisitWithStatement(WithStatement* stmt) {
|
|
2527
2639
|
ASSERT(!HasStackOverflow());
|
|
2528
2640
|
ASSERT(current_block() != NULL);
|
|
2529
2641
|
ASSERT(current_block()->HasPredecessor());
|
|
2530
|
-
return Bailout("
|
|
2642
|
+
return Bailout("WithStatement");
|
|
2531
2643
|
}
|
|
2532
2644
|
|
|
2533
2645
|
|
|
2534
|
-
void HGraphBuilder::
|
|
2646
|
+
void HGraphBuilder::VisitExitContextStatement(ExitContextStatement* stmt) {
|
|
2535
2647
|
ASSERT(!HasStackOverflow());
|
|
2536
2648
|
ASSERT(current_block() != NULL);
|
|
2537
2649
|
ASSERT(current_block()->HasPredecessor());
|
|
2538
|
-
return Bailout("
|
|
2650
|
+
return Bailout("ExitContextStatement");
|
|
2539
2651
|
}
|
|
2540
2652
|
|
|
2541
2653
|
|
|
@@ -2579,15 +2691,16 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
|
|
|
2579
2691
|
// Otherwise generate a compare and branch.
|
|
2580
2692
|
CHECK_ALIVE(VisitForValue(clause->label()));
|
|
2581
2693
|
HValue* label_value = Pop();
|
|
2582
|
-
|
|
2583
|
-
new(zone())
|
|
2694
|
+
HCompareIDAndBranch* compare =
|
|
2695
|
+
new(zone()) HCompareIDAndBranch(tag_value,
|
|
2696
|
+
label_value,
|
|
2697
|
+
Token::EQ_STRICT);
|
|
2584
2698
|
compare->SetInputRepresentation(Representation::Integer32());
|
|
2585
|
-
ASSERT(!compare->HasSideEffects());
|
|
2586
|
-
AddInstruction(compare);
|
|
2587
2699
|
HBasicBlock* body_block = graph()->CreateBasicBlock();
|
|
2588
2700
|
HBasicBlock* next_test_block = graph()->CreateBasicBlock();
|
|
2589
|
-
|
|
2590
|
-
|
|
2701
|
+
compare->SetSuccessorAt(0, body_block);
|
|
2702
|
+
compare->SetSuccessorAt(1, next_test_block);
|
|
2703
|
+
current_block()->Finish(compare);
|
|
2591
2704
|
set_current_block(next_test_block);
|
|
2592
2705
|
}
|
|
2593
2706
|
|
|
@@ -2673,7 +2786,7 @@ void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) {
|
|
|
2673
2786
|
HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
|
|
2674
2787
|
HBasicBlock* osr_entry = graph()->CreateBasicBlock();
|
|
2675
2788
|
HValue* true_value = graph()->GetConstantTrue();
|
|
2676
|
-
|
|
2789
|
+
HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry);
|
|
2677
2790
|
current_block()->Finish(test);
|
|
2678
2791
|
|
|
2679
2792
|
HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
|
|
@@ -2701,6 +2814,21 @@ void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) {
|
|
|
2701
2814
|
}
|
|
2702
2815
|
|
|
2703
2816
|
|
|
2817
|
+
void HGraphBuilder::VisitLoopBody(IterationStatement* stmt,
|
|
2818
|
+
HBasicBlock* loop_entry,
|
|
2819
|
+
BreakAndContinueInfo* break_info) {
|
|
2820
|
+
BreakAndContinueScope push(break_info, this);
|
|
2821
|
+
AddSimulate(stmt->StackCheckId());
|
|
2822
|
+
HValue* context = environment()->LookupContext();
|
|
2823
|
+
HStackCheck* stack_check =
|
|
2824
|
+
new(zone()) HStackCheck(context, HStackCheck::kBackwardsBranch);
|
|
2825
|
+
AddInstruction(stack_check);
|
|
2826
|
+
ASSERT(loop_entry->IsLoopHeader());
|
|
2827
|
+
loop_entry->loop_information()->set_stack_check(stack_check);
|
|
2828
|
+
CHECK_BAILOUT(Visit(stmt->body()));
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2831
|
+
|
|
2704
2832
|
void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
|
2705
2833
|
ASSERT(!HasStackOverflow());
|
|
2706
2834
|
ASSERT(current_block() != NULL);
|
|
@@ -2708,13 +2836,11 @@ void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
|
|
2708
2836
|
ASSERT(current_block() != NULL);
|
|
2709
2837
|
PreProcessOsrEntry(stmt);
|
|
2710
2838
|
HBasicBlock* loop_entry = CreateLoopHeaderBlock();
|
|
2711
|
-
current_block()->Goto(loop_entry
|
|
2839
|
+
current_block()->Goto(loop_entry);
|
|
2712
2840
|
set_current_block(loop_entry);
|
|
2713
2841
|
|
|
2714
2842
|
BreakAndContinueInfo break_info(stmt);
|
|
2715
|
-
|
|
2716
|
-
CHECK_BAILOUT(Visit(stmt->body()));
|
|
2717
|
-
}
|
|
2843
|
+
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
|
|
2718
2844
|
HBasicBlock* body_exit =
|
|
2719
2845
|
JoinContinue(stmt, current_block(), break_info.continue_block());
|
|
2720
2846
|
HBasicBlock* loop_successor = NULL;
|
|
@@ -2752,7 +2878,7 @@ void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
|
|
|
2752
2878
|
ASSERT(current_block() != NULL);
|
|
2753
2879
|
PreProcessOsrEntry(stmt);
|
|
2754
2880
|
HBasicBlock* loop_entry = CreateLoopHeaderBlock();
|
|
2755
|
-
current_block()->Goto(loop_entry
|
|
2881
|
+
current_block()->Goto(loop_entry);
|
|
2756
2882
|
set_current_block(loop_entry);
|
|
2757
2883
|
|
|
2758
2884
|
// If the condition is constant true, do not generate a branch.
|
|
@@ -2775,7 +2901,7 @@ void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
|
|
|
2775
2901
|
BreakAndContinueInfo break_info(stmt);
|
|
2776
2902
|
if (current_block() != NULL) {
|
|
2777
2903
|
BreakAndContinueScope push(&break_info, this);
|
|
2778
|
-
CHECK_BAILOUT(
|
|
2904
|
+
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
|
|
2779
2905
|
}
|
|
2780
2906
|
HBasicBlock* body_exit =
|
|
2781
2907
|
JoinContinue(stmt, current_block(), break_info.continue_block());
|
|
@@ -2798,7 +2924,7 @@ void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
|
|
|
2798
2924
|
ASSERT(current_block() != NULL);
|
|
2799
2925
|
PreProcessOsrEntry(stmt);
|
|
2800
2926
|
HBasicBlock* loop_entry = CreateLoopHeaderBlock();
|
|
2801
|
-
current_block()->Goto(loop_entry
|
|
2927
|
+
current_block()->Goto(loop_entry);
|
|
2802
2928
|
set_current_block(loop_entry);
|
|
2803
2929
|
|
|
2804
2930
|
HBasicBlock* loop_successor = NULL;
|
|
@@ -2820,7 +2946,7 @@ void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
|
|
|
2820
2946
|
BreakAndContinueInfo break_info(stmt);
|
|
2821
2947
|
if (current_block() != NULL) {
|
|
2822
2948
|
BreakAndContinueScope push(&break_info, this);
|
|
2823
|
-
CHECK_BAILOUT(
|
|
2949
|
+
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
|
|
2824
2950
|
}
|
|
2825
2951
|
HBasicBlock* body_exit =
|
|
2826
2952
|
JoinContinue(stmt, current_block(), break_info.continue_block());
|
|
@@ -2904,9 +3030,10 @@ void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
|
|
|
2904
3030
|
}
|
|
2905
3031
|
// We also have a stack overflow if the recursive compilation did.
|
|
2906
3032
|
if (HasStackOverflow()) return;
|
|
3033
|
+
HValue* context = environment()->LookupContext();
|
|
2907
3034
|
HFunctionLiteral* instr =
|
|
2908
|
-
new(zone()) HFunctionLiteral(shared_info, expr->pretenure());
|
|
2909
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
3035
|
+
new(zone()) HFunctionLiteral(context, shared_info, expr->pretenure());
|
|
3036
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
2910
3037
|
}
|
|
2911
3038
|
|
|
2912
3039
|
|
|
@@ -2951,7 +3078,7 @@ void HGraphBuilder::VisitConditional(Conditional* expr) {
|
|
|
2951
3078
|
HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id());
|
|
2952
3079
|
set_current_block(join);
|
|
2953
3080
|
if (join != NULL && !ast_context()->IsEffect()) {
|
|
2954
|
-
ast_context()->ReturnValue(Pop());
|
|
3081
|
+
return ast_context()->ReturnValue(Pop());
|
|
2955
3082
|
}
|
|
2956
3083
|
}
|
|
2957
3084
|
}
|
|
@@ -2995,8 +3122,15 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
|
|
2995
3122
|
Variable* variable = expr->AsVariable();
|
|
2996
3123
|
if (variable == NULL) {
|
|
2997
3124
|
return Bailout("reference to rewritten variable");
|
|
3125
|
+
} else if (variable->mode() == Variable::LET) {
|
|
3126
|
+
return Bailout("reference to let variable");
|
|
2998
3127
|
} else if (variable->IsStackAllocated()) {
|
|
2999
|
-
|
|
3128
|
+
HValue* value = environment()->Lookup(variable);
|
|
3129
|
+
if (variable->mode() == Variable::CONST &&
|
|
3130
|
+
value == graph()->GetConstantHole()) {
|
|
3131
|
+
return Bailout("reference to uninitialized const variable");
|
|
3132
|
+
}
|
|
3133
|
+
return ast_context()->ReturnValue(value);
|
|
3000
3134
|
} else if (variable->IsContextSlot()) {
|
|
3001
3135
|
if (variable->mode() == Variable::CONST) {
|
|
3002
3136
|
return Bailout("reference to const context slot");
|
|
@@ -3004,7 +3138,7 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
|
|
3004
3138
|
HValue* context = BuildContextChainWalk(variable);
|
|
3005
3139
|
int index = variable->AsSlot()->index();
|
|
3006
3140
|
HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index);
|
|
3007
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
3141
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
3008
3142
|
} else if (variable->is_global()) {
|
|
3009
3143
|
LookupResult lookup;
|
|
3010
3144
|
GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false);
|
|
@@ -3019,7 +3153,7 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
|
|
3019
3153
|
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
|
|
3020
3154
|
bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
|
|
3021
3155
|
HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole);
|
|
3022
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
3156
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
3023
3157
|
} else {
|
|
3024
3158
|
HValue* context = environment()->LookupContext();
|
|
3025
3159
|
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
|
|
@@ -3031,7 +3165,7 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
|
|
3031
3165
|
ast_context()->is_for_typeof());
|
|
3032
3166
|
instr->set_position(expr->position());
|
|
3033
3167
|
ASSERT(instr->HasSideEffects());
|
|
3034
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
3168
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
3035
3169
|
}
|
|
3036
3170
|
} else {
|
|
3037
3171
|
return Bailout("reference to a variable which requires dynamic lookup");
|
|
@@ -3045,7 +3179,7 @@ void HGraphBuilder::VisitLiteral(Literal* expr) {
|
|
|
3045
3179
|
ASSERT(current_block()->HasPredecessor());
|
|
3046
3180
|
HConstant* instr =
|
|
3047
3181
|
new(zone()) HConstant(expr->handle(), Representation::Tagged());
|
|
3048
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
3182
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
3049
3183
|
}
|
|
3050
3184
|
|
|
3051
3185
|
|
|
@@ -3053,10 +3187,13 @@ void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
|
|
|
3053
3187
|
ASSERT(!HasStackOverflow());
|
|
3054
3188
|
ASSERT(current_block() != NULL);
|
|
3055
3189
|
ASSERT(current_block()->HasPredecessor());
|
|
3056
|
-
|
|
3190
|
+
HValue* context = environment()->LookupContext();
|
|
3191
|
+
|
|
3192
|
+
HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context,
|
|
3193
|
+
expr->pattern(),
|
|
3057
3194
|
expr->flags(),
|
|
3058
3195
|
expr->literal_index());
|
|
3059
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
3196
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
3060
3197
|
}
|
|
3061
3198
|
|
|
3062
3199
|
|
|
@@ -3126,9 +3263,9 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|
|
3126
3263
|
// (e.g. because of code motion).
|
|
3127
3264
|
HToFastProperties* result = new(zone()) HToFastProperties(Pop());
|
|
3128
3265
|
AddInstruction(result);
|
|
3129
|
-
ast_context()->ReturnValue(result);
|
|
3266
|
+
return ast_context()->ReturnValue(result);
|
|
3130
3267
|
} else {
|
|
3131
|
-
ast_context()->ReturnValue(Pop());
|
|
3268
|
+
return ast_context()->ReturnValue(Pop());
|
|
3132
3269
|
}
|
|
3133
3270
|
}
|
|
3134
3271
|
|
|
@@ -3139,8 +3276,10 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
|
|
3139
3276
|
ASSERT(current_block()->HasPredecessor());
|
|
3140
3277
|
ZoneList<Expression*>* subexprs = expr->values();
|
|
3141
3278
|
int length = subexprs->length();
|
|
3279
|
+
HValue* context = environment()->LookupContext();
|
|
3142
3280
|
|
|
3143
|
-
HArrayLiteral* literal = new(zone()) HArrayLiteral(
|
|
3281
|
+
HArrayLiteral* literal = new(zone()) HArrayLiteral(context,
|
|
3282
|
+
expr->constant_elements(),
|
|
3144
3283
|
length,
|
|
3145
3284
|
expr->literal_index(),
|
|
3146
3285
|
expr->depth());
|
|
@@ -3162,8 +3301,8 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
|
|
3162
3301
|
|
|
3163
3302
|
// Load the elements array before the first store.
|
|
3164
3303
|
if (elements == NULL) {
|
|
3165
|
-
|
|
3166
|
-
|
|
3304
|
+
elements = new(zone()) HLoadElements(literal);
|
|
3305
|
+
AddInstruction(elements);
|
|
3167
3306
|
}
|
|
3168
3307
|
|
|
3169
3308
|
HValue* key = AddInstruction(
|
|
@@ -3172,15 +3311,7 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
|
|
3172
3311
|
AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value));
|
|
3173
3312
|
AddSimulate(expr->GetIdForElement(i));
|
|
3174
3313
|
}
|
|
3175
|
-
ast_context()->ReturnValue(Pop());
|
|
3176
|
-
}
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
|
|
3180
|
-
ASSERT(!HasStackOverflow());
|
|
3181
|
-
ASSERT(current_block() != NULL);
|
|
3182
|
-
ASSERT(current_block()->HasPredecessor());
|
|
3183
|
-
return Bailout("CatchExtensionObject");
|
|
3314
|
+
return ast_context()->ReturnValue(Pop());
|
|
3184
3315
|
}
|
|
3185
3316
|
|
|
3186
3317
|
|
|
@@ -3267,7 +3398,7 @@ HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
|
|
|
3267
3398
|
ASSERT(!name.is_null());
|
|
3268
3399
|
|
|
3269
3400
|
LookupResult lookup;
|
|
3270
|
-
|
|
3401
|
+
SmallMapList* types = expr->GetReceiverTypes();
|
|
3271
3402
|
bool is_monomorphic = expr->IsMonomorphic() &&
|
|
3272
3403
|
ComputeStoredField(types->first(), name, &lookup);
|
|
3273
3404
|
|
|
@@ -3281,7 +3412,7 @@ HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
|
|
|
3281
3412
|
void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
|
|
3282
3413
|
HValue* object,
|
|
3283
3414
|
HValue* value,
|
|
3284
|
-
|
|
3415
|
+
SmallMapList* types,
|
|
3285
3416
|
Handle<String> name) {
|
|
3286
3417
|
// TODO(ager): We should recognize when the prototype chains for different
|
|
3287
3418
|
// maps are identical. In that case we can avoid repeatedly generating the
|
|
@@ -3342,15 +3473,14 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
|
|
|
3342
3473
|
Drop(1);
|
|
3343
3474
|
}
|
|
3344
3475
|
}
|
|
3345
|
-
ast_context()->ReturnValue(value);
|
|
3346
|
-
return;
|
|
3476
|
+
return ast_context()->ReturnValue(value);
|
|
3347
3477
|
}
|
|
3348
3478
|
}
|
|
3349
3479
|
|
|
3350
3480
|
ASSERT(join != NULL);
|
|
3351
3481
|
join->SetJoinId(expr->id());
|
|
3352
3482
|
set_current_block(join);
|
|
3353
|
-
if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
|
|
3483
|
+
if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
|
|
3354
3484
|
}
|
|
3355
3485
|
|
|
3356
3486
|
|
|
@@ -3373,7 +3503,7 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
|
|
|
3373
3503
|
Handle<String> name = Handle<String>::cast(key->handle());
|
|
3374
3504
|
ASSERT(!name.is_null());
|
|
3375
3505
|
|
|
3376
|
-
|
|
3506
|
+
SmallMapList* types = expr->GetReceiverTypes();
|
|
3377
3507
|
LookupResult lookup;
|
|
3378
3508
|
|
|
3379
3509
|
if (expr->IsMonomorphic()) {
|
|
@@ -3394,13 +3524,21 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
|
|
|
3394
3524
|
value = Pop();
|
|
3395
3525
|
HValue* key = Pop();
|
|
3396
3526
|
HValue* object = Pop();
|
|
3397
|
-
|
|
3527
|
+
bool has_side_effects = false;
|
|
3528
|
+
HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(),
|
|
3529
|
+
expr->position(),
|
|
3530
|
+
true, // is_store
|
|
3531
|
+
&has_side_effects);
|
|
3532
|
+
Push(value);
|
|
3533
|
+
ASSERT(has_side_effects); // Stores always have side effects.
|
|
3534
|
+
AddSimulate(expr->AssignmentId());
|
|
3535
|
+
return ast_context()->ReturnValue(Pop());
|
|
3398
3536
|
}
|
|
3399
3537
|
Push(value);
|
|
3400
3538
|
instr->set_position(expr->position());
|
|
3401
3539
|
AddInstruction(instr);
|
|
3402
3540
|
if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
|
|
3403
|
-
ast_context()->ReturnValue(Pop());
|
|
3541
|
+
return ast_context()->ReturnValue(Pop());
|
|
3404
3542
|
}
|
|
3405
3543
|
|
|
3406
3544
|
|
|
@@ -3451,6 +3589,11 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
|
|
3451
3589
|
BinaryOperation* operation = expr->binary_operation();
|
|
3452
3590
|
|
|
3453
3591
|
if (var != NULL) {
|
|
3592
|
+
if (var->mode() == Variable::CONST ||
|
|
3593
|
+
var->mode() == Variable::LET) {
|
|
3594
|
+
return Bailout("unsupported let or const compound assignment");
|
|
3595
|
+
}
|
|
3596
|
+
|
|
3454
3597
|
CHECK_ALIVE(VisitForValue(operation));
|
|
3455
3598
|
|
|
3456
3599
|
if (var->is_global()) {
|
|
@@ -3461,6 +3604,20 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
|
|
3461
3604
|
} else if (var->IsStackAllocated()) {
|
|
3462
3605
|
Bind(var, Top());
|
|
3463
3606
|
} else if (var->IsContextSlot()) {
|
|
3607
|
+
// Bail out if we try to mutate a parameter value in a function using
|
|
3608
|
+
// the arguments object. We do not (yet) correctly handle the
|
|
3609
|
+
// arguments property of the function.
|
|
3610
|
+
if (info()->scope()->arguments() != NULL) {
|
|
3611
|
+
// Parameters will rewrite to context slots. We have no direct way
|
|
3612
|
+
// to detect that the variable is a parameter.
|
|
3613
|
+
int count = info()->scope()->num_parameters();
|
|
3614
|
+
for (int i = 0; i < count; ++i) {
|
|
3615
|
+
if (var == info()->scope()->parameter(i)) {
|
|
3616
|
+
Bailout("assignment to parameter, function uses arguments object");
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
|
|
3464
3621
|
HValue* context = BuildContextChainWalk(var);
|
|
3465
3622
|
int index = var->AsSlot()->index();
|
|
3466
3623
|
HStoreContextSlot* instr =
|
|
@@ -3470,7 +3627,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
|
|
3470
3627
|
} else {
|
|
3471
3628
|
return Bailout("compound assignment to lookup slot");
|
|
3472
3629
|
}
|
|
3473
|
-
ast_context()->ReturnValue(Pop());
|
|
3630
|
+
return ast_context()->ReturnValue(Pop());
|
|
3474
3631
|
|
|
3475
3632
|
} else if (prop != NULL) {
|
|
3476
3633
|
prop->RecordTypeFeedback(oracle());
|
|
@@ -3505,7 +3662,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
|
|
3505
3662
|
Drop(2);
|
|
3506
3663
|
Push(instr);
|
|
3507
3664
|
if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
|
|
3508
|
-
ast_context()->ReturnValue(Pop());
|
|
3665
|
+
return ast_context()->ReturnValue(Pop());
|
|
3509
3666
|
|
|
3510
3667
|
} else {
|
|
3511
3668
|
// Keyed property.
|
|
@@ -3514,9 +3671,14 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
|
|
3514
3671
|
HValue* obj = environment()->ExpressionStackAt(1);
|
|
3515
3672
|
HValue* key = environment()->ExpressionStackAt(0);
|
|
3516
3673
|
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3674
|
+
bool has_side_effects = false;
|
|
3675
|
+
HValue* load = HandleKeyedElementAccess(
|
|
3676
|
+
obj, key, NULL, prop, expr->CompoundLoadId(), RelocInfo::kNoPosition,
|
|
3677
|
+
false, // is_store
|
|
3678
|
+
&has_side_effects);
|
|
3679
|
+
Push(load);
|
|
3680
|
+
if (has_side_effects) AddSimulate(expr->CompoundLoadId());
|
|
3681
|
+
|
|
3520
3682
|
|
|
3521
3683
|
CHECK_ALIVE(VisitForValue(expr->value()));
|
|
3522
3684
|
HValue* right = Pop();
|
|
@@ -3527,13 +3689,17 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
|
|
3527
3689
|
if (instr->HasSideEffects()) AddSimulate(operation->id());
|
|
3528
3690
|
|
|
3529
3691
|
expr->RecordTypeFeedback(oracle());
|
|
3530
|
-
|
|
3531
|
-
|
|
3692
|
+
HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
|
|
3693
|
+
RelocInfo::kNoPosition,
|
|
3694
|
+
true, // is_store
|
|
3695
|
+
&has_side_effects);
|
|
3696
|
+
|
|
3532
3697
|
// Drop the simulated receiver, key, and value. Return the value.
|
|
3533
3698
|
Drop(3);
|
|
3534
3699
|
Push(instr);
|
|
3535
|
-
|
|
3536
|
-
|
|
3700
|
+
ASSERT(has_side_effects); // Stores always have side effects.
|
|
3701
|
+
AddSimulate(expr->AssignmentId());
|
|
3702
|
+
return ast_context()->ReturnValue(Pop());
|
|
3537
3703
|
}
|
|
3538
3704
|
|
|
3539
3705
|
} else {
|
|
@@ -3557,6 +3723,21 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
|
|
|
3557
3723
|
}
|
|
3558
3724
|
|
|
3559
3725
|
if (var != NULL) {
|
|
3726
|
+
if (var->mode() == Variable::CONST) {
|
|
3727
|
+
if (expr->op() != Token::INIT_CONST) {
|
|
3728
|
+
return Bailout("non-initializer assignment to const");
|
|
3729
|
+
}
|
|
3730
|
+
if (!var->IsStackAllocated()) {
|
|
3731
|
+
return Bailout("assignment to const context slot");
|
|
3732
|
+
}
|
|
3733
|
+
// We insert a use of the old value to detect unsupported uses of const
|
|
3734
|
+
// variables (e.g. initialization inside a loop).
|
|
3735
|
+
HValue* old_value = environment()->Lookup(var);
|
|
3736
|
+
AddInstruction(new HUseConst(old_value));
|
|
3737
|
+
} else if (var->mode() == Variable::LET) {
|
|
3738
|
+
return Bailout("unsupported assignment to let");
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3560
3741
|
if (proxy->IsArguments()) return Bailout("assignment to arguments");
|
|
3561
3742
|
|
|
3562
3743
|
// Handle the assignment.
|
|
@@ -3567,9 +3748,24 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
|
|
|
3567
3748
|
CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
|
|
3568
3749
|
HValue* value = Pop();
|
|
3569
3750
|
Bind(var, value);
|
|
3570
|
-
ast_context()->ReturnValue(value);
|
|
3751
|
+
return ast_context()->ReturnValue(value);
|
|
3752
|
+
|
|
3753
|
+
} else if (var->IsContextSlot()) {
|
|
3754
|
+
ASSERT(var->mode() != Variable::CONST);
|
|
3755
|
+
// Bail out if we try to mutate a parameter value in a function using
|
|
3756
|
+
// the arguments object. We do not (yet) correctly handle the
|
|
3757
|
+
// arguments property of the function.
|
|
3758
|
+
if (info()->scope()->arguments() != NULL) {
|
|
3759
|
+
// Parameters will rewrite to context slots. We have no direct way
|
|
3760
|
+
// to detect that the variable is a parameter.
|
|
3761
|
+
int count = info()->scope()->num_parameters();
|
|
3762
|
+
for (int i = 0; i < count; ++i) {
|
|
3763
|
+
if (var == info()->scope()->parameter(i)) {
|
|
3764
|
+
Bailout("assignment to parameter, function uses arguments object");
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3571
3768
|
|
|
3572
|
-
} else if (var->IsContextSlot() && var->mode() != Variable::CONST) {
|
|
3573
3769
|
CHECK_ALIVE(VisitForValue(expr->value()));
|
|
3574
3770
|
HValue* context = BuildContextChainWalk(var);
|
|
3575
3771
|
int index = var->AsSlot()->index();
|
|
@@ -3577,7 +3773,7 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
|
|
|
3577
3773
|
new(zone()) HStoreContextSlot(context, index, Top());
|
|
3578
3774
|
AddInstruction(instr);
|
|
3579
3775
|
if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
|
|
3580
|
-
ast_context()->ReturnValue(Pop());
|
|
3776
|
+
return ast_context()->ReturnValue(Pop());
|
|
3581
3777
|
|
|
3582
3778
|
} else if (var->is_global()) {
|
|
3583
3779
|
CHECK_ALIVE(VisitForValue(expr->value()));
|
|
@@ -3585,7 +3781,7 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
|
|
|
3585
3781
|
Top(),
|
|
3586
3782
|
expr->position(),
|
|
3587
3783
|
expr->AssignmentId());
|
|
3588
|
-
ast_context()->ReturnValue(Pop());
|
|
3784
|
+
return ast_context()->ReturnValue(Pop());
|
|
3589
3785
|
|
|
3590
3786
|
} else {
|
|
3591
3787
|
return Bailout("assignment to LOOKUP or const CONTEXT variable");
|
|
@@ -3609,8 +3805,9 @@ void HGraphBuilder::VisitThrow(Throw* expr) {
|
|
|
3609
3805
|
ASSERT(ast_context()->IsEffect());
|
|
3610
3806
|
CHECK_ALIVE(VisitForValue(expr->exception()));
|
|
3611
3807
|
|
|
3808
|
+
HValue* context = environment()->LookupContext();
|
|
3612
3809
|
HValue* value = environment()->Pop();
|
|
3613
|
-
HThrow* instr = new(zone()) HThrow(value);
|
|
3810
|
+
HThrow* instr = new(zone()) HThrow(context, value);
|
|
3614
3811
|
instr->set_position(expr->position());
|
|
3615
3812
|
AddInstruction(instr);
|
|
3616
3813
|
AddSimulate(expr->id());
|
|
@@ -3682,70 +3879,299 @@ HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
|
|
|
3682
3879
|
}
|
|
3683
3880
|
|
|
3684
3881
|
|
|
3685
|
-
HInstruction* HGraphBuilder::
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3882
|
+
HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
|
|
3883
|
+
HValue* external_elements,
|
|
3884
|
+
HValue* checked_key,
|
|
3885
|
+
HValue* val,
|
|
3886
|
+
JSObject::ElementsKind elements_kind,
|
|
3887
|
+
bool is_store) {
|
|
3888
|
+
if (is_store) {
|
|
3889
|
+
ASSERT(val != NULL);
|
|
3890
|
+
switch (elements_kind) {
|
|
3891
|
+
case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
|
|
3892
|
+
HClampToUint8* clamp = new(zone()) HClampToUint8(val);
|
|
3893
|
+
AddInstruction(clamp);
|
|
3894
|
+
val = clamp;
|
|
3895
|
+
break;
|
|
3896
|
+
}
|
|
3897
|
+
case JSObject::EXTERNAL_BYTE_ELEMENTS:
|
|
3898
|
+
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
|
3899
|
+
case JSObject::EXTERNAL_SHORT_ELEMENTS:
|
|
3900
|
+
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
|
3901
|
+
case JSObject::EXTERNAL_INT_ELEMENTS:
|
|
3902
|
+
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
|
|
3903
|
+
HToInt32* floor_val = new(zone()) HToInt32(val);
|
|
3904
|
+
AddInstruction(floor_val);
|
|
3905
|
+
val = floor_val;
|
|
3906
|
+
break;
|
|
3907
|
+
}
|
|
3908
|
+
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
|
|
3909
|
+
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
|
|
3910
|
+
break;
|
|
3911
|
+
case JSObject::FAST_ELEMENTS:
|
|
3912
|
+
case JSObject::FAST_DOUBLE_ELEMENTS:
|
|
3913
|
+
case JSObject::DICTIONARY_ELEMENTS:
|
|
3914
|
+
case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
|
|
3915
|
+
UNREACHABLE();
|
|
3916
|
+
break;
|
|
3917
|
+
}
|
|
3918
|
+
return new(zone()) HStoreKeyedSpecializedArrayElement(
|
|
3919
|
+
external_elements, checked_key, val, elements_kind);
|
|
3920
|
+
} else {
|
|
3921
|
+
return new(zone()) HLoadKeyedSpecializedArrayElement(
|
|
3922
|
+
external_elements, checked_key, elements_kind);
|
|
3923
|
+
}
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3926
|
+
|
|
3927
|
+
HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
|
|
3928
|
+
HValue* key,
|
|
3929
|
+
HValue* val,
|
|
3930
|
+
Expression* expr,
|
|
3931
|
+
bool is_store) {
|
|
3932
|
+
ASSERT(expr->IsMonomorphic());
|
|
3690
3933
|
Handle<Map> map = expr->GetMonomorphicReceiverType();
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3934
|
+
if (!map->has_fast_elements() &&
|
|
3935
|
+
!map->has_fast_double_elements() &&
|
|
3936
|
+
!map->has_external_array_elements()) {
|
|
3937
|
+
return is_store ? BuildStoreKeyedGeneric(object, key, val)
|
|
3938
|
+
: BuildLoadKeyedGeneric(object, key);
|
|
3939
|
+
}
|
|
3940
|
+
AddInstruction(new(zone()) HCheckNonSmi(object));
|
|
3941
|
+
HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map));
|
|
3942
|
+
HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
|
|
3943
|
+
bool fast_double_elements = map->has_fast_double_elements();
|
|
3944
|
+
if (is_store && map->has_fast_elements()) {
|
|
3945
|
+
AddInstruction(new(zone()) HCheckMap(
|
|
3946
|
+
elements, isolate()->factory()->fixed_array_map()));
|
|
3947
|
+
}
|
|
3695
3948
|
HInstruction* length = NULL;
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
AddInstruction(new(zone())
|
|
3699
|
-
AddInstruction(
|
|
3949
|
+
HInstruction* checked_key = NULL;
|
|
3950
|
+
if (map->has_external_array_elements()) {
|
|
3951
|
+
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
|
|
3952
|
+
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
|
|
3953
|
+
HLoadExternalArrayPointer* external_elements =
|
|
3954
|
+
new(zone()) HLoadExternalArrayPointer(elements);
|
|
3955
|
+
AddInstruction(external_elements);
|
|
3956
|
+
return BuildExternalArrayElementAccess(external_elements, checked_key,
|
|
3957
|
+
val, map->elements_kind(), is_store);
|
|
3958
|
+
}
|
|
3959
|
+
ASSERT(map->has_fast_elements() || fast_double_elements);
|
|
3960
|
+
if (map->instance_type() == JS_ARRAY_TYPE) {
|
|
3961
|
+
length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck));
|
|
3962
|
+
} else {
|
|
3963
|
+
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
|
|
3964
|
+
}
|
|
3965
|
+
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
|
|
3966
|
+
if (is_store) {
|
|
3967
|
+
if (fast_double_elements) {
|
|
3968
|
+
return new(zone()) HStoreKeyedFastDoubleElement(elements,
|
|
3969
|
+
checked_key,
|
|
3970
|
+
val);
|
|
3971
|
+
} else {
|
|
3972
|
+
return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
|
|
3973
|
+
}
|
|
3700
3974
|
} else {
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3975
|
+
if (fast_double_elements) {
|
|
3976
|
+
return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key);
|
|
3977
|
+
} else {
|
|
3978
|
+
return new(zone()) HLoadKeyedFastElement(elements, checked_key);
|
|
3979
|
+
}
|
|
3704
3980
|
}
|
|
3705
|
-
return new(zone()) HLoadKeyedFastElement(elements, key);
|
|
3706
3981
|
}
|
|
3707
3982
|
|
|
3708
3983
|
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3984
|
+
HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
|
|
3985
|
+
HValue* key,
|
|
3986
|
+
HValue* val,
|
|
3987
|
+
Expression* prop,
|
|
3988
|
+
int ast_id,
|
|
3989
|
+
int position,
|
|
3990
|
+
bool is_store,
|
|
3991
|
+
bool* has_side_effects) {
|
|
3992
|
+
*has_side_effects = false;
|
|
3714
3993
|
AddInstruction(new(zone()) HCheckNonSmi(object));
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3994
|
+
AddInstruction(HCheckInstanceType::NewIsSpecObject(object));
|
|
3995
|
+
SmallMapList* maps = prop->GetReceiverTypes();
|
|
3996
|
+
bool todo_external_array = false;
|
|
3997
|
+
|
|
3998
|
+
static const int kNumElementTypes = JSObject::kElementsKindCount;
|
|
3999
|
+
bool type_todo[kNumElementTypes];
|
|
4000
|
+
for (int i = 0; i < kNumElementTypes; ++i) {
|
|
4001
|
+
type_todo[i] = false;
|
|
4002
|
+
}
|
|
4003
|
+
|
|
4004
|
+
for (int i = 0; i < maps->length(); ++i) {
|
|
4005
|
+
ASSERT(maps->at(i)->IsMap());
|
|
4006
|
+
type_todo[maps->at(i)->elements_kind()] = true;
|
|
4007
|
+
if (maps->at(i)->elements_kind()
|
|
4008
|
+
>= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
|
|
4009
|
+
todo_external_array = true;
|
|
4010
|
+
}
|
|
4011
|
+
}
|
|
4012
|
+
|
|
4013
|
+
HBasicBlock* join = graph()->CreateBasicBlock();
|
|
4014
|
+
|
|
4015
|
+
HInstruction* elements_kind_instr =
|
|
4016
|
+
AddInstruction(new(zone()) HElementsKind(object));
|
|
4017
|
+
HCompareConstantEqAndBranch* elements_kind_branch = NULL;
|
|
4018
|
+
HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
|
|
4019
|
+
HLoadExternalArrayPointer* external_elements = NULL;
|
|
4020
|
+
HInstruction* checked_key = NULL;
|
|
4021
|
+
|
|
4022
|
+
// FAST_ELEMENTS is assumed to be the first case.
|
|
4023
|
+
STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
|
|
4024
|
+
|
|
4025
|
+
for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS;
|
|
4026
|
+
elements_kind <= JSObject::LAST_ELEMENTS_KIND;
|
|
4027
|
+
elements_kind = JSObject::ElementsKind(elements_kind + 1)) {
|
|
4028
|
+
// After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we
|
|
4029
|
+
// need to add some code that's executed for all external array cases.
|
|
4030
|
+
STATIC_ASSERT(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
|
|
4031
|
+
JSObject::LAST_ELEMENTS_KIND);
|
|
4032
|
+
if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
|
|
4033
|
+
&& todo_external_array) {
|
|
4034
|
+
HInstruction* length =
|
|
4035
|
+
AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
|
|
4036
|
+
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
|
|
4037
|
+
external_elements = new(zone()) HLoadExternalArrayPointer(elements);
|
|
4038
|
+
AddInstruction(external_elements);
|
|
4039
|
+
}
|
|
4040
|
+
if (type_todo[elements_kind]) {
|
|
4041
|
+
HBasicBlock* if_true = graph()->CreateBasicBlock();
|
|
4042
|
+
HBasicBlock* if_false = graph()->CreateBasicBlock();
|
|
4043
|
+
elements_kind_branch = new(zone()) HCompareConstantEqAndBranch(
|
|
4044
|
+
elements_kind_instr, elements_kind, Token::EQ_STRICT);
|
|
4045
|
+
elements_kind_branch->SetSuccessorAt(0, if_true);
|
|
4046
|
+
elements_kind_branch->SetSuccessorAt(1, if_false);
|
|
4047
|
+
current_block()->Finish(elements_kind_branch);
|
|
4048
|
+
|
|
4049
|
+
set_current_block(if_true);
|
|
4050
|
+
HInstruction* access;
|
|
4051
|
+
if (elements_kind == JSObject::FAST_ELEMENTS ||
|
|
4052
|
+
elements_kind == JSObject::FAST_DOUBLE_ELEMENTS) {
|
|
4053
|
+
bool fast_double_elements =
|
|
4054
|
+
elements_kind == JSObject::FAST_DOUBLE_ELEMENTS;
|
|
4055
|
+
if (is_store && elements_kind == JSObject::FAST_ELEMENTS) {
|
|
4056
|
+
AddInstruction(new(zone()) HCheckMap(
|
|
4057
|
+
elements, isolate()->factory()->fixed_array_map(),
|
|
4058
|
+
elements_kind_branch));
|
|
4059
|
+
}
|
|
4060
|
+
HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
|
|
4061
|
+
HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
|
|
4062
|
+
HHasInstanceTypeAndBranch* typecheck =
|
|
4063
|
+
new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE);
|
|
4064
|
+
typecheck->SetSuccessorAt(0, if_jsarray);
|
|
4065
|
+
typecheck->SetSuccessorAt(1, if_fastobject);
|
|
4066
|
+
current_block()->Finish(typecheck);
|
|
4067
|
+
|
|
4068
|
+
set_current_block(if_jsarray);
|
|
4069
|
+
HInstruction* length = new(zone()) HJSArrayLength(object, typecheck);
|
|
4070
|
+
AddInstruction(length);
|
|
4071
|
+
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
|
|
4072
|
+
if (is_store) {
|
|
4073
|
+
if (fast_double_elements) {
|
|
4074
|
+
access = AddInstruction(
|
|
4075
|
+
new(zone()) HStoreKeyedFastDoubleElement(elements,
|
|
4076
|
+
checked_key,
|
|
4077
|
+
val));
|
|
4078
|
+
} else {
|
|
4079
|
+
access = AddInstruction(
|
|
4080
|
+
new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
|
|
4081
|
+
}
|
|
4082
|
+
} else {
|
|
4083
|
+
if (fast_double_elements) {
|
|
4084
|
+
access = AddInstruction(
|
|
4085
|
+
new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key));
|
|
4086
|
+
} else {
|
|
4087
|
+
access = AddInstruction(
|
|
4088
|
+
new(zone()) HLoadKeyedFastElement(elements, checked_key));
|
|
4089
|
+
}
|
|
4090
|
+
Push(access);
|
|
4091
|
+
}
|
|
4092
|
+
*has_side_effects |= access->HasSideEffects();
|
|
4093
|
+
if (position != -1) {
|
|
4094
|
+
access->set_position(position);
|
|
4095
|
+
}
|
|
4096
|
+
if_jsarray->Goto(join);
|
|
4097
|
+
|
|
4098
|
+
set_current_block(if_fastobject);
|
|
4099
|
+
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
|
|
4100
|
+
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
|
|
4101
|
+
if (is_store) {
|
|
4102
|
+
if (fast_double_elements) {
|
|
4103
|
+
access = AddInstruction(
|
|
4104
|
+
new(zone()) HStoreKeyedFastDoubleElement(elements,
|
|
4105
|
+
checked_key,
|
|
4106
|
+
val));
|
|
4107
|
+
} else {
|
|
4108
|
+
access = AddInstruction(
|
|
4109
|
+
new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
|
|
4110
|
+
}
|
|
4111
|
+
} else {
|
|
4112
|
+
if (fast_double_elements) {
|
|
4113
|
+
access = AddInstruction(
|
|
4114
|
+
new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key));
|
|
4115
|
+
} else {
|
|
4116
|
+
access = AddInstruction(
|
|
4117
|
+
new(zone()) HLoadKeyedFastElement(elements, checked_key));
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
} else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) {
|
|
4121
|
+
if (is_store) {
|
|
4122
|
+
access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
|
|
4123
|
+
} else {
|
|
4124
|
+
access = AddInstruction(BuildLoadKeyedGeneric(object, key));
|
|
4125
|
+
}
|
|
4126
|
+
} else { // External array elements.
|
|
4127
|
+
access = AddInstruction(BuildExternalArrayElementAccess(
|
|
4128
|
+
external_elements, checked_key, val, elements_kind, is_store));
|
|
4129
|
+
}
|
|
4130
|
+
*has_side_effects |= access->HasSideEffects();
|
|
4131
|
+
access->set_position(position);
|
|
4132
|
+
if (!is_store) {
|
|
4133
|
+
Push(access);
|
|
4134
|
+
}
|
|
4135
|
+
current_block()->Goto(join);
|
|
4136
|
+
set_current_block(if_false);
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
|
|
4140
|
+
// Deopt if none of the cases matched.
|
|
4141
|
+
current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
|
|
4142
|
+
join->SetJoinId(ast_id);
|
|
4143
|
+
set_current_block(join);
|
|
4144
|
+
return is_store ? NULL : Pop();
|
|
3731
4145
|
}
|
|
3732
4146
|
|
|
3733
4147
|
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
4148
|
+
HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj,
|
|
4149
|
+
HValue* key,
|
|
4150
|
+
HValue* val,
|
|
4151
|
+
Expression* expr,
|
|
4152
|
+
int ast_id,
|
|
4153
|
+
int position,
|
|
4154
|
+
bool is_store,
|
|
4155
|
+
bool* has_side_effects) {
|
|
4156
|
+
ASSERT(!expr->IsPropertyName());
|
|
4157
|
+
HInstruction* instr = NULL;
|
|
4158
|
+
if (expr->IsMonomorphic()) {
|
|
4159
|
+
instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store);
|
|
4160
|
+
} else if (expr->GetReceiverTypes() != NULL &&
|
|
4161
|
+
!expr->GetReceiverTypes()->is_empty()) {
|
|
4162
|
+
return HandlePolymorphicElementAccess(
|
|
4163
|
+
obj, key, val, expr, ast_id, position, is_store, has_side_effects);
|
|
4164
|
+
} else {
|
|
4165
|
+
if (is_store) {
|
|
4166
|
+
instr = BuildStoreKeyedGeneric(obj, key, val);
|
|
4167
|
+
} else {
|
|
4168
|
+
instr = BuildLoadKeyedGeneric(obj, key);
|
|
3746
4169
|
}
|
|
3747
4170
|
}
|
|
3748
|
-
|
|
4171
|
+
instr->set_position(position);
|
|
4172
|
+
AddInstruction(instr);
|
|
4173
|
+
*has_side_effects = instr->HasSideEffects();
|
|
4174
|
+
return instr;
|
|
3749
4175
|
}
|
|
3750
4176
|
|
|
3751
4177
|
|
|
@@ -3761,85 +4187,6 @@ HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
|
|
|
3761
4187
|
function_strict_mode());
|
|
3762
4188
|
}
|
|
3763
4189
|
|
|
3764
|
-
|
|
3765
|
-
HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
|
|
3766
|
-
HValue* key,
|
|
3767
|
-
HValue* val,
|
|
3768
|
-
Expression* expr) {
|
|
3769
|
-
ASSERT(expr->IsMonomorphic());
|
|
3770
|
-
AddInstruction(new(zone()) HCheckNonSmi(object));
|
|
3771
|
-
Handle<Map> map = expr->GetMonomorphicReceiverType();
|
|
3772
|
-
ASSERT(map->has_fast_elements());
|
|
3773
|
-
AddInstruction(new(zone()) HCheckMap(object, map));
|
|
3774
|
-
HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
|
|
3775
|
-
AddInstruction(new(zone()) HCheckMap(
|
|
3776
|
-
elements, isolate()->factory()->fixed_array_map()));
|
|
3777
|
-
bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
|
|
3778
|
-
HInstruction* length = NULL;
|
|
3779
|
-
if (is_array) {
|
|
3780
|
-
length = AddInstruction(new(zone()) HJSArrayLength(object));
|
|
3781
|
-
} else {
|
|
3782
|
-
length = AddInstruction(new(zone()) HFixedArrayLength(elements));
|
|
3783
|
-
}
|
|
3784
|
-
AddInstruction(new(zone()) HBoundsCheck(key, length));
|
|
3785
|
-
return new(zone()) HStoreKeyedFastElement(elements, key, val);
|
|
3786
|
-
}
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement(
|
|
3790
|
-
HValue* object,
|
|
3791
|
-
HValue* key,
|
|
3792
|
-
HValue* val,
|
|
3793
|
-
Expression* expr) {
|
|
3794
|
-
ASSERT(expr->IsMonomorphic());
|
|
3795
|
-
AddInstruction(new(zone()) HCheckNonSmi(object));
|
|
3796
|
-
Handle<Map> map = expr->GetMonomorphicReceiverType();
|
|
3797
|
-
ASSERT(!map->has_fast_elements());
|
|
3798
|
-
ASSERT(map->has_external_array_elements());
|
|
3799
|
-
AddInstruction(new(zone()) HCheckMap(object, map));
|
|
3800
|
-
HLoadElements* elements = new(zone()) HLoadElements(object);
|
|
3801
|
-
AddInstruction(elements);
|
|
3802
|
-
HInstruction* length = AddInstruction(
|
|
3803
|
-
new(zone()) HExternalArrayLength(elements));
|
|
3804
|
-
AddInstruction(new(zone()) HBoundsCheck(key, length));
|
|
3805
|
-
HLoadExternalArrayPointer* external_elements =
|
|
3806
|
-
new(zone()) HLoadExternalArrayPointer(elements);
|
|
3807
|
-
AddInstruction(external_elements);
|
|
3808
|
-
if (expr->external_array_type() == kExternalPixelArray) {
|
|
3809
|
-
HClampToUint8* clamp = new(zone()) HClampToUint8(val);
|
|
3810
|
-
AddInstruction(clamp);
|
|
3811
|
-
val = clamp;
|
|
3812
|
-
}
|
|
3813
|
-
return new(zone()) HStoreKeyedSpecializedArrayElement(
|
|
3814
|
-
external_elements,
|
|
3815
|
-
key,
|
|
3816
|
-
val,
|
|
3817
|
-
expr->external_array_type());
|
|
3818
|
-
}
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object,
|
|
3822
|
-
HValue* key,
|
|
3823
|
-
HValue* value,
|
|
3824
|
-
Expression* expr) {
|
|
3825
|
-
if (expr->IsMonomorphic()) {
|
|
3826
|
-
Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
|
|
3827
|
-
// An object has either fast elements or external array elements, but
|
|
3828
|
-
// never both. Pixel array maps that are assigned to pixel array elements
|
|
3829
|
-
// are always created with the fast elements flag cleared.
|
|
3830
|
-
if (receiver_type->has_external_array_elements()) {
|
|
3831
|
-
return BuildStoreKeyedSpecializedArrayElement(object,
|
|
3832
|
-
key,
|
|
3833
|
-
value,
|
|
3834
|
-
expr);
|
|
3835
|
-
} else if (receiver_type->has_fast_elements()) {
|
|
3836
|
-
return BuildStoreKeyedFastElement(object, key, value, expr);
|
|
3837
|
-
}
|
|
3838
|
-
}
|
|
3839
|
-
return BuildStoreKeyedGeneric(object, key, value);
|
|
3840
|
-
}
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
4190
|
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
|
|
3844
4191
|
VariableProxy* proxy = expr->obj()->AsVariableProxy();
|
|
3845
4192
|
if (proxy == NULL) return false;
|
|
@@ -3848,6 +4195,13 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
|
|
|
3848
4195
|
return false;
|
|
3849
4196
|
}
|
|
3850
4197
|
|
|
4198
|
+
// Our implementation of arguments (based on this stack frame or an
|
|
4199
|
+
// adapter below it) does not work for inlined functions.
|
|
4200
|
+
if (function_state()->outer() != NULL) {
|
|
4201
|
+
Bailout("arguments access in inlined function");
|
|
4202
|
+
return true;
|
|
4203
|
+
}
|
|
4204
|
+
|
|
3851
4205
|
HInstruction* result = NULL;
|
|
3852
4206
|
if (expr->key()->IsPropertyName()) {
|
|
3853
4207
|
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
|
|
@@ -3863,8 +4217,9 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
|
|
|
3863
4217
|
HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
|
|
3864
4218
|
HInstruction* length = AddInstruction(
|
|
3865
4219
|
new(zone()) HArgumentsLength(elements));
|
|
3866
|
-
|
|
3867
|
-
|
|
4220
|
+
HInstruction* checked_key =
|
|
4221
|
+
AddInstruction(new(zone()) HBoundsCheck(key, length));
|
|
4222
|
+
result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
|
|
3868
4223
|
}
|
|
3869
4224
|
ast_context()->ReturnInstruction(result, expr->id());
|
|
3870
4225
|
return true;
|
|
@@ -3885,8 +4240,9 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
|
|
3885
4240
|
if (expr->IsArrayLength()) {
|
|
3886
4241
|
HValue* array = Pop();
|
|
3887
4242
|
AddInstruction(new(zone()) HCheckNonSmi(array));
|
|
3888
|
-
|
|
3889
|
-
|
|
4243
|
+
HInstruction* mapcheck =
|
|
4244
|
+
AddInstruction(HCheckInstanceType::NewIsJSArray(array));
|
|
4245
|
+
instr = new(zone()) HJSArrayLength(array, mapcheck);
|
|
3890
4246
|
|
|
3891
4247
|
} else if (expr->IsStringLength()) {
|
|
3892
4248
|
HValue* string = Pop();
|
|
@@ -3897,9 +4253,11 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
|
|
3897
4253
|
CHECK_ALIVE(VisitForValue(expr->key()));
|
|
3898
4254
|
HValue* index = Pop();
|
|
3899
4255
|
HValue* string = Pop();
|
|
3900
|
-
|
|
4256
|
+
HValue* context = environment()->LookupContext();
|
|
4257
|
+
HStringCharCodeAt* char_code =
|
|
4258
|
+
BuildStringCharCodeAt(context, string, index);
|
|
3901
4259
|
AddInstruction(char_code);
|
|
3902
|
-
instr = new(zone()) HStringCharFromCode(char_code);
|
|
4260
|
+
instr = new(zone()) HStringCharFromCode(context, char_code);
|
|
3903
4261
|
|
|
3904
4262
|
} else if (expr->IsFunctionPrototype()) {
|
|
3905
4263
|
HValue* function = Pop();
|
|
@@ -3908,14 +4266,15 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
|
|
3908
4266
|
|
|
3909
4267
|
} else if (expr->key()->IsPropertyName()) {
|
|
3910
4268
|
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
|
|
3911
|
-
|
|
4269
|
+
SmallMapList* types = expr->GetReceiverTypes();
|
|
3912
4270
|
|
|
3913
4271
|
HValue* obj = Pop();
|
|
3914
4272
|
if (expr->IsMonomorphic()) {
|
|
3915
4273
|
instr = BuildLoadNamed(obj, expr, types->first(), name);
|
|
3916
4274
|
} else if (types != NULL && types->length() > 1) {
|
|
3917
4275
|
AddInstruction(new(zone()) HCheckNonSmi(obj));
|
|
3918
|
-
|
|
4276
|
+
HValue* context = environment()->LookupContext();
|
|
4277
|
+
instr = new(zone()) HLoadNamedFieldPolymorphic(context, obj, types, name);
|
|
3919
4278
|
} else {
|
|
3920
4279
|
instr = BuildLoadNamedGeneric(obj, expr);
|
|
3921
4280
|
}
|
|
@@ -3925,10 +4284,25 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
|
|
3925
4284
|
|
|
3926
4285
|
HValue* key = Pop();
|
|
3927
4286
|
HValue* obj = Pop();
|
|
3928
|
-
|
|
4287
|
+
|
|
4288
|
+
bool has_side_effects = false;
|
|
4289
|
+
HValue* load = HandleKeyedElementAccess(
|
|
4290
|
+
obj, key, NULL, expr, expr->id(), expr->position(),
|
|
4291
|
+
false, // is_store
|
|
4292
|
+
&has_side_effects);
|
|
4293
|
+
if (has_side_effects) {
|
|
4294
|
+
if (ast_context()->IsEffect()) {
|
|
4295
|
+
AddSimulate(expr->id());
|
|
4296
|
+
} else {
|
|
4297
|
+
Push(load);
|
|
4298
|
+
AddSimulate(expr->id());
|
|
4299
|
+
Drop(1);
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4302
|
+
return ast_context()->ReturnValue(load);
|
|
3929
4303
|
}
|
|
3930
4304
|
instr->set_position(expr->position());
|
|
3931
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
4305
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
3932
4306
|
}
|
|
3933
4307
|
|
|
3934
4308
|
|
|
@@ -3953,7 +4327,7 @@ void HGraphBuilder::AddCheckConstantFunction(Call* expr,
|
|
|
3953
4327
|
|
|
3954
4328
|
void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
|
|
3955
4329
|
HValue* receiver,
|
|
3956
|
-
|
|
4330
|
+
SmallMapList* types,
|
|
3957
4331
|
Handle<String> name) {
|
|
3958
4332
|
// TODO(ager): We should recognize when the prototype chains for different
|
|
3959
4333
|
// maps are identical. In that case we can avoid repeatedly generating the
|
|
@@ -4016,8 +4390,7 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
|
|
|
4016
4390
|
if (!ast_context()->IsEffect()) Push(call);
|
|
4017
4391
|
current_block()->Goto(join);
|
|
4018
4392
|
} else {
|
|
4019
|
-
ast_context()->ReturnInstruction(call, expr->id());
|
|
4020
|
-
return;
|
|
4393
|
+
return ast_context()->ReturnInstruction(call, expr->id());
|
|
4021
4394
|
}
|
|
4022
4395
|
}
|
|
4023
4396
|
|
|
@@ -4028,7 +4401,7 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
|
|
|
4028
4401
|
if (join->HasPredecessor()) {
|
|
4029
4402
|
set_current_block(join);
|
|
4030
4403
|
join->SetJoinId(expr->id());
|
|
4031
|
-
if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
|
|
4404
|
+
if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
|
|
4032
4405
|
} else {
|
|
4033
4406
|
set_current_block(NULL);
|
|
4034
4407
|
}
|
|
@@ -4140,14 +4513,6 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
|
4140
4513
|
return false;
|
|
4141
4514
|
}
|
|
4142
4515
|
|
|
4143
|
-
// Check if we can handle all declarations in the inlined functions.
|
|
4144
|
-
VisitDeclarations(target_info.scope()->declarations());
|
|
4145
|
-
if (HasStackOverflow()) {
|
|
4146
|
-
TraceInline(target, caller, "target has non-trivial declaration");
|
|
4147
|
-
ClearStackOverflow();
|
|
4148
|
-
return false;
|
|
4149
|
-
}
|
|
4150
|
-
|
|
4151
4516
|
// Don't inline functions that uses the arguments object or that
|
|
4152
4517
|
// have a mismatching number of parameters.
|
|
4153
4518
|
int arity = expr->arguments()->length();
|
|
@@ -4157,6 +4522,15 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
|
4157
4522
|
return false;
|
|
4158
4523
|
}
|
|
4159
4524
|
|
|
4525
|
+
// All declarations must be inlineable.
|
|
4526
|
+
ZoneList<Declaration*>* decls = target_info.scope()->declarations();
|
|
4527
|
+
int decl_count = decls->length();
|
|
4528
|
+
for (int i = 0; i < decl_count; ++i) {
|
|
4529
|
+
if (!decls->at(i)->IsInlineable()) {
|
|
4530
|
+
TraceInline(target, caller, "target has non-trivial declaration");
|
|
4531
|
+
return false;
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4160
4534
|
// All statements in the body must be inlineable.
|
|
4161
4535
|
for (int i = 0, count = function->body()->length(); i < count; ++i) {
|
|
4162
4536
|
if (!function->body()->at(i)->IsInlineable()) {
|
|
@@ -4175,6 +4549,13 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
|
4175
4549
|
TraceInline(target, caller, "could not generate deoptimization info");
|
|
4176
4550
|
return false;
|
|
4177
4551
|
}
|
|
4552
|
+
if (target_shared->scope_info() == SerializedScopeInfo::Empty()) {
|
|
4553
|
+
// The scope info might not have been set if a lazily compiled
|
|
4554
|
+
// function is inlined before being called for the first time.
|
|
4555
|
+
Handle<SerializedScopeInfo> target_scope_info =
|
|
4556
|
+
SerializedScopeInfo::Create(target_info.scope());
|
|
4557
|
+
target_shared->set_scope_info(*target_scope_info);
|
|
4558
|
+
}
|
|
4178
4559
|
target_shared->EnableDeoptimizationSupport(*target_info.code());
|
|
4179
4560
|
Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG,
|
|
4180
4561
|
&target_info,
|
|
@@ -4182,6 +4563,9 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
|
4182
4563
|
}
|
|
4183
4564
|
|
|
4184
4565
|
// ----------------------------------------------------------------
|
|
4566
|
+
// After this point, we've made a decision to inline this function (so
|
|
4567
|
+
// TryInline should always return true).
|
|
4568
|
+
|
|
4185
4569
|
// Save the pending call context and type feedback oracle. Set up new ones
|
|
4186
4570
|
// for the inlined function.
|
|
4187
4571
|
ASSERT(target_shared->has_deoptimization_support());
|
|
@@ -4194,17 +4578,16 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
|
4194
4578
|
HEnvironment* inner_env =
|
|
4195
4579
|
environment()->CopyForInlining(target,
|
|
4196
4580
|
function,
|
|
4197
|
-
HEnvironment::HYDROGEN,
|
|
4198
4581
|
undefined,
|
|
4199
4582
|
call_kind);
|
|
4200
4583
|
HBasicBlock* body_entry = CreateBasicBlock(inner_env);
|
|
4201
4584
|
current_block()->Goto(body_entry);
|
|
4202
|
-
|
|
4203
4585
|
body_entry->SetJoinId(expr->ReturnId());
|
|
4204
4586
|
set_current_block(body_entry);
|
|
4205
4587
|
AddInstruction(new(zone()) HEnterInlined(target,
|
|
4206
4588
|
function,
|
|
4207
4589
|
call_kind));
|
|
4590
|
+
VisitDeclarations(target_info.scope()->declarations());
|
|
4208
4591
|
VisitStatements(function->body());
|
|
4209
4592
|
if (HasStackOverflow()) {
|
|
4210
4593
|
// Bail out if the inline function did, as we cannot residualize a call
|
|
@@ -4227,7 +4610,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
|
4227
4610
|
ASSERT(function_return() != NULL);
|
|
4228
4611
|
ASSERT(call_context()->IsEffect() || call_context()->IsValue());
|
|
4229
4612
|
if (call_context()->IsEffect()) {
|
|
4230
|
-
current_block()->Goto(function_return()
|
|
4613
|
+
current_block()->Goto(function_return());
|
|
4231
4614
|
} else {
|
|
4232
4615
|
current_block()->AddLeaveInlined(undefined, function_return());
|
|
4233
4616
|
}
|
|
@@ -4239,11 +4622,11 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
|
4239
4622
|
// TODO(3168478): refactor to avoid this.
|
|
4240
4623
|
HBasicBlock* empty_true = graph()->CreateBasicBlock();
|
|
4241
4624
|
HBasicBlock* empty_false = graph()->CreateBasicBlock();
|
|
4242
|
-
|
|
4625
|
+
HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false);
|
|
4243
4626
|
current_block()->Finish(test);
|
|
4244
4627
|
|
|
4245
|
-
empty_true->Goto(inlined_test_context()->if_true()
|
|
4246
|
-
empty_false->Goto(inlined_test_context()->if_false()
|
|
4628
|
+
empty_true->Goto(inlined_test_context()->if_true());
|
|
4629
|
+
empty_false->Goto(inlined_test_context()->if_false());
|
|
4247
4630
|
}
|
|
4248
4631
|
}
|
|
4249
4632
|
|
|
@@ -4251,21 +4634,22 @@ bool HGraphBuilder::TryInline(Call* expr) {
|
|
|
4251
4634
|
if (inlined_test_context() != NULL) {
|
|
4252
4635
|
HBasicBlock* if_true = inlined_test_context()->if_true();
|
|
4253
4636
|
HBasicBlock* if_false = inlined_test_context()->if_false();
|
|
4254
|
-
|
|
4255
|
-
if_false->SetJoinId(expr->id());
|
|
4256
|
-
ASSERT(ast_context() == inlined_test_context());
|
|
4637
|
+
|
|
4257
4638
|
// Pop the return test context from the expression context stack.
|
|
4639
|
+
ASSERT(ast_context() == inlined_test_context());
|
|
4258
4640
|
ClearInlinedTestContext();
|
|
4259
4641
|
|
|
4260
4642
|
// Forward to the real test context.
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4643
|
+
if (if_true->HasPredecessor()) {
|
|
4644
|
+
if_true->SetJoinId(expr->id());
|
|
4645
|
+
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
|
|
4646
|
+
if_true->Goto(true_target);
|
|
4647
|
+
}
|
|
4648
|
+
if (if_false->HasPredecessor()) {
|
|
4649
|
+
if_false->SetJoinId(expr->id());
|
|
4650
|
+
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
|
|
4651
|
+
if_false->Goto(false_target);
|
|
4652
|
+
}
|
|
4269
4653
|
set_current_block(NULL);
|
|
4270
4654
|
|
|
4271
4655
|
} else if (function_return()->HasPredecessor()) {
|
|
@@ -4294,18 +4678,20 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
|
|
|
4294
4678
|
if (argument_count == 2 && check_type == STRING_CHECK) {
|
|
4295
4679
|
HValue* index = Pop();
|
|
4296
4680
|
HValue* string = Pop();
|
|
4681
|
+
HValue* context = environment()->LookupContext();
|
|
4297
4682
|
ASSERT(!expr->holder().is_null());
|
|
4298
4683
|
AddInstruction(new(zone()) HCheckPrototypeMaps(
|
|
4299
4684
|
oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
|
|
4300
4685
|
expr->holder()));
|
|
4301
|
-
HStringCharCodeAt* char_code =
|
|
4686
|
+
HStringCharCodeAt* char_code =
|
|
4687
|
+
BuildStringCharCodeAt(context, string, index);
|
|
4302
4688
|
if (id == kStringCharCodeAt) {
|
|
4303
4689
|
ast_context()->ReturnInstruction(char_code, expr->id());
|
|
4304
4690
|
return true;
|
|
4305
4691
|
}
|
|
4306
4692
|
AddInstruction(char_code);
|
|
4307
4693
|
HStringCharFromCode* result =
|
|
4308
|
-
new(zone()) HStringCharFromCode(char_code);
|
|
4694
|
+
new(zone()) HStringCharFromCode(context, char_code);
|
|
4309
4695
|
ast_context()->ReturnInstruction(result, expr->id());
|
|
4310
4696
|
return true;
|
|
4311
4697
|
}
|
|
@@ -4320,8 +4706,10 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
|
|
|
4320
4706
|
if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
|
|
4321
4707
|
AddCheckConstantFunction(expr, receiver, receiver_map, true);
|
|
4322
4708
|
HValue* argument = Pop();
|
|
4709
|
+
HValue* context = environment()->LookupContext();
|
|
4323
4710
|
Drop(1); // Receiver.
|
|
4324
|
-
HUnaryMathOperation* op =
|
|
4711
|
+
HUnaryMathOperation* op =
|
|
4712
|
+
new(zone()) HUnaryMathOperation(context, argument, id);
|
|
4325
4713
|
op->set_position(expr->position());
|
|
4326
4714
|
ast_context()->ReturnInstruction(op, expr->id());
|
|
4327
4715
|
return true;
|
|
@@ -4333,31 +4721,33 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
|
|
|
4333
4721
|
HValue* right = Pop();
|
|
4334
4722
|
HValue* left = Pop();
|
|
4335
4723
|
Pop(); // Pop receiver.
|
|
4724
|
+
HValue* context = environment()->LookupContext();
|
|
4336
4725
|
HInstruction* result = NULL;
|
|
4337
4726
|
// Use sqrt() if exponent is 0.5 or -0.5.
|
|
4338
4727
|
if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
|
|
4339
4728
|
double exponent = HConstant::cast(right)->DoubleValue();
|
|
4340
4729
|
if (exponent == 0.5) {
|
|
4341
|
-
result =
|
|
4730
|
+
result =
|
|
4731
|
+
new(zone()) HUnaryMathOperation(context, left, kMathPowHalf);
|
|
4342
4732
|
} else if (exponent == -0.5) {
|
|
4343
4733
|
HConstant* double_one =
|
|
4344
4734
|
new(zone()) HConstant(Handle<Object>(Smi::FromInt(1)),
|
|
4345
4735
|
Representation::Double());
|
|
4346
4736
|
AddInstruction(double_one);
|
|
4347
4737
|
HUnaryMathOperation* square_root =
|
|
4348
|
-
new(zone()) HUnaryMathOperation(left, kMathPowHalf);
|
|
4738
|
+
new(zone()) HUnaryMathOperation(context, left, kMathPowHalf);
|
|
4349
4739
|
AddInstruction(square_root);
|
|
4350
4740
|
// MathPowHalf doesn't have side effects so there's no need for
|
|
4351
4741
|
// an environment simulation here.
|
|
4352
4742
|
ASSERT(!square_root->HasSideEffects());
|
|
4353
|
-
result = new(zone()) HDiv(double_one, square_root);
|
|
4743
|
+
result = new(zone()) HDiv(context, double_one, square_root);
|
|
4354
4744
|
} else if (exponent == 2.0) {
|
|
4355
|
-
result = new(zone()) HMul(left, left);
|
|
4745
|
+
result = new(zone()) HMul(context, left, left);
|
|
4356
4746
|
}
|
|
4357
4747
|
} else if (right->IsConstant() &&
|
|
4358
4748
|
HConstant::cast(right)->HasInteger32Value() &&
|
|
4359
4749
|
HConstant::cast(right)->Integer32Value() == 2) {
|
|
4360
|
-
result = new(zone()) HMul(left, left);
|
|
4750
|
+
result = new(zone()) HMul(context, left, left);
|
|
4361
4751
|
}
|
|
4362
4752
|
|
|
4363
4753
|
if (result == NULL) {
|
|
@@ -4380,10 +4770,17 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
|
|
|
4380
4770
|
Property* prop = callee->AsProperty();
|
|
4381
4771
|
ASSERT(prop != NULL);
|
|
4382
4772
|
|
|
4383
|
-
if (
|
|
4773
|
+
if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
|
|
4774
|
+
return false;
|
|
4775
|
+
}
|
|
4776
|
+
Handle<Map> function_map = expr->GetReceiverTypes()->first();
|
|
4777
|
+
if (function_map->instance_type() != JS_FUNCTION_TYPE ||
|
|
4778
|
+
!expr->target()->shared()->HasBuiltinFunctionId() ||
|
|
4779
|
+
expr->target()->shared()->builtin_function_id() != kFunctionApply) {
|
|
4780
|
+
return false;
|
|
4781
|
+
}
|
|
4384
4782
|
|
|
4385
|
-
|
|
4386
|
-
if (!name->IsEqualTo(CStrVector("apply"))) return false;
|
|
4783
|
+
if (info()->scope()->arguments() == NULL) return false;
|
|
4387
4784
|
|
|
4388
4785
|
ZoneList<Expression*>* args = expr->arguments();
|
|
4389
4786
|
if (args->length() != 2) return false;
|
|
@@ -4393,8 +4790,12 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
|
|
|
4393
4790
|
HValue* arg_two_value = environment()->Lookup(arg_two->var());
|
|
4394
4791
|
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
|
|
4395
4792
|
|
|
4396
|
-
|
|
4397
|
-
|
|
4793
|
+
// Our implementation of arguments (based on this stack frame or an
|
|
4794
|
+
// adapter below it) does not work for inlined functions.
|
|
4795
|
+
if (function_state()->outer() != NULL) {
|
|
4796
|
+
Bailout("Function.prototype.apply optimization in inlined function");
|
|
4797
|
+
return true;
|
|
4798
|
+
}
|
|
4398
4799
|
|
|
4399
4800
|
// Found pattern f.apply(receiver, arguments).
|
|
4400
4801
|
VisitForValue(prop->obj());
|
|
@@ -4405,10 +4806,7 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
|
|
|
4405
4806
|
HValue* receiver = Pop();
|
|
4406
4807
|
HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
|
|
4407
4808
|
HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
|
|
4408
|
-
AddCheckConstantFunction(expr,
|
|
4409
|
-
function,
|
|
4410
|
-
expr->GetReceiverTypes()->first(),
|
|
4411
|
-
true);
|
|
4809
|
+
AddCheckConstantFunction(expr, function, function_map, true);
|
|
4412
4810
|
HInstruction* result =
|
|
4413
4811
|
new(zone()) HApplyArguments(function, receiver, length, elements);
|
|
4414
4812
|
result->set_position(expr->position());
|
|
@@ -4429,7 +4827,7 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|
|
4429
4827
|
if (prop != NULL) {
|
|
4430
4828
|
if (!prop->key()->IsPropertyName()) {
|
|
4431
4829
|
// Keyed function call.
|
|
4432
|
-
CHECK_ALIVE(
|
|
4830
|
+
CHECK_ALIVE(VisitArgument(prop->obj()));
|
|
4433
4831
|
|
|
4434
4832
|
CHECK_ALIVE(VisitForValue(prop->key()));
|
|
4435
4833
|
// Push receiver and key like the non-optimized code generator expects it.
|
|
@@ -4438,15 +4836,13 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|
|
4438
4836
|
Push(key);
|
|
4439
4837
|
Push(receiver);
|
|
4440
4838
|
|
|
4441
|
-
CHECK_ALIVE(
|
|
4839
|
+
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
|
4442
4840
|
|
|
4443
4841
|
HValue* context = environment()->LookupContext();
|
|
4444
|
-
call =
|
|
4445
|
-
new(zone()) HCallKeyed(context, key, argument_count));
|
|
4842
|
+
call = new(zone()) HCallKeyed(context, key, argument_count);
|
|
4446
4843
|
call->set_position(expr->position());
|
|
4447
|
-
Drop(1); //
|
|
4448
|
-
ast_context()->ReturnInstruction(call, expr->id());
|
|
4449
|
-
return;
|
|
4844
|
+
Drop(argument_count + 1); // 1 is the key.
|
|
4845
|
+
return ast_context()->ReturnInstruction(call, expr->id());
|
|
4450
4846
|
}
|
|
4451
4847
|
|
|
4452
4848
|
// Named function call.
|
|
@@ -4459,13 +4855,14 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|
|
4459
4855
|
|
|
4460
4856
|
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
|
|
4461
4857
|
|
|
4462
|
-
|
|
4858
|
+
SmallMapList* types = expr->GetReceiverTypes();
|
|
4463
4859
|
|
|
4464
4860
|
HValue* receiver =
|
|
4465
4861
|
environment()->ExpressionStackAt(expr->arguments()->length());
|
|
4466
4862
|
if (expr->IsMonomorphic()) {
|
|
4467
|
-
Handle<Map> receiver_map =
|
|
4468
|
-
|
|
4863
|
+
Handle<Map> receiver_map = (types == NULL || types->is_empty())
|
|
4864
|
+
? Handle<Map>::null()
|
|
4865
|
+
: types->first();
|
|
4469
4866
|
if (TryInlineBuiltinFunction(expr,
|
|
4470
4867
|
receiver,
|
|
4471
4868
|
receiver_map,
|
|
@@ -4504,11 +4901,6 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|
|
4504
4901
|
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
|
|
4505
4902
|
bool global_call = (var != NULL) && var->is_global() && !var->is_this();
|
|
4506
4903
|
|
|
4507
|
-
if (!global_call) {
|
|
4508
|
-
++argument_count;
|
|
4509
|
-
CHECK_ALIVE(VisitForValue(expr->expression()));
|
|
4510
|
-
}
|
|
4511
|
-
|
|
4512
4904
|
if (global_call) {
|
|
4513
4905
|
bool known_global_function = false;
|
|
4514
4906
|
// If there is a global property cell for the name at compile time and
|
|
@@ -4548,27 +4940,34 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|
|
4548
4940
|
argument_count));
|
|
4549
4941
|
} else {
|
|
4550
4942
|
HValue* context = environment()->LookupContext();
|
|
4551
|
-
|
|
4552
|
-
|
|
4943
|
+
HGlobalObject* receiver = new(zone()) HGlobalObject(context);
|
|
4944
|
+
AddInstruction(receiver);
|
|
4945
|
+
PushAndAdd(new(zone()) HPushArgument(receiver));
|
|
4946
|
+
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
|
4553
4947
|
|
|
4554
|
-
call =
|
|
4555
|
-
|
|
4556
|
-
argument_count));
|
|
4948
|
+
call = new(zone()) HCallGlobal(context, var->name(), argument_count);
|
|
4949
|
+
Drop(argument_count);
|
|
4557
4950
|
}
|
|
4558
4951
|
|
|
4559
4952
|
} else {
|
|
4953
|
+
CHECK_ALIVE(VisitArgument(expr->expression()));
|
|
4560
4954
|
HValue* context = environment()->LookupContext();
|
|
4561
4955
|
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
|
|
4956
|
+
HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object);
|
|
4562
4957
|
AddInstruction(global_object);
|
|
4563
|
-
|
|
4564
|
-
|
|
4958
|
+
AddInstruction(receiver);
|
|
4959
|
+
PushAndAdd(new(zone()) HPushArgument(receiver));
|
|
4960
|
+
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
|
4565
4961
|
|
|
4566
|
-
call
|
|
4962
|
+
// The function to call is treated as an argument to the call function
|
|
4963
|
+
// stub.
|
|
4964
|
+
call = new(zone()) HCallFunction(context, argument_count + 1);
|
|
4965
|
+
Drop(argument_count + 1);
|
|
4567
4966
|
}
|
|
4568
4967
|
}
|
|
4569
4968
|
|
|
4570
4969
|
call->set_position(expr->position());
|
|
4571
|
-
ast_context()->ReturnInstruction(call, expr->id());
|
|
4970
|
+
return ast_context()->ReturnInstruction(call, expr->id());
|
|
4572
4971
|
}
|
|
4573
4972
|
|
|
4574
4973
|
|
|
@@ -4578,19 +4977,19 @@ void HGraphBuilder::VisitCallNew(CallNew* expr) {
|
|
|
4578
4977
|
ASSERT(current_block()->HasPredecessor());
|
|
4579
4978
|
// The constructor function is also used as the receiver argument to the
|
|
4580
4979
|
// JS construct call builtin.
|
|
4581
|
-
|
|
4582
|
-
CHECK_ALIVE(
|
|
4980
|
+
HValue* constructor = NULL;
|
|
4981
|
+
CHECK_ALIVE(constructor = VisitArgument(expr->expression()));
|
|
4982
|
+
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
|
4583
4983
|
|
|
4584
4984
|
HValue* context = environment()->LookupContext();
|
|
4585
4985
|
|
|
4586
4986
|
// The constructor is both an operand to the instruction and an argument
|
|
4587
4987
|
// to the construct call.
|
|
4588
4988
|
int arg_count = expr->arguments()->length() + 1; // Plus constructor.
|
|
4589
|
-
HValue* constructor = environment()->ExpressionStackAt(arg_count - 1);
|
|
4590
4989
|
HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count);
|
|
4591
4990
|
call->set_position(expr->position());
|
|
4592
|
-
|
|
4593
|
-
ast_context()->ReturnInstruction(call, expr->id());
|
|
4991
|
+
Drop(arg_count);
|
|
4992
|
+
return ast_context()->ReturnInstruction(call, expr->id());
|
|
4594
4993
|
}
|
|
4595
4994
|
|
|
4596
4995
|
|
|
@@ -4636,13 +5035,14 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
|
|
|
4636
5035
|
ASSERT(function->intrinsic_type == Runtime::RUNTIME);
|
|
4637
5036
|
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
|
4638
5037
|
|
|
5038
|
+
HValue* context = environment()->LookupContext();
|
|
4639
5039
|
Handle<String> name = expr->name();
|
|
4640
5040
|
int argument_count = expr->arguments()->length();
|
|
4641
5041
|
HCallRuntime* call =
|
|
4642
|
-
new(zone()) HCallRuntime(name, function, argument_count);
|
|
5042
|
+
new(zone()) HCallRuntime(context, name, function, argument_count);
|
|
4643
5043
|
call->set_position(RelocInfo::kNoPosition);
|
|
4644
5044
|
Drop(argument_count);
|
|
4645
|
-
ast_context()->ReturnInstruction(call, expr->id());
|
|
5045
|
+
return ast_context()->ReturnInstruction(call, expr->id());
|
|
4646
5046
|
}
|
|
4647
5047
|
}
|
|
4648
5048
|
|
|
@@ -4670,27 +5070,22 @@ void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
|
|
|
4670
5070
|
// Result of deleting non-property, non-variable reference is true.
|
|
4671
5071
|
// Evaluate the subexpression for side effects.
|
|
4672
5072
|
CHECK_ALIVE(VisitForEffect(expr->expression()));
|
|
4673
|
-
ast_context()->ReturnValue(graph()->GetConstantTrue());
|
|
5073
|
+
return ast_context()->ReturnValue(graph()->GetConstantTrue());
|
|
4674
5074
|
} else if (var != NULL &&
|
|
4675
5075
|
!var->is_global() &&
|
|
4676
5076
|
var->AsSlot() != NULL &&
|
|
4677
5077
|
var->AsSlot()->type() != Slot::LOOKUP) {
|
|
4678
5078
|
// Result of deleting non-global, non-dynamic variables is false.
|
|
4679
5079
|
// The subexpression does not have side effects.
|
|
4680
|
-
ast_context()->ReturnValue(graph()->GetConstantFalse());
|
|
5080
|
+
return ast_context()->ReturnValue(graph()->GetConstantFalse());
|
|
4681
5081
|
} else if (prop != NULL) {
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
HValue* key = Pop();
|
|
4690
|
-
HValue* obj = Pop();
|
|
4691
|
-
HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key);
|
|
4692
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
4693
|
-
}
|
|
5082
|
+
CHECK_ALIVE(VisitForValue(prop->obj()));
|
|
5083
|
+
CHECK_ALIVE(VisitForValue(prop->key()));
|
|
5084
|
+
HValue* key = Pop();
|
|
5085
|
+
HValue* obj = Pop();
|
|
5086
|
+
HValue* context = environment()->LookupContext();
|
|
5087
|
+
HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key);
|
|
5088
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
4694
5089
|
} else if (var->is_global()) {
|
|
4695
5090
|
Bailout("delete with global variable");
|
|
4696
5091
|
} else {
|
|
@@ -4701,42 +5096,58 @@ void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
|
|
|
4701
5096
|
|
|
4702
5097
|
void HGraphBuilder::VisitVoid(UnaryOperation* expr) {
|
|
4703
5098
|
CHECK_ALIVE(VisitForEffect(expr->expression()));
|
|
4704
|
-
ast_context()->ReturnValue(graph()->GetConstantUndefined());
|
|
5099
|
+
return ast_context()->ReturnValue(graph()->GetConstantUndefined());
|
|
4705
5100
|
}
|
|
4706
5101
|
|
|
4707
5102
|
|
|
4708
5103
|
void HGraphBuilder::VisitTypeof(UnaryOperation* expr) {
|
|
4709
5104
|
CHECK_ALIVE(VisitForTypeOf(expr->expression()));
|
|
4710
5105
|
HValue* value = Pop();
|
|
4711
|
-
|
|
5106
|
+
HValue* context = environment()->LookupContext();
|
|
5107
|
+
HInstruction* instr = new(zone()) HTypeof(context, value);
|
|
5108
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
4712
5109
|
}
|
|
4713
5110
|
|
|
4714
5111
|
|
|
4715
5112
|
void HGraphBuilder::VisitAdd(UnaryOperation* expr) {
|
|
4716
5113
|
CHECK_ALIVE(VisitForValue(expr->expression()));
|
|
4717
5114
|
HValue* value = Pop();
|
|
4718
|
-
|
|
4719
|
-
|
|
5115
|
+
HValue* context = environment()->LookupContext();
|
|
5116
|
+
HInstruction* instr =
|
|
5117
|
+
new(zone()) HMul(context, value, graph_->GetConstant1());
|
|
5118
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
4720
5119
|
}
|
|
4721
5120
|
|
|
4722
5121
|
|
|
4723
5122
|
void HGraphBuilder::VisitSub(UnaryOperation* expr) {
|
|
4724
5123
|
CHECK_ALIVE(VisitForValue(expr->expression()));
|
|
4725
5124
|
HValue* value = Pop();
|
|
4726
|
-
|
|
5125
|
+
HValue* context = environment()->LookupContext();
|
|
5126
|
+
HInstruction* instr =
|
|
5127
|
+
new(zone()) HMul(context, value, graph_->GetConstantMinus1());
|
|
4727
5128
|
TypeInfo info = oracle()->UnaryType(expr);
|
|
5129
|
+
if (info.IsUninitialized()) {
|
|
5130
|
+
AddInstruction(new(zone()) HSoftDeoptimize);
|
|
5131
|
+
current_block()->MarkAsDeoptimizing();
|
|
5132
|
+
info = TypeInfo::Unknown();
|
|
5133
|
+
}
|
|
4728
5134
|
Representation rep = ToRepresentation(info);
|
|
4729
5135
|
TraceRepresentation(expr->op(), info, instr, rep);
|
|
4730
5136
|
instr->AssumeRepresentation(rep);
|
|
4731
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
5137
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
4732
5138
|
}
|
|
4733
5139
|
|
|
4734
5140
|
|
|
4735
5141
|
void HGraphBuilder::VisitBitNot(UnaryOperation* expr) {
|
|
4736
5142
|
CHECK_ALIVE(VisitForValue(expr->expression()));
|
|
4737
5143
|
HValue* value = Pop();
|
|
5144
|
+
TypeInfo info = oracle()->UnaryType(expr);
|
|
5145
|
+
if (info.IsUninitialized()) {
|
|
5146
|
+
AddInstruction(new(zone()) HSoftDeoptimize);
|
|
5147
|
+
current_block()->MarkAsDeoptimizing();
|
|
5148
|
+
}
|
|
4738
5149
|
HInstruction* instr = new(zone()) HBitNot(value);
|
|
4739
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
5150
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
4740
5151
|
}
|
|
4741
5152
|
|
|
4742
5153
|
|
|
@@ -4781,7 +5192,7 @@ void HGraphBuilder::VisitNot(UnaryOperation* expr) {
|
|
|
4781
5192
|
HBasicBlock* join =
|
|
4782
5193
|
CreateJoin(materialize_false, materialize_true, expr->id());
|
|
4783
5194
|
set_current_block(join);
|
|
4784
|
-
if (join != NULL) ast_context()->ReturnValue(Pop());
|
|
5195
|
+
if (join != NULL) return ast_context()->ReturnValue(Pop());
|
|
4785
5196
|
}
|
|
4786
5197
|
|
|
4787
5198
|
|
|
@@ -4810,7 +5221,8 @@ HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input,
|
|
|
4810
5221
|
HConstant* delta = (expr->op() == Token::INC)
|
|
4811
5222
|
? graph_->GetConstant1()
|
|
4812
5223
|
: graph_->GetConstantMinus1();
|
|
4813
|
-
|
|
5224
|
+
HValue* context = environment()->LookupContext();
|
|
5225
|
+
HInstruction* instr = new(zone()) HAdd(context, Top(), delta);
|
|
4814
5226
|
TraceRepresentation(expr->op(), info, instr, rep);
|
|
4815
5227
|
instr->AssumeRepresentation(rep);
|
|
4816
5228
|
AddInstruction(instr);
|
|
@@ -4839,6 +5251,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
|
|
4839
5251
|
HValue* after = NULL; // The result after incrementing or decrementing.
|
|
4840
5252
|
|
|
4841
5253
|
if (var != NULL) {
|
|
5254
|
+
if (var->mode() == Variable::CONST) {
|
|
5255
|
+
return Bailout("unsupported count operation with const");
|
|
5256
|
+
}
|
|
4842
5257
|
// Argument of the count operation is a variable, not a property.
|
|
4843
5258
|
ASSERT(prop == NULL);
|
|
4844
5259
|
CHECK_ALIVE(VisitForValue(target));
|
|
@@ -4855,6 +5270,20 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
|
|
4855
5270
|
} else if (var->IsStackAllocated()) {
|
|
4856
5271
|
Bind(var, after);
|
|
4857
5272
|
} else if (var->IsContextSlot()) {
|
|
5273
|
+
// Bail out if we try to mutate a parameter value in a function using
|
|
5274
|
+
// the arguments object. We do not (yet) correctly handle the
|
|
5275
|
+
// arguments property of the function.
|
|
5276
|
+
if (info()->scope()->arguments() != NULL) {
|
|
5277
|
+
// Parameters will rewrite to context slots. We have no direct way
|
|
5278
|
+
// to detect that the variable is a parameter.
|
|
5279
|
+
int count = info()->scope()->num_parameters();
|
|
5280
|
+
for (int i = 0; i < count; ++i) {
|
|
5281
|
+
if (var == info()->scope()->parameter(i)) {
|
|
5282
|
+
Bailout("assignment to parameter, function uses arguments object");
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
5285
|
+
}
|
|
5286
|
+
|
|
4858
5287
|
HValue* context = BuildContextChainWalk(var);
|
|
4859
5288
|
int index = var->AsSlot()->index();
|
|
4860
5289
|
HStoreContextSlot* instr =
|
|
@@ -4910,16 +5339,22 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
|
|
4910
5339
|
HValue* obj = environment()->ExpressionStackAt(1);
|
|
4911
5340
|
HValue* key = environment()->ExpressionStackAt(0);
|
|
4912
5341
|
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
5342
|
+
bool has_side_effects = false;
|
|
5343
|
+
HValue* load = HandleKeyedElementAccess(
|
|
5344
|
+
obj, key, NULL, prop, expr->CountId(), RelocInfo::kNoPosition,
|
|
5345
|
+
false, // is_store
|
|
5346
|
+
&has_side_effects);
|
|
5347
|
+
Push(load);
|
|
5348
|
+
if (has_side_effects) AddSimulate(expr->CountId());
|
|
4916
5349
|
|
|
4917
5350
|
after = BuildIncrement(returns_original_input, expr);
|
|
4918
5351
|
input = Pop();
|
|
4919
5352
|
|
|
4920
5353
|
expr->RecordTypeFeedback(oracle());
|
|
4921
|
-
|
|
4922
|
-
|
|
5354
|
+
HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
|
|
5355
|
+
RelocInfo::kNoPosition,
|
|
5356
|
+
true, // is_store
|
|
5357
|
+
&has_side_effects);
|
|
4923
5358
|
|
|
4924
5359
|
// Drop the key from the bailout environment. Overwrite the receiver
|
|
4925
5360
|
// with the result of the operation, and the placeholder with the
|
|
@@ -4927,43 +5362,86 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
|
|
4927
5362
|
Drop(1);
|
|
4928
5363
|
environment()->SetExpressionStackAt(0, after);
|
|
4929
5364
|
if (returns_original_input) environment()->SetExpressionStackAt(1, input);
|
|
4930
|
-
|
|
5365
|
+
ASSERT(has_side_effects); // Stores always have side effects.
|
|
5366
|
+
AddSimulate(expr->AssignmentId());
|
|
4931
5367
|
}
|
|
4932
5368
|
}
|
|
4933
5369
|
|
|
4934
5370
|
Drop(returns_original_input ? 2 : 1);
|
|
4935
|
-
ast_context()->ReturnValue(expr->is_postfix() ? input : after);
|
|
4936
|
-
}
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
HCompareSymbolEq* HGraphBuilder::BuildSymbolCompare(HValue* left,
|
|
4940
|
-
HValue* right,
|
|
4941
|
-
Token::Value op) {
|
|
4942
|
-
ASSERT(op == Token::EQ || op == Token::EQ_STRICT);
|
|
4943
|
-
AddInstruction(new(zone()) HCheckNonSmi(left));
|
|
4944
|
-
AddInstruction(HCheckInstanceType::NewIsSymbol(left));
|
|
4945
|
-
AddInstruction(new(zone()) HCheckNonSmi(right));
|
|
4946
|
-
AddInstruction(HCheckInstanceType::NewIsSymbol(right));
|
|
4947
|
-
return new(zone()) HCompareSymbolEq(left, right, op);
|
|
5371
|
+
return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
|
|
4948
5372
|
}
|
|
4949
5373
|
|
|
4950
5374
|
|
|
4951
|
-
HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue*
|
|
5375
|
+
HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* context,
|
|
5376
|
+
HValue* string,
|
|
4952
5377
|
HValue* index) {
|
|
4953
5378
|
AddInstruction(new(zone()) HCheckNonSmi(string));
|
|
4954
5379
|
AddInstruction(HCheckInstanceType::NewIsString(string));
|
|
4955
5380
|
HStringLength* length = new(zone()) HStringLength(string);
|
|
4956
5381
|
AddInstruction(length);
|
|
4957
|
-
|
|
4958
|
-
|
|
5382
|
+
HInstruction* checked_index =
|
|
5383
|
+
AddInstruction(new(zone()) HBoundsCheck(index, length));
|
|
5384
|
+
return new(zone()) HStringCharCodeAt(context, string, checked_index);
|
|
4959
5385
|
}
|
|
4960
5386
|
|
|
4961
5387
|
|
|
4962
5388
|
HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
|
|
4963
5389
|
HValue* left,
|
|
4964
5390
|
HValue* right) {
|
|
5391
|
+
HValue* context = environment()->LookupContext();
|
|
4965
5392
|
TypeInfo info = oracle()->BinaryType(expr);
|
|
4966
|
-
|
|
5393
|
+
if (info.IsUninitialized()) {
|
|
5394
|
+
AddInstruction(new(zone()) HSoftDeoptimize);
|
|
5395
|
+
current_block()->MarkAsDeoptimizing();
|
|
5396
|
+
info = TypeInfo::Unknown();
|
|
5397
|
+
}
|
|
5398
|
+
HInstruction* instr = NULL;
|
|
5399
|
+
switch (expr->op()) {
|
|
5400
|
+
case Token::ADD:
|
|
5401
|
+
if (info.IsString()) {
|
|
5402
|
+
AddInstruction(new(zone()) HCheckNonSmi(left));
|
|
5403
|
+
AddInstruction(HCheckInstanceType::NewIsString(left));
|
|
5404
|
+
AddInstruction(new(zone()) HCheckNonSmi(right));
|
|
5405
|
+
AddInstruction(HCheckInstanceType::NewIsString(right));
|
|
5406
|
+
instr = new(zone()) HStringAdd(context, left, right);
|
|
5407
|
+
} else {
|
|
5408
|
+
instr = new(zone()) HAdd(context, left, right);
|
|
5409
|
+
}
|
|
5410
|
+
break;
|
|
5411
|
+
case Token::SUB:
|
|
5412
|
+
instr = new(zone()) HSub(context, left, right);
|
|
5413
|
+
break;
|
|
5414
|
+
case Token::MUL:
|
|
5415
|
+
instr = new(zone()) HMul(context, left, right);
|
|
5416
|
+
break;
|
|
5417
|
+
case Token::MOD:
|
|
5418
|
+
instr = new(zone()) HMod(context, left, right);
|
|
5419
|
+
break;
|
|
5420
|
+
case Token::DIV:
|
|
5421
|
+
instr = new(zone()) HDiv(context, left, right);
|
|
5422
|
+
break;
|
|
5423
|
+
case Token::BIT_XOR:
|
|
5424
|
+
instr = new(zone()) HBitXor(context, left, right);
|
|
5425
|
+
break;
|
|
5426
|
+
case Token::BIT_AND:
|
|
5427
|
+
instr = new(zone()) HBitAnd(context, left, right);
|
|
5428
|
+
break;
|
|
5429
|
+
case Token::BIT_OR:
|
|
5430
|
+
instr = new(zone()) HBitOr(context, left, right);
|
|
5431
|
+
break;
|
|
5432
|
+
case Token::SAR:
|
|
5433
|
+
instr = new(zone()) HSar(context, left, right);
|
|
5434
|
+
break;
|
|
5435
|
+
case Token::SHR:
|
|
5436
|
+
instr = new(zone()) HShr(context, left, right);
|
|
5437
|
+
break;
|
|
5438
|
+
case Token::SHL:
|
|
5439
|
+
instr = new(zone()) HShl(context, left, right);
|
|
5440
|
+
break;
|
|
5441
|
+
default:
|
|
5442
|
+
UNREACHABLE();
|
|
5443
|
+
}
|
|
5444
|
+
|
|
4967
5445
|
// If we hit an uninitialized binary op stub we will get type info
|
|
4968
5446
|
// for a smi operation. If one of the operands is a constant string
|
|
4969
5447
|
// do not generate code assuming it is a smi operation.
|
|
@@ -4983,36 +5461,6 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
|
|
|
4983
5461
|
}
|
|
4984
5462
|
|
|
4985
5463
|
|
|
4986
|
-
HInstruction* HGraphBuilder::BuildBinaryOperation(
|
|
4987
|
-
Token::Value op, HValue* left, HValue* right, TypeInfo info) {
|
|
4988
|
-
switch (op) {
|
|
4989
|
-
case Token::ADD:
|
|
4990
|
-
if (info.IsString()) {
|
|
4991
|
-
AddInstruction(new(zone()) HCheckNonSmi(left));
|
|
4992
|
-
AddInstruction(HCheckInstanceType::NewIsString(left));
|
|
4993
|
-
AddInstruction(new(zone()) HCheckNonSmi(right));
|
|
4994
|
-
AddInstruction(HCheckInstanceType::NewIsString(right));
|
|
4995
|
-
return new(zone()) HStringAdd(left, right);
|
|
4996
|
-
} else {
|
|
4997
|
-
return new(zone()) HAdd(left, right);
|
|
4998
|
-
}
|
|
4999
|
-
case Token::SUB: return new(zone()) HSub(left, right);
|
|
5000
|
-
case Token::MUL: return new(zone()) HMul(left, right);
|
|
5001
|
-
case Token::MOD: return new(zone()) HMod(left, right);
|
|
5002
|
-
case Token::DIV: return new(zone()) HDiv(left, right);
|
|
5003
|
-
case Token::BIT_XOR: return new(zone()) HBitXor(left, right);
|
|
5004
|
-
case Token::BIT_AND: return new(zone()) HBitAnd(left, right);
|
|
5005
|
-
case Token::BIT_OR: return new(zone()) HBitOr(left, right);
|
|
5006
|
-
case Token::SAR: return new(zone()) HSar(left, right);
|
|
5007
|
-
case Token::SHR: return new(zone()) HShr(left, right);
|
|
5008
|
-
case Token::SHL: return new(zone()) HShl(left, right);
|
|
5009
|
-
default:
|
|
5010
|
-
UNREACHABLE();
|
|
5011
|
-
return NULL;
|
|
5012
|
-
}
|
|
5013
|
-
}
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
5464
|
// Check for the form (%_ClassOf(foo) === 'BarClass').
|
|
5017
5465
|
static bool IsClassOfTest(CompareOperation* expr) {
|
|
5018
5466
|
if (expr->op() != Token::EQ_STRICT) return false;
|
|
@@ -5032,10 +5480,13 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
|
|
|
5032
5480
|
ASSERT(current_block() != NULL);
|
|
5033
5481
|
ASSERT(current_block()->HasPredecessor());
|
|
5034
5482
|
switch (expr->op()) {
|
|
5035
|
-
case Token::COMMA:
|
|
5036
|
-
|
|
5037
|
-
case Token::
|
|
5038
|
-
|
|
5483
|
+
case Token::COMMA:
|
|
5484
|
+
return VisitComma(expr);
|
|
5485
|
+
case Token::OR:
|
|
5486
|
+
case Token::AND:
|
|
5487
|
+
return VisitLogicalExpression(expr);
|
|
5488
|
+
default:
|
|
5489
|
+
return VisitArithmeticExpression(expr);
|
|
5039
5490
|
}
|
|
5040
5491
|
}
|
|
5041
5492
|
|
|
@@ -5048,7 +5499,8 @@ void HGraphBuilder::VisitComma(BinaryOperation* expr) {
|
|
|
5048
5499
|
}
|
|
5049
5500
|
|
|
5050
5501
|
|
|
5051
|
-
void HGraphBuilder::
|
|
5502
|
+
void HGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
|
|
5503
|
+
bool is_logical_and = expr->op() == Token::AND;
|
|
5052
5504
|
if (ast_context()->IsTest()) {
|
|
5053
5505
|
TestContext* context = TestContext::cast(ast_context());
|
|
5054
5506
|
// Translate left subexpression.
|
|
@@ -5078,9 +5530,11 @@ void HGraphBuilder::VisitAndOr(BinaryOperation* expr, bool is_logical_and) {
|
|
|
5078
5530
|
// We need an extra block to maintain edge-split form.
|
|
5079
5531
|
HBasicBlock* empty_block = graph()->CreateBasicBlock();
|
|
5080
5532
|
HBasicBlock* eval_right = graph()->CreateBasicBlock();
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5533
|
+
unsigned test_id = expr->left()->test_id();
|
|
5534
|
+
ToBooleanStub::Types expected(oracle()->ToBooleanTypes(test_id));
|
|
5535
|
+
HBranch* test = is_logical_and
|
|
5536
|
+
? new(zone()) HBranch(Top(), eval_right, empty_block, expected)
|
|
5537
|
+
: new(zone()) HBranch(Top(), empty_block, eval_right, expected);
|
|
5084
5538
|
current_block()->Finish(test);
|
|
5085
5539
|
|
|
5086
5540
|
set_current_block(eval_right);
|
|
@@ -5090,7 +5544,7 @@ void HGraphBuilder::VisitAndOr(BinaryOperation* expr, bool is_logical_and) {
|
|
|
5090
5544
|
HBasicBlock* join_block =
|
|
5091
5545
|
CreateJoin(empty_block, current_block(), expr->id());
|
|
5092
5546
|
set_current_block(join_block);
|
|
5093
|
-
ast_context()->ReturnValue(Pop());
|
|
5547
|
+
return ast_context()->ReturnValue(Pop());
|
|
5094
5548
|
|
|
5095
5549
|
} else {
|
|
5096
5550
|
ASSERT(ast_context()->IsEffect());
|
|
@@ -5135,14 +5589,14 @@ void HGraphBuilder::VisitAndOr(BinaryOperation* expr, bool is_logical_and) {
|
|
|
5135
5589
|
}
|
|
5136
5590
|
|
|
5137
5591
|
|
|
5138
|
-
void HGraphBuilder::
|
|
5592
|
+
void HGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
|
|
5139
5593
|
CHECK_ALIVE(VisitForValue(expr->left()));
|
|
5140
5594
|
CHECK_ALIVE(VisitForValue(expr->right()));
|
|
5141
5595
|
HValue* right = Pop();
|
|
5142
5596
|
HValue* left = Pop();
|
|
5143
5597
|
HInstruction* instr = BuildBinaryOperation(expr, left, right);
|
|
5144
5598
|
instr->set_position(expr->position());
|
|
5145
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
5599
|
+
return ast_context()->ReturnInstruction(instr, expr->id());
|
|
5146
5600
|
}
|
|
5147
5601
|
|
|
5148
5602
|
|
|
@@ -5175,46 +5629,75 @@ Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
|
|
|
5175
5629
|
}
|
|
5176
5630
|
|
|
5177
5631
|
|
|
5632
|
+
void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* compare_expr,
|
|
5633
|
+
Expression* expr,
|
|
5634
|
+
Handle<String> check) {
|
|
5635
|
+
CHECK_ALIVE(VisitForTypeOf(expr));
|
|
5636
|
+
HValue* expr_value = Pop();
|
|
5637
|
+
HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(expr_value, check);
|
|
5638
|
+
instr->set_position(compare_expr->position());
|
|
5639
|
+
return ast_context()->ReturnControl(instr, compare_expr->id());
|
|
5640
|
+
}
|
|
5641
|
+
|
|
5642
|
+
|
|
5643
|
+
void HGraphBuilder::HandleLiteralCompareUndefined(
|
|
5644
|
+
CompareOperation* compare_expr, Expression* expr) {
|
|
5645
|
+
CHECK_ALIVE(VisitForValue(expr));
|
|
5646
|
+
HValue* lhs = Pop();
|
|
5647
|
+
HValue* rhs = graph()->GetConstantUndefined();
|
|
5648
|
+
HCompareObjectEqAndBranch* instr =
|
|
5649
|
+
new(zone()) HCompareObjectEqAndBranch(lhs, rhs);
|
|
5650
|
+
instr->set_position(compare_expr->position());
|
|
5651
|
+
return ast_context()->ReturnControl(instr, compare_expr->id());
|
|
5652
|
+
}
|
|
5653
|
+
|
|
5654
|
+
|
|
5178
5655
|
void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
|
5179
5656
|
ASSERT(!HasStackOverflow());
|
|
5180
5657
|
ASSERT(current_block() != NULL);
|
|
5181
5658
|
ASSERT(current_block()->HasPredecessor());
|
|
5182
5659
|
if (IsClassOfTest(expr)) {
|
|
5183
5660
|
CallRuntime* call = expr->left()->AsCallRuntime();
|
|
5661
|
+
ASSERT(call->arguments()->length() == 1);
|
|
5184
5662
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5185
5663
|
HValue* value = Pop();
|
|
5186
5664
|
Literal* literal = expr->right()->AsLiteral();
|
|
5187
5665
|
Handle<String> rhs = Handle<String>::cast(literal->handle());
|
|
5188
|
-
|
|
5666
|
+
HClassOfTestAndBranch* instr =
|
|
5667
|
+
new(zone()) HClassOfTestAndBranch(value, rhs);
|
|
5189
5668
|
instr->set_position(expr->position());
|
|
5190
|
-
ast_context()->
|
|
5669
|
+
return ast_context()->ReturnControl(instr, expr->id());
|
|
5670
|
+
}
|
|
5671
|
+
|
|
5672
|
+
// Check for special cases that compare against literals.
|
|
5673
|
+
Expression *sub_expr;
|
|
5674
|
+
Handle<String> check;
|
|
5675
|
+
if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
|
|
5676
|
+
HandleLiteralCompareTypeof(expr, sub_expr, check);
|
|
5191
5677
|
return;
|
|
5192
5678
|
}
|
|
5193
5679
|
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
Literal* right_literal = expr->right()->AsLiteral();
|
|
5197
|
-
if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) &&
|
|
5198
|
-
left_unary != NULL && left_unary->op() == Token::TYPEOF &&
|
|
5199
|
-
right_literal != NULL && right_literal->handle()->IsString()) {
|
|
5200
|
-
CHECK_ALIVE(VisitForTypeOf(left_unary->expression()));
|
|
5201
|
-
HValue* left = Pop();
|
|
5202
|
-
HInstruction* instr = new(zone()) HTypeofIs(left,
|
|
5203
|
-
Handle<String>::cast(right_literal->handle()));
|
|
5204
|
-
instr->set_position(expr->position());
|
|
5205
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
5680
|
+
if (expr->IsLiteralCompareUndefined(&sub_expr)) {
|
|
5681
|
+
HandleLiteralCompareUndefined(expr, sub_expr);
|
|
5206
5682
|
return;
|
|
5207
5683
|
}
|
|
5208
5684
|
|
|
5685
|
+
TypeInfo type_info = oracle()->CompareType(expr);
|
|
5686
|
+
// Check if this expression was ever executed according to type feedback.
|
|
5687
|
+
if (type_info.IsUninitialized()) {
|
|
5688
|
+
AddInstruction(new(zone()) HSoftDeoptimize);
|
|
5689
|
+
current_block()->MarkAsDeoptimizing();
|
|
5690
|
+
type_info = TypeInfo::Unknown();
|
|
5691
|
+
}
|
|
5692
|
+
|
|
5209
5693
|
CHECK_ALIVE(VisitForValue(expr->left()));
|
|
5210
5694
|
CHECK_ALIVE(VisitForValue(expr->right()));
|
|
5211
5695
|
|
|
5696
|
+
HValue* context = environment()->LookupContext();
|
|
5212
5697
|
HValue* right = Pop();
|
|
5213
5698
|
HValue* left = Pop();
|
|
5214
5699
|
Token::Value op = expr->op();
|
|
5215
5700
|
|
|
5216
|
-
TypeInfo type_info = oracle()->CompareType(expr);
|
|
5217
|
-
HInstruction* instr = NULL;
|
|
5218
5701
|
if (op == Token::INSTANCEOF) {
|
|
5219
5702
|
// Check to see if the rhs of the instanceof is a global function not
|
|
5220
5703
|
// residing in new space. If it is we assume that the function will stay the
|
|
@@ -5244,40 +5727,61 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
|
|
5244
5727
|
// If the target is not null we have found a known global function that is
|
|
5245
5728
|
// assumed to stay the same for this instanceof.
|
|
5246
5729
|
if (target.is_null()) {
|
|
5247
|
-
|
|
5248
|
-
|
|
5730
|
+
HInstanceOf* result = new(zone()) HInstanceOf(context, left, right);
|
|
5731
|
+
result->set_position(expr->position());
|
|
5732
|
+
return ast_context()->ReturnInstruction(result, expr->id());
|
|
5249
5733
|
} else {
|
|
5250
5734
|
AddInstruction(new(zone()) HCheckFunction(right, target));
|
|
5251
|
-
|
|
5735
|
+
HInstanceOfKnownGlobal* result =
|
|
5736
|
+
new(zone()) HInstanceOfKnownGlobal(context, left, target);
|
|
5737
|
+
result->set_position(expr->position());
|
|
5738
|
+
return ast_context()->ReturnInstruction(result, expr->id());
|
|
5252
5739
|
}
|
|
5253
5740
|
} else if (op == Token::IN) {
|
|
5254
|
-
|
|
5741
|
+
HIn* result = new(zone()) HIn(context, left, right);
|
|
5742
|
+
result->set_position(expr->position());
|
|
5743
|
+
return ast_context()->ReturnInstruction(result, expr->id());
|
|
5255
5744
|
} else if (type_info.IsNonPrimitive()) {
|
|
5256
5745
|
switch (op) {
|
|
5257
5746
|
case Token::EQ:
|
|
5258
5747
|
case Token::EQ_STRICT: {
|
|
5259
5748
|
AddInstruction(new(zone()) HCheckNonSmi(left));
|
|
5260
|
-
AddInstruction(HCheckInstanceType::
|
|
5749
|
+
AddInstruction(HCheckInstanceType::NewIsSpecObject(left));
|
|
5261
5750
|
AddInstruction(new(zone()) HCheckNonSmi(right));
|
|
5262
|
-
AddInstruction(HCheckInstanceType::
|
|
5263
|
-
|
|
5264
|
-
|
|
5751
|
+
AddInstruction(HCheckInstanceType::NewIsSpecObject(right));
|
|
5752
|
+
HCompareObjectEqAndBranch* result =
|
|
5753
|
+
new(zone()) HCompareObjectEqAndBranch(left, right);
|
|
5754
|
+
result->set_position(expr->position());
|
|
5755
|
+
return ast_context()->ReturnControl(result, expr->id());
|
|
5265
5756
|
}
|
|
5266
5757
|
default:
|
|
5267
5758
|
return Bailout("Unsupported non-primitive compare");
|
|
5268
|
-
break;
|
|
5269
5759
|
}
|
|
5270
5760
|
} else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) &&
|
|
5271
5761
|
(op == Token::EQ || op == Token::EQ_STRICT)) {
|
|
5272
|
-
|
|
5762
|
+
AddInstruction(new(zone()) HCheckNonSmi(left));
|
|
5763
|
+
AddInstruction(HCheckInstanceType::NewIsSymbol(left));
|
|
5764
|
+
AddInstruction(new(zone()) HCheckNonSmi(right));
|
|
5765
|
+
AddInstruction(HCheckInstanceType::NewIsSymbol(right));
|
|
5766
|
+
HCompareObjectEqAndBranch* result =
|
|
5767
|
+
new(zone()) HCompareObjectEqAndBranch(left, right);
|
|
5768
|
+
result->set_position(expr->position());
|
|
5769
|
+
return ast_context()->ReturnControl(result, expr->id());
|
|
5273
5770
|
} else {
|
|
5274
|
-
HCompare* compare = new(zone()) HCompare(left, right, op);
|
|
5275
5771
|
Representation r = ToRepresentation(type_info);
|
|
5276
|
-
|
|
5277
|
-
|
|
5772
|
+
if (r.IsTagged()) {
|
|
5773
|
+
HCompareGeneric* result =
|
|
5774
|
+
new(zone()) HCompareGeneric(context, left, right, op);
|
|
5775
|
+
result->set_position(expr->position());
|
|
5776
|
+
return ast_context()->ReturnInstruction(result, expr->id());
|
|
5777
|
+
} else {
|
|
5778
|
+
HCompareIDAndBranch* result =
|
|
5779
|
+
new(zone()) HCompareIDAndBranch(left, right, op);
|
|
5780
|
+
result->set_position(expr->position());
|
|
5781
|
+
result->SetInputRepresentation(r);
|
|
5782
|
+
return ast_context()->ReturnControl(result, expr->id());
|
|
5783
|
+
}
|
|
5278
5784
|
}
|
|
5279
|
-
instr->set_position(expr->position());
|
|
5280
|
-
ast_context()->ReturnInstruction(instr, expr->id());
|
|
5281
5785
|
}
|
|
5282
5786
|
|
|
5283
5787
|
|
|
@@ -5286,10 +5790,10 @@ void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) {
|
|
|
5286
5790
|
ASSERT(current_block() != NULL);
|
|
5287
5791
|
ASSERT(current_block()->HasPredecessor());
|
|
5288
5792
|
CHECK_ALIVE(VisitForValue(expr->expression()));
|
|
5289
|
-
|
|
5290
5793
|
HValue* value = Pop();
|
|
5291
|
-
|
|
5292
|
-
|
|
5794
|
+
HIsNullAndBranch* instr =
|
|
5795
|
+
new(zone()) HIsNullAndBranch(value, expr->is_strict());
|
|
5796
|
+
return ast_context()->ReturnControl(instr, expr->id());
|
|
5293
5797
|
}
|
|
5294
5798
|
|
|
5295
5799
|
|
|
@@ -5297,23 +5801,24 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
|
|
|
5297
5801
|
ASSERT(!HasStackOverflow());
|
|
5298
5802
|
ASSERT(current_block() != NULL);
|
|
5299
5803
|
ASSERT(current_block()->HasPredecessor());
|
|
5300
|
-
|
|
5804
|
+
HThisFunction* self = new(zone()) HThisFunction;
|
|
5805
|
+
return ast_context()->ReturnInstruction(self, expr->id());
|
|
5301
5806
|
}
|
|
5302
5807
|
|
|
5303
5808
|
|
|
5304
5809
|
void HGraphBuilder::VisitDeclaration(Declaration* decl) {
|
|
5305
|
-
// We
|
|
5306
|
-
// The following all require code generation: global variables and
|
|
5307
|
-
// functions, variables with slot type LOOKUP, declarations with
|
|
5308
|
-
// mode CONST, and functions.
|
|
5810
|
+
// We support only declarations that do not require code generation.
|
|
5309
5811
|
Variable* var = decl->proxy()->var();
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
decl->mode() == Variable::CONST ||
|
|
5314
|
-
decl->fun() != NULL) {
|
|
5812
|
+
if (!var->IsStackAllocated() ||
|
|
5813
|
+
decl->fun() != NULL ||
|
|
5814
|
+
decl->mode() == Variable::LET) {
|
|
5315
5815
|
return Bailout("unsupported declaration");
|
|
5316
5816
|
}
|
|
5817
|
+
|
|
5818
|
+
if (decl->mode() == Variable::CONST) {
|
|
5819
|
+
ASSERT(var->IsStackAllocated());
|
|
5820
|
+
environment()->Bind(var, graph()->GetConstantHole());
|
|
5821
|
+
}
|
|
5317
5822
|
}
|
|
5318
5823
|
|
|
5319
5824
|
|
|
@@ -5323,8 +5828,8 @@ void HGraphBuilder::GenerateIsSmi(CallRuntime* call) {
|
|
|
5323
5828
|
ASSERT(call->arguments()->length() == 1);
|
|
5324
5829
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5325
5830
|
HValue* value = Pop();
|
|
5326
|
-
|
|
5327
|
-
ast_context()->
|
|
5831
|
+
HIsSmiAndBranch* result = new(zone()) HIsSmiAndBranch(value);
|
|
5832
|
+
return ast_context()->ReturnControl(result, call->id());
|
|
5328
5833
|
}
|
|
5329
5834
|
|
|
5330
5835
|
|
|
@@ -5332,9 +5837,11 @@ void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
|
|
|
5332
5837
|
ASSERT(call->arguments()->length() == 1);
|
|
5333
5838
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5334
5839
|
HValue* value = Pop();
|
|
5335
|
-
|
|
5336
|
-
new(zone())
|
|
5337
|
-
|
|
5840
|
+
HHasInstanceTypeAndBranch* result =
|
|
5841
|
+
new(zone()) HHasInstanceTypeAndBranch(value,
|
|
5842
|
+
FIRST_SPEC_OBJECT_TYPE,
|
|
5843
|
+
LAST_SPEC_OBJECT_TYPE);
|
|
5844
|
+
return ast_context()->ReturnControl(result, call->id());
|
|
5338
5845
|
}
|
|
5339
5846
|
|
|
5340
5847
|
|
|
@@ -5342,9 +5849,9 @@ void HGraphBuilder::GenerateIsFunction(CallRuntime* call) {
|
|
|
5342
5849
|
ASSERT(call->arguments()->length() == 1);
|
|
5343
5850
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5344
5851
|
HValue* value = Pop();
|
|
5345
|
-
|
|
5346
|
-
new(zone())
|
|
5347
|
-
ast_context()->
|
|
5852
|
+
HHasInstanceTypeAndBranch* result =
|
|
5853
|
+
new(zone()) HHasInstanceTypeAndBranch(value, JS_FUNCTION_TYPE);
|
|
5854
|
+
return ast_context()->ReturnControl(result, call->id());
|
|
5348
5855
|
}
|
|
5349
5856
|
|
|
5350
5857
|
|
|
@@ -5352,8 +5859,9 @@ void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
|
|
|
5352
5859
|
ASSERT(call->arguments()->length() == 1);
|
|
5353
5860
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5354
5861
|
HValue* value = Pop();
|
|
5355
|
-
|
|
5356
|
-
|
|
5862
|
+
HHasCachedArrayIndexAndBranch* result =
|
|
5863
|
+
new(zone()) HHasCachedArrayIndexAndBranch(value);
|
|
5864
|
+
return ast_context()->ReturnControl(result, call->id());
|
|
5357
5865
|
}
|
|
5358
5866
|
|
|
5359
5867
|
|
|
@@ -5361,8 +5869,9 @@ void HGraphBuilder::GenerateIsArray(CallRuntime* call) {
|
|
|
5361
5869
|
ASSERT(call->arguments()->length() == 1);
|
|
5362
5870
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5363
5871
|
HValue* value = Pop();
|
|
5364
|
-
|
|
5365
|
-
|
|
5872
|
+
HHasInstanceTypeAndBranch* result =
|
|
5873
|
+
new(zone()) HHasInstanceTypeAndBranch(value, JS_ARRAY_TYPE);
|
|
5874
|
+
return ast_context()->ReturnControl(result, call->id());
|
|
5366
5875
|
}
|
|
5367
5876
|
|
|
5368
5877
|
|
|
@@ -5370,9 +5879,9 @@ void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
|
|
|
5370
5879
|
ASSERT(call->arguments()->length() == 1);
|
|
5371
5880
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5372
5881
|
HValue* value = Pop();
|
|
5373
|
-
|
|
5374
|
-
new(zone())
|
|
5375
|
-
ast_context()->
|
|
5882
|
+
HHasInstanceTypeAndBranch* result =
|
|
5883
|
+
new(zone()) HHasInstanceTypeAndBranch(value, JS_REGEXP_TYPE);
|
|
5884
|
+
return ast_context()->ReturnControl(result, call->id());
|
|
5376
5885
|
}
|
|
5377
5886
|
|
|
5378
5887
|
|
|
@@ -5380,8 +5889,8 @@ void HGraphBuilder::GenerateIsObject(CallRuntime* call) {
|
|
|
5380
5889
|
ASSERT(call->arguments()->length() == 1);
|
|
5381
5890
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5382
5891
|
HValue* value = Pop();
|
|
5383
|
-
|
|
5384
|
-
ast_context()->
|
|
5892
|
+
HIsObjectAndBranch* result = new(zone()) HIsObjectAndBranch(value);
|
|
5893
|
+
return ast_context()->ReturnControl(result, call->id());
|
|
5385
5894
|
}
|
|
5386
5895
|
|
|
5387
5896
|
|
|
@@ -5394,8 +5903,9 @@ void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
|
|
|
5394
5903
|
ASSERT(call->arguments()->length() == 1);
|
|
5395
5904
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5396
5905
|
HValue* value = Pop();
|
|
5397
|
-
|
|
5398
|
-
|
|
5906
|
+
HIsUndetectableAndBranch* result =
|
|
5907
|
+
new(zone()) HIsUndetectableAndBranch(value);
|
|
5908
|
+
return ast_context()->ReturnControl(result, call->id());
|
|
5399
5909
|
}
|
|
5400
5910
|
|
|
5401
5911
|
|
|
@@ -5413,23 +5923,32 @@ void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
|
|
|
5413
5923
|
// We are generating graph for inlined function. Currently
|
|
5414
5924
|
// constructor inlining is not supported and we can just return
|
|
5415
5925
|
// false from %_IsConstructCall().
|
|
5416
|
-
ast_context()->ReturnValue(graph()->GetConstantFalse());
|
|
5926
|
+
return ast_context()->ReturnValue(graph()->GetConstantFalse());
|
|
5417
5927
|
} else {
|
|
5418
|
-
ast_context()->
|
|
5928
|
+
return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch,
|
|
5929
|
+
call->id());
|
|
5419
5930
|
}
|
|
5420
5931
|
}
|
|
5421
5932
|
|
|
5422
5933
|
|
|
5423
5934
|
// Support for arguments.length and arguments[?].
|
|
5424
5935
|
void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
|
|
5936
|
+
// Our implementation of arguments (based on this stack frame or an
|
|
5937
|
+
// adapter below it) does not work for inlined functions. This runtime
|
|
5938
|
+
// function is blacklisted by AstNode::IsInlineable.
|
|
5939
|
+
ASSERT(function_state()->outer() == NULL);
|
|
5425
5940
|
ASSERT(call->arguments()->length() == 0);
|
|
5426
5941
|
HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
|
|
5427
5942
|
HArgumentsLength* result = new(zone()) HArgumentsLength(elements);
|
|
5428
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
5943
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5429
5944
|
}
|
|
5430
5945
|
|
|
5431
5946
|
|
|
5432
5947
|
void HGraphBuilder::GenerateArguments(CallRuntime* call) {
|
|
5948
|
+
// Our implementation of arguments (based on this stack frame or an
|
|
5949
|
+
// adapter below it) does not work for inlined functions. This runtime
|
|
5950
|
+
// function is blacklisted by AstNode::IsInlineable.
|
|
5951
|
+
ASSERT(function_state()->outer() == NULL);
|
|
5433
5952
|
ASSERT(call->arguments()->length() == 1);
|
|
5434
5953
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5435
5954
|
HValue* index = Pop();
|
|
@@ -5437,7 +5956,7 @@ void HGraphBuilder::GenerateArguments(CallRuntime* call) {
|
|
|
5437
5956
|
HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
|
|
5438
5957
|
HAccessArgumentsAt* result =
|
|
5439
5958
|
new(zone()) HAccessArgumentsAt(elements, length, index);
|
|
5440
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
5959
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5441
5960
|
}
|
|
5442
5961
|
|
|
5443
5962
|
|
|
@@ -5454,7 +5973,7 @@ void HGraphBuilder::GenerateValueOf(CallRuntime* call) {
|
|
|
5454
5973
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5455
5974
|
HValue* value = Pop();
|
|
5456
5975
|
HValueOf* result = new(zone()) HValueOf(value);
|
|
5457
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
5976
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5458
5977
|
}
|
|
5459
5978
|
|
|
5460
5979
|
|
|
@@ -5470,8 +5989,9 @@ void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
|
|
|
5470
5989
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
|
|
5471
5990
|
HValue* index = Pop();
|
|
5472
5991
|
HValue* string = Pop();
|
|
5473
|
-
|
|
5474
|
-
|
|
5992
|
+
HValue* context = environment()->LookupContext();
|
|
5993
|
+
HStringCharCodeAt* result = BuildStringCharCodeAt(context, string, index);
|
|
5994
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5475
5995
|
}
|
|
5476
5996
|
|
|
5477
5997
|
|
|
@@ -5480,8 +6000,10 @@ void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
|
|
|
5480
6000
|
ASSERT(call->arguments()->length() == 1);
|
|
5481
6001
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5482
6002
|
HValue* char_code = Pop();
|
|
5483
|
-
|
|
5484
|
-
|
|
6003
|
+
HValue* context = environment()->LookupContext();
|
|
6004
|
+
HStringCharFromCode* result =
|
|
6005
|
+
new(zone()) HStringCharFromCode(context, char_code);
|
|
6006
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5485
6007
|
}
|
|
5486
6008
|
|
|
5487
6009
|
|
|
@@ -5492,10 +6014,12 @@ void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
|
|
|
5492
6014
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
|
|
5493
6015
|
HValue* index = Pop();
|
|
5494
6016
|
HValue* string = Pop();
|
|
5495
|
-
|
|
6017
|
+
HValue* context = environment()->LookupContext();
|
|
6018
|
+
HStringCharCodeAt* char_code = BuildStringCharCodeAt(context, string, index);
|
|
5496
6019
|
AddInstruction(char_code);
|
|
5497
|
-
HStringCharFromCode* result =
|
|
5498
|
-
|
|
6020
|
+
HStringCharFromCode* result =
|
|
6021
|
+
new(zone()) HStringCharFromCode(context, char_code);
|
|
6022
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5499
6023
|
}
|
|
5500
6024
|
|
|
5501
6025
|
|
|
@@ -5506,14 +6030,15 @@ void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
|
|
|
5506
6030
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
|
|
5507
6031
|
HValue* right = Pop();
|
|
5508
6032
|
HValue* left = Pop();
|
|
5509
|
-
|
|
5510
|
-
|
|
6033
|
+
HCompareObjectEqAndBranch* result =
|
|
6034
|
+
new(zone()) HCompareObjectEqAndBranch(left, right);
|
|
6035
|
+
return ast_context()->ReturnControl(result, call->id());
|
|
5511
6036
|
}
|
|
5512
6037
|
|
|
5513
6038
|
|
|
5514
6039
|
void HGraphBuilder::GenerateLog(CallRuntime* call) {
|
|
5515
6040
|
// %_Log is ignored in optimized code.
|
|
5516
|
-
ast_context()->ReturnValue(graph()->GetConstantUndefined());
|
|
6041
|
+
return ast_context()->ReturnValue(graph()->GetConstantUndefined());
|
|
5517
6042
|
}
|
|
5518
6043
|
|
|
5519
6044
|
|
|
@@ -5530,7 +6055,7 @@ void HGraphBuilder::GenerateStringAdd(CallRuntime* call) {
|
|
|
5530
6055
|
HValue* context = environment()->LookupContext();
|
|
5531
6056
|
HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2);
|
|
5532
6057
|
Drop(2);
|
|
5533
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6058
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5534
6059
|
}
|
|
5535
6060
|
|
|
5536
6061
|
|
|
@@ -5541,7 +6066,7 @@ void HGraphBuilder::GenerateSubString(CallRuntime* call) {
|
|
|
5541
6066
|
HValue* context = environment()->LookupContext();
|
|
5542
6067
|
HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3);
|
|
5543
6068
|
Drop(3);
|
|
5544
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6069
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5545
6070
|
}
|
|
5546
6071
|
|
|
5547
6072
|
|
|
@@ -5553,7 +6078,7 @@ void HGraphBuilder::GenerateStringCompare(CallRuntime* call) {
|
|
|
5553
6078
|
HCallStub* result =
|
|
5554
6079
|
new(zone()) HCallStub(context, CodeStub::StringCompare, 2);
|
|
5555
6080
|
Drop(2);
|
|
5556
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6081
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5557
6082
|
}
|
|
5558
6083
|
|
|
5559
6084
|
|
|
@@ -5564,7 +6089,7 @@ void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
|
|
|
5564
6089
|
HValue* context = environment()->LookupContext();
|
|
5565
6090
|
HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4);
|
|
5566
6091
|
Drop(4);
|
|
5567
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6092
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5568
6093
|
}
|
|
5569
6094
|
|
|
5570
6095
|
|
|
@@ -5576,7 +6101,7 @@ void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
|
|
|
5576
6101
|
HCallStub* result =
|
|
5577
6102
|
new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3);
|
|
5578
6103
|
Drop(3);
|
|
5579
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6104
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5580
6105
|
}
|
|
5581
6106
|
|
|
5582
6107
|
|
|
@@ -5594,7 +6119,7 @@ void HGraphBuilder::GenerateNumberToString(CallRuntime* call) {
|
|
|
5594
6119
|
HCallStub* result =
|
|
5595
6120
|
new(zone()) HCallStub(context, CodeStub::NumberToString, 1);
|
|
5596
6121
|
Drop(1);
|
|
5597
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6122
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5598
6123
|
}
|
|
5599
6124
|
|
|
5600
6125
|
|
|
@@ -5621,7 +6146,7 @@ void HGraphBuilder::GenerateCallFunction(CallRuntime* call) {
|
|
|
5621
6146
|
HInvokeFunction* result =
|
|
5622
6147
|
new(zone()) HInvokeFunction(context, function, arg_count);
|
|
5623
6148
|
Drop(arg_count);
|
|
5624
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6149
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5625
6150
|
}
|
|
5626
6151
|
|
|
5627
6152
|
|
|
@@ -5633,7 +6158,7 @@ void HGraphBuilder::GenerateMathPow(CallRuntime* call) {
|
|
|
5633
6158
|
HValue* right = Pop();
|
|
5634
6159
|
HValue* left = Pop();
|
|
5635
6160
|
HPower* result = new(zone()) HPower(left, right);
|
|
5636
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6161
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5637
6162
|
}
|
|
5638
6163
|
|
|
5639
6164
|
|
|
@@ -5645,7 +6170,7 @@ void HGraphBuilder::GenerateMathSin(CallRuntime* call) {
|
|
|
5645
6170
|
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
|
|
5646
6171
|
result->set_transcendental_type(TranscendentalCache::SIN);
|
|
5647
6172
|
Drop(1);
|
|
5648
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6173
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5649
6174
|
}
|
|
5650
6175
|
|
|
5651
6176
|
|
|
@@ -5657,7 +6182,7 @@ void HGraphBuilder::GenerateMathCos(CallRuntime* call) {
|
|
|
5657
6182
|
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
|
|
5658
6183
|
result->set_transcendental_type(TranscendentalCache::COS);
|
|
5659
6184
|
Drop(1);
|
|
5660
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6185
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5661
6186
|
}
|
|
5662
6187
|
|
|
5663
6188
|
|
|
@@ -5669,7 +6194,7 @@ void HGraphBuilder::GenerateMathLog(CallRuntime* call) {
|
|
|
5669
6194
|
new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
|
|
5670
6195
|
result->set_transcendental_type(TranscendentalCache::LOG);
|
|
5671
6196
|
Drop(1);
|
|
5672
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6197
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5673
6198
|
}
|
|
5674
6199
|
|
|
5675
6200
|
|
|
@@ -5689,7 +6214,7 @@ void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
|
|
|
5689
6214
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
5690
6215
|
HValue* value = Pop();
|
|
5691
6216
|
HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value);
|
|
5692
|
-
ast_context()->ReturnInstruction(result, call->id());
|
|
6217
|
+
return ast_context()->ReturnInstruction(result, call->id());
|
|
5693
6218
|
}
|
|
5694
6219
|
|
|
5695
6220
|
|
|
@@ -5860,7 +6385,6 @@ HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
|
|
|
5860
6385
|
HEnvironment* HEnvironment::CopyForInlining(
|
|
5861
6386
|
Handle<JSFunction> target,
|
|
5862
6387
|
FunctionLiteral* function,
|
|
5863
|
-
CompilationPhase compilation_phase,
|
|
5864
6388
|
HConstant* undefined,
|
|
5865
6389
|
CallKind call_kind) const {
|
|
5866
6390
|
// Outer environment is a copy of this one without the arguments.
|
|
@@ -5872,22 +6396,15 @@ HEnvironment* HEnvironment::CopyForInlining(
|
|
|
5872
6396
|
HEnvironment* inner =
|
|
5873
6397
|
new(zone) HEnvironment(outer, function->scope(), target);
|
|
5874
6398
|
// Get the argument values from the original environment.
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
inner->SetValueAt(i, push);
|
|
5885
|
-
}
|
|
5886
|
-
}
|
|
5887
|
-
// If the function we are inlining is a strict mode function, pass
|
|
5888
|
-
// undefined as the receiver for function calls (instead of the
|
|
5889
|
-
// global receiver).
|
|
5890
|
-
if (function->strict_mode() && call_kind == CALL_AS_FUNCTION) {
|
|
6399
|
+
for (int i = 0; i <= arity; ++i) { // Include receiver.
|
|
6400
|
+
HValue* push = ExpressionStackAt(arity - i);
|
|
6401
|
+
inner->SetValueAt(i, push);
|
|
6402
|
+
}
|
|
6403
|
+
// If the function we are inlining is a strict mode function or a
|
|
6404
|
+
// builtin function, pass undefined as the receiver for function
|
|
6405
|
+
// calls (instead of the global receiver).
|
|
6406
|
+
if ((target->shared()->native() || function->strict_mode()) &&
|
|
6407
|
+
call_kind == CALL_AS_FUNCTION) {
|
|
5891
6408
|
inner->SetValueAt(0, undefined);
|
|
5892
6409
|
}
|
|
5893
6410
|
inner->SetValueAt(arity + 1, outer->LookupContext());
|
|
@@ -5969,15 +6486,15 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
|
|
|
5969
6486
|
PrintEmptyProperty("predecessors");
|
|
5970
6487
|
}
|
|
5971
6488
|
|
|
5972
|
-
if (current->end()
|
|
6489
|
+
if (current->end()->SuccessorCount() == 0) {
|
|
5973
6490
|
PrintEmptyProperty("successors");
|
|
5974
|
-
} else
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
6491
|
+
} else {
|
|
6492
|
+
PrintIndent();
|
|
6493
|
+
trace_.Add("successors");
|
|
6494
|
+
for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
|
|
6495
|
+
trace_.Add(" \"B%d\"", it.Current()->block_id());
|
|
6496
|
+
}
|
|
6497
|
+
trace_.Add("\n");
|
|
5981
6498
|
}
|
|
5982
6499
|
|
|
5983
6500
|
PrintEmptyProperty("xhandlers");
|